From 9647cdd4f1da1ce0d85c431fd9762e653ac3b1cc Mon Sep 17 00:00:00 2001 From: Reece Hart Date: Wed, 27 Jul 2016 21:41:59 -0700 Subject: [PATCH 001/719] fixed #228: make exit code customizable to indicated whether files were changed --- yapf/__init__.py | 10 ++++++++-- yapftests/main_test.py | 24 +++++++++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index dfbb8ee2d..1348066f3 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -87,6 +87,12 @@ def main(argv): default=None, help='range of lines to reformat, one-based') + parser.add_argument( + '-c', + '--changed-files-exit-code', + default=0, + type=int, + help='exit code to indicate that files were changed') parser.add_argument( '-e', '--exclude', @@ -161,7 +167,7 @@ def main(argv): lines=lines, verify=args.verify) sys.stdout.write(reformatted_source) - return 2 if changed else 0 + return args.changed_files_exit_code if changed else 0 files = file_resources.GetCommandLineFiles(args.files, args.recursive, args.exclude) @@ -175,7 +181,7 @@ def main(argv): in_place=args.in_place, print_diff=args.diff, verify=args.verify) - return 2 if changed else 0 + return args.changed_files_exit_code if changed else 0 def FormatFiles(filenames, diff --git a/yapftests/main_test.py b/yapftests/main_test.py index e5a5a74ce..163fc8872 100644 --- a/yapftests/main_test.py +++ b/yapftests/main_test.py @@ -91,7 +91,7 @@ def testEchoInputWithStyle(self): with patched_input(code): with captured_output() as (out, err): ret = yapf.main(['-', '--style=chromium']) - self.assertEqual(ret, 2) + self.assertEqual(ret, 0) self.assertEqual(out.getvalue(), chromium_code) def testEchoBadInput(self): @@ -116,3 +116,25 @@ def testVersion(self): self.assertEqual(ret, 0) version = 'yapf {}\n'.format(yapf.__version__) self.assertEqual(version, out.getvalue()) + + def testUnchangedFileExitCode(self): + code = "a = 1" + with patched_input(code): + with captured_output() as (out, err): + ret = yapf.main([]) + self.assertEqual(ret, 0) + + def testChangedFileExitCode(self): + code = "a=1" + with patched_input(code): + with captured_output() as (out, err): + ret = yapf.main([]) + self.assertEqual(ret, 0) + + def testCustomChangedFileExitCode(self): + code = "a=1" + with patched_input(code): + with captured_output() as (out, err): + ret = yapf.main(['-', '-c', '2']) + self.assertEqual(ret, 2) + From 4b62936b1a23269e0565078d934249e66cbde1c1 Mon Sep 17 00:00:00 2001 From: Reece Hart Date: Thu, 11 Aug 2016 13:46:15 -0700 Subject: [PATCH 002/719] Per @gwelymernans in #286: hardcode 0/1 returns and update CHANGELOG --- CHANGELOG | 5 +++++ yapf/__init__.py | 10 ++-------- yapftests/main_test.py | 21 --------------------- 3 files changed, 7 insertions(+), 29 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4bc8925bb..fd92065e0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,11 @@ ### Fixed - Enforce splitting each element in a dictionary if comma terminated. +### Changed +- Issue #228: Return exit code 0 on success, regardless of whether files were + changed. (Previously, 0 meant success with no files + modified, and 2 meant success with at least one file modified.) + ## [0.11.0] 2016-07-17 ### Added - The COALESCE_BRACKETS knob prevents splitting consecutive brackets when diff --git a/yapf/__init__.py b/yapf/__init__.py index 1348066f3..145d8f435 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -87,12 +87,6 @@ def main(argv): default=None, help='range of lines to reformat, one-based') - parser.add_argument( - '-c', - '--changed-files-exit-code', - default=0, - type=int, - help='exit code to indicate that files were changed') parser.add_argument( '-e', '--exclude', @@ -167,7 +161,7 @@ def main(argv): lines=lines, verify=args.verify) sys.stdout.write(reformatted_source) - return args.changed_files_exit_code if changed else 0 + return 0 files = file_resources.GetCommandLineFiles(args.files, args.recursive, args.exclude) @@ -181,7 +175,7 @@ def main(argv): in_place=args.in_place, print_diff=args.diff, verify=args.verify) - return args.changed_files_exit_code if changed else 0 + return 0 def FormatFiles(filenames, diff --git a/yapftests/main_test.py b/yapftests/main_test.py index 163fc8872..42e6f9b5b 100644 --- a/yapftests/main_test.py +++ b/yapftests/main_test.py @@ -117,24 +117,3 @@ def testVersion(self): version = 'yapf {}\n'.format(yapf.__version__) self.assertEqual(version, out.getvalue()) - def testUnchangedFileExitCode(self): - code = "a = 1" - with patched_input(code): - with captured_output() as (out, err): - ret = yapf.main([]) - self.assertEqual(ret, 0) - - def testChangedFileExitCode(self): - code = "a=1" - with patched_input(code): - with captured_output() as (out, err): - ret = yapf.main([]) - self.assertEqual(ret, 0) - - def testCustomChangedFileExitCode(self): - code = "a=1" - with patched_input(code): - with captured_output() as (out, err): - ret = yapf.main(['-', '-c', '2']) - self.assertEqual(ret, 2) - From c0f34815ef9d66abb444c0b6eaf13a03948ee810 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 15 Aug 2016 17:04:26 -0700 Subject: [PATCH 003/719] Process the asynchronous function after comments If a comment came before an asynchronous function, we wouldn't process it correctly because of indexing. Closes #291 --- CHANGELOG | 3 +++ yapf/yapflib/blank_line_calculator.py | 7 +++---- yapf/yapflib/pytree_unwrapper.py | 18 +++++++++++++---- yapf/yapflib/reformatter.py | 4 ++-- yapf/yapflib/verifier.py | 2 +- yapftests/reformatter_test.py | 28 +++++++++++++++++++++++++++ 6 files changed, 51 insertions(+), 11 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index bb3ffdc7b..8d9e87a7d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,9 @@ - Enforce splitting each element in a dictionary if comma terminated. - It's okay to split in the middle of a dotted name if the whole expression is going to go over the column limit. +- Asynchronous functions were going missing if they were preceded by a comment + (a what? exactly). The asynchronous function processing wasn't taking the + comment into account and thus skipping the whole function. ### Changed - Issue #228: Return exit code 0 on success, regardless of whether files were diff --git a/yapf/yapflib/blank_line_calculator.py b/yapf/yapflib/blank_line_calculator.py index e02fded8f..a006b9eac 100644 --- a/yapf/yapflib/blank_line_calculator.py +++ b/yapf/yapflib/blank_line_calculator.py @@ -92,11 +92,10 @@ def Visit_funcdef(self, node): # pylint: disable=invalid-name self.last_was_class_or_function = False index = self._SetBlankLinesBetweenCommentAndClassFunc(node) if _AsyncFunction(node): - # Move the number of blank lines to the async keyword. - num_newlines = pytree_utils.GetNodeAnnotation( - node.children[0], pytree_utils.Annotation.NEWLINES) - self._SetNumNewlines(node.prev_sibling, num_newlines) + index = self._SetBlankLinesBetweenCommentAndClassFunc(node.prev_sibling.parent) self._SetNumNewlines(node.children[0], None) + else: + index = self._SetBlankLinesBetweenCommentAndClassFunc(node) self.last_was_decorator = False self.function_level += 1 for child in node.children[index:]: diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index f20d1e294..ebfe8d1bf 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -194,8 +194,13 @@ def Visit_funcdef(self, node): # pylint: disable=invalid-name def Visit_async_funcdef(self, node): # pylint: disable=invalid-name self._StartNewLine() - self.Visit(node.children[0]) - for child in node.children[1].children: + index = 0 + for child in node.children: + index += 1 + self.Visit(child) + if pytree_utils.NodeName(child) == 'ASYNC': + break + for child in node.children[index].children: self.Visit(child) _CLASS_DEF_ELEMS = frozenset({'class'}) @@ -205,8 +210,13 @@ def Visit_classdef(self, node): # pylint: disable=invalid-name def Visit_async_stmt(self, node): # pylint: disable=invalid-name self._StartNewLine() - self.Visit(node.children[0]) - for child in node.children[1].children: + index = 0 + for child in node.children: + index += 1 + self.Visit(child) + if pytree_utils.NodeName(child) == 'ASYNC': + break + for child in node.children[index].children: self.Visit(child) def Visit_decorators(self, node): # pylint: disable=invalid-name diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 75482c50e..93b4d3ab8 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -452,7 +452,7 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, else: return ONE_BLANK_LINE - if first_token.value in {'class', 'def', '@'}: + if first_token.value in {'class', 'def', 'async', '@'}: # TODO(morbo): This can go once the blank line calculator is more # sophisticated. if not indent_depth: @@ -478,7 +478,7 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, pytree_utils.Annotation.NEWLINES, None) return NO_BLANK_LINES - elif prev_uwline.first.value in {'class', 'def'}: + elif prev_uwline.first.value in {'class', 'def', 'async'}: if not style.Get('BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'): pytree_utils.SetNodeAnnotation(first_token.node, pytree_utils.Annotation.NEWLINES, None) diff --git a/yapf/yapflib/verifier.py b/yapf/yapflib/verifier.py index a670ea9db..891798d2f 100644 --- a/yapf/yapflib/verifier.py +++ b/yapf/yapflib/verifier.py @@ -66,7 +66,7 @@ def _NormalizeCode(code): break code = '\n'.join(lines[i:]) + '\n' - if re.match(r'(if|while|for|with|def|class)\b', code): + if re.match(r'(if|while|for|with|def|class|async|await)\b', code): code += '\n pass' elif re.match(r'(elif|else)\b', code): try: diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index cb2e6d5f3..9298e6fae 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -3271,6 +3271,34 @@ def testNoSpacesAroundPowerOparator(self): finally: style.SetGlobalStyle(style.CreatePEP8Style()) + def testAsyncWithPrecedingComment(self): + if sys.version_info[1] < 5: + return + unformatted_code = textwrap.dedent("""\ + import asyncio + + # Comment + async def bar(): + pass + + async def foo(): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + import asyncio + + + # Comment + async def bar(): + pass + + + async def foo(): + pass + """) + uwlines = _ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + class TestsForFBStyle(ReformatterTest): From 2e44a279f2953491152e6f372ebc0933965e3194 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 17 Aug 2016 00:01:56 -0700 Subject: [PATCH 004/719] Don't set splitting of closing bracket unbreakable If the closing bracket is preceded by a comma, then we don't want to set it's split penalty to unbreakable. That would conflict with assumptions made further on in the code. --- CHANGELOG | 13 ++++++++----- yapf/yapflib/blank_line_calculator.py | 3 ++- yapf/yapflib/split_penalty.py | 3 ++- yapftests/main_test.py | 1 - yapftests/reformatter_test.py | 25 +++++++++++++++++++++---- 5 files changed, 33 insertions(+), 12 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8d9e87a7d..55a15e1e7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,11 @@ # This project adheres to [Semantic Versioning](http://semver.org/). ## [0.11.1] UNRELEASED +### Changed +- Issue #228: Return exit code 0 on success, regardless of whether files were + changed. (Previously, 0 meant success with no files + modified, and 2 meant success with at least one file modified.) + ### Fixed - Enforce splitting each element in a dictionary if comma terminated. - It's okay to split in the middle of a dotted name if the whole expression is @@ -10,11 +15,9 @@ - Asynchronous functions were going missing if they were preceded by a comment (a what? exactly). The asynchronous function processing wasn't taking the comment into account and thus skipping the whole function. - -### Changed -- Issue #228: Return exit code 0 on success, regardless of whether files were - changed. (Previously, 0 meant success with no files - modified, and 2 meant success with at least one file modified.) +- The splitting of arguments when comma terminated had a conflict. The split + penalty of the closing bracket was set to the maximum, but it shouldn't be if + the closing bracket is preceded by a comma. ## [0.11.0] 2016-07-17 ### Added diff --git a/yapf/yapflib/blank_line_calculator.py b/yapf/yapflib/blank_line_calculator.py index a006b9eac..677062051 100644 --- a/yapf/yapflib/blank_line_calculator.py +++ b/yapf/yapflib/blank_line_calculator.py @@ -92,7 +92,8 @@ def Visit_funcdef(self, node): # pylint: disable=invalid-name self.last_was_class_or_function = False index = self._SetBlankLinesBetweenCommentAndClassFunc(node) if _AsyncFunction(node): - index = self._SetBlankLinesBetweenCommentAndClassFunc(node.prev_sibling.parent) + index = self._SetBlankLinesBetweenCommentAndClassFunc( + node.prev_sibling.parent) self._SetNumNewlines(node.children[0], None) else: index = self._SetBlankLinesBetweenCommentAndClassFunc(node) diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 50796decf..0f0810022 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -209,7 +209,8 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring if last_child_node.value.strip().startswith('#'): last_child_node = last_child_node.prev_sibling if not style.Get('DEDENT_CLOSING_BRACKETS'): - self._SetUnbreakable(last_child_node) + if _LastChildNode(last_child_node.prev_sibling).value != ',': + self._SetUnbreakable(last_child_node) if _FirstChildNode(trailer).lineno == last_child_node.lineno: # If the trailer was originally on one line, then try to keep it diff --git a/yapftests/main_test.py b/yapftests/main_test.py index 42e6f9b5b..73b4a81f6 100644 --- a/yapftests/main_test.py +++ b/yapftests/main_test.py @@ -116,4 +116,3 @@ def testVersion(self): self.assertEqual(ret, 0) version = 'yapf {}\n'.format(yapf.__version__) self.assertEqual(version, out.getvalue()) - diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index 9298e6fae..d318c18dd 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -1702,7 +1702,18 @@ def testSplittingArgumentsTerminatedByComma(self): style.CreateStyleFromConfig( '{based_on_style: chromium, ' 'split_arguments_when_comma_terminated: True}')) - code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ + function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3) + + function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3,) + + a_very_long_function_name(long_argument_name_1=1, long_argument_name_2=2, long_argument_name_3=3, long_argument_name_4=4) + + a_very_long_function_name(long_argument_name_1, long_argument_name_2, long_argument_name_3, long_argument_name_4,) + + r =f0 (1, 2,3,) + """) + expected_formatted_code = textwrap.dedent("""\ function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3) function_name( @@ -1723,14 +1734,20 @@ def testSplittingArgumentsTerminatedByComma(self): long_argument_name_3, long_argument_name_4, ) + + r = f0( + 1, + 2, + 3, + ) """) - uwlines = _ParseAndUnwrap(code) + uwlines = _ParseAndUnwrap(unformatted_code) reformatted_code = reformatter.Reformat(uwlines) - self.assertCodeEqual(code, reformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatted_code) uwlines = _ParseAndUnwrap(reformatted_code) reformatted_code = reformatter.Reformat(uwlines) - self.assertCodeEqual(code, reformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatted_code) finally: style.SetGlobalStyle(style.CreateChromiumStyle()) From 16025c0e99767692e50bd5290c89c005fed70094 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 17 Aug 2016 00:33:02 -0700 Subject: [PATCH 005/719] Bump up to v0.11.1 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 55a15e1e7..ce64c5ecf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.11.1] UNRELEASED +## [0.11.1] 2016-08-17 ### Changed - Issue #228: Return exit code 0 on success, regardless of whether files were changed. (Previously, 0 meant success with no files diff --git a/yapf/__init__.py b/yapf/__init__.py index 145d8f435..e20294534 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.11.0' +__version__ = '0.11.1' def main(argv): From 3f80ecb1b0d6179c9efd29a1cce69b3ab71a0b3d Mon Sep 17 00:00:00 2001 From: bey Date: Fri, 19 Aug 2016 16:40:36 +0300 Subject: [PATCH 006/719] Fix TODO on style module --- yapf/yapflib/style.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index ae7333ceb..43159e4a5 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -313,7 +313,12 @@ def CreateStyleFromConfig(style_config): Raises: StyleConfigError: if an unknown style option was encountered. """ + styles = (CreatePEP8Style(), CreateGoogleStyle(), + CreateFacebookStyle(), CreateChromiumStyle()) if style_config is None: + for style in styles: + if _style != style: + return _style return DEFAULT_STYLE_FACTORY() style_factory = _STYLE_NAME_TO_FACTORY.get(style_config.lower()) if style_factory is not None: @@ -423,5 +428,5 @@ def _CreateStyleFromConfigParser(config): # TODO(eliben): For now we're preserving the global presence of a style dict. # Refactor this so that the style is passed around through yapf rather than # being global. -_style = {} +_style = None SetGlobalStyle(DEFAULT_STYLE_FACTORY()) From 17b5e115fa54a1bf543208017c4564d0441bbb07 Mon Sep 17 00:00:00 2001 From: bey Date: Fri, 19 Aug 2016 17:06:35 +0300 Subject: [PATCH 007/719] Add test class for indentation --- yapftests/yapf_test.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 449a4b5ff..0c9dadf57 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -26,6 +26,7 @@ from yapf.yapflib import py3compat from yapf.yapflib import yapf_api +from yapf.yapflib import style ROOT_DIR = os.path.dirname(os.path.abspath(os.path.dirname(__file__))) @@ -1117,5 +1118,30 @@ def testBadSyntax(self): self.assertRaises(SyntaxError, yapf_api.FormatCode, code) +class DiffIndentTest(unittest.TestCase): + + @staticmethod + def own_style(): + my_style = style.CreatePEP8Style() + my_style['INDENT_WIDTH'] = 3 + my_style['CONTINUATION_INDENT_WIDTH'] = 3 + return my_style + + def _Check(self, unformatted_code, expected_formatted_code): + formatted_code, _ = yapf_api.FormatCode( + unformatted_code, style_config=style.SetGlobalStyle(self.own_style())) + self.assertEqual(expected_formatted_code, formatted_code) + + def testSimple(self): + unformatted_code = textwrap.dedent(u"""\ + for i in range(10): + print i + """) + formatted_code = textwrap.dedent(u"""\ + for i in range(10): + print i + """) + self._Check(unformatted_code, formatted_code) + if __name__ == '__main__': unittest.main() From 01eb65a6c761ab301b222a18ba9991049b25cf03 Mon Sep 17 00:00:00 2001 From: bey Date: Fri, 19 Aug 2016 17:23:30 +0300 Subject: [PATCH 008/719] Fix bug with defining default style. --- yapf/yapflib/style.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 43159e4a5..5642021f3 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -315,9 +315,13 @@ def CreateStyleFromConfig(style_config): """ styles = (CreatePEP8Style(), CreateGoogleStyle(), CreateFacebookStyle(), CreateChromiumStyle()) + def_style = False if style_config is None: for style in styles: - if _style != style: + if _style == style: + def_style = True + break + if not def_style: return _style return DEFAULT_STYLE_FACTORY() style_factory = _STYLE_NAME_TO_FACTORY.get(style_config.lower()) From 2c3039cbd40a10209f66f82f0bbc46054589a283 Mon Sep 17 00:00:00 2001 From: bey Date: Fri, 19 Aug 2016 17:36:21 +0300 Subject: [PATCH 009/719] Remove inappropriate test. Test for indentation should be in reformatter_test module. --- yapftests/yapf_test.py | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 0c9dadf57..449a4b5ff 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -26,7 +26,6 @@ from yapf.yapflib import py3compat from yapf.yapflib import yapf_api -from yapf.yapflib import style ROOT_DIR = os.path.dirname(os.path.abspath(os.path.dirname(__file__))) @@ -1118,30 +1117,5 @@ def testBadSyntax(self): self.assertRaises(SyntaxError, yapf_api.FormatCode, code) -class DiffIndentTest(unittest.TestCase): - - @staticmethod - def own_style(): - my_style = style.CreatePEP8Style() - my_style['INDENT_WIDTH'] = 3 - my_style['CONTINUATION_INDENT_WIDTH'] = 3 - return my_style - - def _Check(self, unformatted_code, expected_formatted_code): - formatted_code, _ = yapf_api.FormatCode( - unformatted_code, style_config=style.SetGlobalStyle(self.own_style())) - self.assertEqual(expected_formatted_code, formatted_code) - - def testSimple(self): - unformatted_code = textwrap.dedent(u"""\ - for i in range(10): - print i - """) - formatted_code = textwrap.dedent(u"""\ - for i in range(10): - print i - """) - self._Check(unformatted_code, formatted_code) - if __name__ == '__main__': unittest.main() From 03e3d0274ee6a0a5e3daffd3e43e0074749efd45 Mon Sep 17 00:00:00 2001 From: bey Date: Fri, 19 Aug 2016 18:59:17 +0300 Subject: [PATCH 010/719] Renew test for indentation. --- yapftests/yapf_test.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 0c9dadf57..40a9d3a9b 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1134,14 +1134,14 @@ def _Check(self, unformatted_code, expected_formatted_code): def testSimple(self): unformatted_code = textwrap.dedent(u"""\ - for i in range(10): - print i - """) - formatted_code = textwrap.dedent(u"""\ - for i in range(10): - print i - """) - self._Check(unformatted_code, formatted_code) + for i in range(5): + print('bar') + """) + expected_formatted_code = textwrap.dedent(u"""\ + for i in range(5): + print('bar') + """) + self._Check(unformatted_code, expected_formatted_code) if __name__ == '__main__': unittest.main() From 81392039b8bebcf4c21ab53d38c6f00579307219 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 19 Aug 2016 23:47:23 -0700 Subject: [PATCH 011/719] Support formatting of typed names Treat a "typed name" similarly to how we treat named arguments in argument lists. The only exception being that we add a space after the colon. --- CHANGELOG | 6 ++ yapf/yapflib/format_decision_state.py | 4 +- yapf/yapflib/subtype_assigner.py | 139 ++++++++++++++------------ yapf/yapflib/unwrapped_line.py | 3 +- yapftests/reformatter_test.py | 15 +++ 5 files changed, 99 insertions(+), 68 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ce64c5ecf..cc3745844 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,12 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.12.0] UNRELEASED +### Added +- Support formatting of typed names. Typed names are formatted a similar way to + how named arguments are formatted, except that there's a space after the + colon. + ## [0.11.1] 2016-08-17 ### Changed - Issue #228: Return exit code 0 on success, regardless of whether files were diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 804280ad8..7c2644759 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -171,8 +171,8 @@ def MustSplit(self): if (style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in current.subtypes): - if (previous.value not in {'=', '*', '**'} and - current.value not in '=,)'): + if (previous.value not in {'=', ':', '*', '**'} and + current.value not in ':=,)'): # If we're going to split the lines because of named arguments, then we # want to split after the opening bracket as well. But not when this is # part of function definition. diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 4e70d613d..fac0f03e6 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -47,6 +47,7 @@ def AssignSubtypes(tree): # Map tokens in argument lists to their respective subtype. _ARGLIST_TOKEN_TO_SUBTYPE = { '=': format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN, + ':': format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN, '*': format_token.Subtype.VARARGS_STAR, '**': format_token.Subtype.KWARGS_STAR_STAR, } @@ -76,18 +77,18 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name last_was_colon = False for child in node.children: if pytree_utils.NodeName(child) == 'comp_for': - self._AppendFirstLeafTokenSubtype( - child, format_token.Subtype.DICT_SET_GENERATOR) + _AppendFirstLeafTokenSubtype(child, + format_token.Subtype.DICT_SET_GENERATOR) else: if dict_maker: if last_was_comma: - self._AppendFirstLeafTokenSubtype( - child, format_token.Subtype.DICTIONARY_KEY) + _AppendFirstLeafTokenSubtype(child, + format_token.Subtype.DICTIONARY_KEY) elif last_was_colon: if pytree_utils.NodeName(child) == 'power': - self._AppendSubtypeRec(child, format_token.Subtype.NONE) + _AppendSubtypeRec(child, format_token.Subtype.NONE) else: - self._AppendFirstLeafTokenSubtype( + _AppendFirstLeafTokenSubtype( child, format_token.Subtype.DICTIONARY_VALUE) if style.Get('INDENT_DICTIONARY_VALUE'): _InsertPseudoParentheses(child) @@ -101,28 +102,28 @@ def Visit_expr_stmt(self, node): # pylint: disable=invalid-name for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == '=': - self._AppendTokenSubtype(child, format_token.Subtype.ASSIGN_OPERATOR) + _AppendTokenSubtype(child, format_token.Subtype.ASSIGN_OPERATOR) def Visit_or_test(self, node): # pylint: disable=invalid-name # or_test ::= and_test ('or' and_test)* for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == 'or': - self._AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) def Visit_and_test(self, node): # pylint: disable=invalid-name # and_test ::= not_test ('and' not_test)* for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == 'and': - self._AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) def Visit_not_test(self, node): # pylint: disable=invalid-name # not_test ::= 'not' not_test | comparison for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == 'not': - self._AppendTokenSubtype(child, format_token.Subtype.UNARY_OPERATOR) + _AppendTokenSubtype(child, format_token.Subtype.UNARY_OPERATOR) def Visit_comparison(self, node): # pylint: disable=invalid-name # comparison ::= expr (comp_op expr)* @@ -132,49 +133,49 @@ def Visit_comparison(self, node): # pylint: disable=invalid-name if (isinstance(child, pytree.Leaf) and child.value in { '<', '>', '==', '>=', '<=', '<>', '!=', 'in', 'not in', 'is', 'is not' }): - self._AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) def Visit_star_expr(self, node): # pylint: disable=invalid-name # star_expr ::= '*' expr for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == '*': - self._AppendTokenSubtype(child, format_token.Subtype.UNARY_OPERATOR) + _AppendTokenSubtype(child, format_token.Subtype.UNARY_OPERATOR) def Visit_expr(self, node): # pylint: disable=invalid-name # expr ::= xor_expr ('|' xor_expr)* for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == '|': - self._AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) def Visit_xor_expr(self, node): # pylint: disable=invalid-name # xor_expr ::= and_expr ('^' and_expr)* for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == '^': - self._AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) def Visit_and_expr(self, node): # pylint: disable=invalid-name # and_expr ::= shift_expr ('&' shift_expr)* for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == '&': - self._AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) def Visit_shift_expr(self, node): # pylint: disable=invalid-name # shift_expr ::= arith_expr (('<<'|'>>') arith_expr)* for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value in {'<<', '>>'}: - self._AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) def Visit_arith_expr(self, node): # pylint: disable=invalid-name # arith_expr ::= term (('+'|'-') term)* for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value in '+-': - self._AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) def Visit_term(self, node): # pylint: disable=invalid-name # term ::= factor (('*'|'/'|'%'|'//') factor)* @@ -182,41 +183,41 @@ def Visit_term(self, node): # pylint: disable=invalid-name self.Visit(child) if (isinstance(child, pytree.Leaf) and child.value in {'*', '/', '%', '//'}): - self._AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) def Visit_factor(self, node): # pylint: disable=invalid-name # factor ::= ('+'|'-'|'~') factor | power for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value in '+-~': - self._AppendTokenSubtype(child, format_token.Subtype.UNARY_OPERATOR) + _AppendTokenSubtype(child, format_token.Subtype.UNARY_OPERATOR) def Visit_power(self, node): # pylint: disable=invalid-name # power ::= atom trailer* ['**' factor] for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == '**': - self._AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) def Visit_trailer(self, node): # pylint: disable=invalid-name for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value in '[]': - self._AppendTokenSubtype(child, format_token.Subtype.SUBSCRIPT_BRACKET) + _AppendTokenSubtype(child, format_token.Subtype.SUBSCRIPT_BRACKET) def Visit_subscript(self, node): # pylint: disable=invalid-name # subscript ::= test | [test] ':' [test] [sliceop] for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == ':': - self._AppendTokenSubtype(child, format_token.Subtype.SUBSCRIPT_COLON) + _AppendTokenSubtype(child, format_token.Subtype.SUBSCRIPT_COLON) def Visit_sliceop(self, node): # pylint: disable=invalid-name # sliceop ::= ':' [test] for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == ':': - self._AppendTokenSubtype(child, format_token.Subtype.SUBSCRIPT_COLON) + _AppendTokenSubtype(child, format_token.Subtype.SUBSCRIPT_COLON) def Visit_argument(self, node): # pylint: disable=invalid-name # argument ::= @@ -229,14 +230,18 @@ def Visit_arglist(self, node): # pylint: disable=invalid-name # | '*' test (',' argument)* [',' '**' test] # | '**' test) self._ProcessArgLists(node) - self._SetDefaultOrNamedAssignArgListSubtype(node) + _SetDefaultOrNamedAssignArgListSubtype(node) + + def Visit_tname(self, node): # pylint: disable=invalid-name + self._ProcessArgLists(node) + _SetDefaultOrNamedAssignArgListSubtype(node) def Visit_funcdef(self, node): # pylint: disable=invalid-name # funcdef ::= # 'def' NAME parameters ['->' test] ':' suite for child in node.children: if pytree_utils.NodeName(child) == 'NAME' and child.value != 'def': - self._AppendTokenSubtype(child, format_token.Subtype.FUNC_DEF) + _AppendTokenSubtype(child, format_token.Subtype.FUNC_DEF) break for child in node.children: self.Visit(child) @@ -248,7 +253,7 @@ def Visit_typedargslist(self, node): # pylint: disable=invalid-name # | '**' tname) # | tfpdef ['=' test] (',' tfpdef ['=' test])* [',']) self._ProcessArgLists(node) - self._SetDefaultOrNamedAssignArgListSubtype(node) + _SetDefaultOrNamedAssignArgListSubtype(node) def Visit_varargslist(self, node): # pylint: disable=invalid-name # varargslist ::= @@ -257,16 +262,16 @@ def Visit_varargslist(self, node): # pylint: disable=invalid-name # | '**' vname) # | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) self._ProcessArgLists(node) - self._SetDefaultOrNamedAssignArgListSubtype(node) + _SetDefaultOrNamedAssignArgListSubtype(node) def Visit_comp_for(self, node): # pylint: disable=invalid-name # comp_for ::= 'for' exprlist 'in' testlist_safe [comp_iter] - self._AppendSubtypeRec(node, format_token.Subtype.COMP_FOR) + _AppendSubtypeRec(node, format_token.Subtype.COMP_FOR) self.DefaultNodeVisit(node) def Visit_comp_if(self, node): # pylint: disable=invalid-name # comp_if ::= 'if' old_test [comp_iter] - self._AppendSubtypeRec(node, format_token.Subtype.COMP_IF) + _AppendSubtypeRec(node, format_token.Subtype.COMP_IF) self.DefaultNodeVisit(node) def _ProcessArgLists(self, node): @@ -274,51 +279,55 @@ def _ProcessArgLists(self, node): for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf): - self._AppendTokenSubtype( + _AppendTokenSubtype( child, subtype=_ARGLIST_TOKEN_TO_SUBTYPE.get(child.value, format_token.Subtype.NONE), force=False) - def _AppendSubtypeRec(self, node, subtype, force=True): - """Append the leafs in the node to the given subtype.""" + +def _SetDefaultOrNamedAssignArgListSubtype(node): + + def HasDefaultOrNamedAssignSubtype(node): if isinstance(node, pytree.Leaf): - self._AppendTokenSubtype(node, subtype, force=force) - return + if (format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in + pytree_utils.GetNodeAnnotation(node, pytree_utils.Annotation.SUBTYPE, + set())): + return True + return False + has_subtype = False for child in node.children: - self._AppendSubtypeRec(child, subtype, force=force) + has_subtype |= HasDefaultOrNamedAssignSubtype(child) + return has_subtype - def _AppendTokenSubtype(self, node, subtype, force=True): - """Append the token's subtype only if it's not already set.""" - pytree_utils.AppendNodeAnnotation(node, pytree_utils.Annotation.SUBTYPE, - subtype) + if HasDefaultOrNamedAssignSubtype(node): + for child in node.children: + if pytree_utils.NodeName(child) != 'COMMA': + _AppendFirstLeafTokenSubtype( + child, format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) - def _AppendFirstLeafTokenSubtype(self, node, subtype, force=False): - """Append the first leaf token's subtypes.""" - if isinstance(node, pytree.Leaf): - self._AppendTokenSubtype(node, subtype, force=force) - return - self._AppendFirstLeafTokenSubtype(node.children[0], subtype, force=force) - - def _SetDefaultOrNamedAssignArgListSubtype(self, node): - - def HasDefaultOrNamedAssignSubtype(node): - if isinstance(node, pytree.Leaf): - if (format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in - pytree_utils.GetNodeAnnotation( - node, pytree_utils.Annotation.SUBTYPE, set())): - return True - return False - has_subtype = False - for child in node.children: - has_subtype |= HasDefaultOrNamedAssignSubtype(child) - return has_subtype - - if HasDefaultOrNamedAssignSubtype(node): - for child in node.children: - if pytree_utils.NodeName(child) != 'COMMA': - self._AppendFirstLeafTokenSubtype( - child, format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) + +def _AppendTokenSubtype(node, subtype, force=True): + """Append the token's subtype only if it's not already set.""" + pytree_utils.AppendNodeAnnotation(node, pytree_utils.Annotation.SUBTYPE, + subtype) + + +def _AppendFirstLeafTokenSubtype(node, subtype, force=False): + """Append the first leaf token's subtypes.""" + if isinstance(node, pytree.Leaf): + _AppendTokenSubtype(node, subtype, force=force) + return + _AppendFirstLeafTokenSubtype(node.children[0], subtype, force=force) + + +def _AppendSubtypeRec(node, subtype, force=True): + """Append the leafs in the node to the given subtype.""" + if isinstance(node, pytree.Leaf): + _AppendTokenSubtype(node, subtype, force=force) + return + for child in node.children: + _AppendSubtypeRec(child, subtype, force=force) def _InsertPseudoParentheses(node): diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 14eaa8e97..831b24926 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -255,7 +255,8 @@ def _SpaceRequiredBetween(left, right): if (format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in left.subtypes or format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in right.subtypes): # A named argument or default parameter shouldn't have spaces around it. - return False + # However, a typed argument should have a space after the colon. + return lval == ':' if (format_token.Subtype.VARARGS_STAR in left.subtypes or format_token.Subtype.KWARGS_STAR_STAR in left.subtypes): # Don't add a space after a vararg's star or a keyword's star-star. diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index d318c18dd..fdc944b1b 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -3219,6 +3219,21 @@ class TestsForPython3Code(ReformatterTest): def setUpClass(cls): style.SetGlobalStyle(style.CreatePEP8Style()) + def testTypedNames(self): + unformatted_code = textwrap.dedent("""\ + def x(aaaaaaaaaaaaaaa:int,bbbbbbbbbbbbbbbb:str,ccccccccccccccc:dict,eeeeeeeeeeeeee:set={1, 2, 3})->bool: + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def x(aaaaaaaaaaaaaaa: int, + bbbbbbbbbbbbbbbb: str, + ccccccccccccccc: dict, + eeeeeeeeeeeeee: set={1, 2, 3}) -> bool: + pass + """) + uwlines = _ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testKeywordOnlyArgSpecifier(self): unformatted_code = textwrap.dedent("""\ def foo(a, *, kw): From 7ff4c0778ebf5a2d15e9d5bd5d8ae15d484a27dd Mon Sep 17 00:00:00 2001 From: Alexander Lenz Date: Fri, 26 Aug 2016 17:27:57 +0200 Subject: [PATCH 012/719] Support optional spaces for default and named assigns. --- CHANGELOG | 2 ++ README.rst | 4 ++++ yapf/yapflib/style.py | 4 ++++ yapf/yapflib/unwrapped_line.py | 2 +- yapftests/reformatter_test.py | 18 ++++++++++++++++++ 5 files changed, 29 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index cc3745844..04461f95a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,8 @@ - Support formatting of typed names. Typed names are formatted a similar way to how named arguments are formatted, except that there's a space after the colon. +- Add a knob, 'SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN', to allow adding spaces + around the assign operator on default or named assigns. ## [0.11.1] 2016-08-17 ### Changed diff --git a/README.rst b/README.rst index d86ce21d9..ab6f3cfd8 100644 --- a/README.rst +++ b/README.rst @@ -374,6 +374,10 @@ Knobs ``SPACES_AROUND_POWER_OPERATOR`` Set to ``True`` to prefer using spaces around ``**``. +``SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN`` + Set to ``True`` to prefer spaces around the assignment operator for default + or keyword arguments. + ``SPACES_BEFORE_COMMENT`` The number of spaces required before a trailing comment. diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 5642021f3..cebbc2792 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -117,6 +117,8 @@ def method(): Join short lines into one line. E.g., single line 'if' statements."""), SPACES_AROUND_POWER_OPERATOR=textwrap.dedent("""\ Use spaces around the power operator."""), + SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=textwrap.dedent("""\ + Use spaces around default or named assigns."""), SPACES_BEFORE_COMMENT=textwrap.dedent("""\ The number of spaces required before a trailing comment."""), SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=textwrap.dedent("""\ @@ -187,6 +189,7 @@ def CreatePEP8Style(): JOIN_MULTIPLE_LINES=True, SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=True, SPACES_AROUND_POWER_OPERATOR=False, + SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=False, SPACES_BEFORE_COMMENT=2, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False, SPLIT_BEFORE_BITWISE_OPERATOR=False, @@ -279,6 +282,7 @@ def _BoolConverter(s): JOIN_MULTIPLE_LINES=_BoolConverter, SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=_BoolConverter, SPACES_AROUND_POWER_OPERATOR=_BoolConverter, + SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=_BoolConverter, SPACES_BEFORE_COMMENT=int, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter, SPLIT_BEFORE_BITWISE_OPERATOR=_BoolConverter, diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 831b24926..a93789ef4 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -256,7 +256,7 @@ def _SpaceRequiredBetween(left, right): format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in right.subtypes): # A named argument or default parameter shouldn't have spaces around it. # However, a typed argument should have a space after the colon. - return lval == ':' + return lval == ':' or style.Get('SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN') if (format_token.Subtype.VARARGS_STAR in left.subtypes or format_token.Subtype.KWARGS_STAR_STAR in left.subtypes): # Don't add a space after a vararg's star or a keyword's star-star. diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index fdc944b1b..d50318306 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -3303,6 +3303,24 @@ def testNoSpacesAroundPowerOparator(self): finally: style.SetGlobalStyle(style.CreatePEP8Style()) + def testSpacesAroundDefaultOrNamedAssign(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: pep8, ' + 'SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN: True}')) + unformatted_code = textwrap.dedent("""\ + f(a=5) + """) + expected_formatted_code = textwrap.dedent("""\ + f(a = 5) + """) + uwlines = _ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreatePEP8Style()) + def testAsyncWithPrecedingComment(self): if sys.version_info[1] < 5: return From f6ac58cc21bebac8dd45641f33411dbf517b6a76 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 31 Aug 2016 10:46:33 -0700 Subject: [PATCH 013/719] Turn verify off by default. Verification isn't maintained. Don't turn it on by default. Closes #297 --- CHANGELOG | 3 +++ yapf/yapflib/reformatter.py | 2 +- yapf/yapflib/yapf_api.py | 4 ++-- yapftests/reformatter_test.py | 4 +--- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 04461f95a..dfdd18502 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,9 @@ - Add a knob, 'SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN', to allow adding spaces around the assign operator on default or named assigns. +## Changed +- Turn "verification" off by default for external APIs. + ## [0.11.1] 2016-08-17 ### Changed - Issue #228: Return exit code 0 on success, regardless of whether files were diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 93b4d3ab8..0722cb38a 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -36,7 +36,7 @@ from yapf.yapflib import verifier -def Reformat(uwlines, verify=True): +def Reformat(uwlines, verify=False): """Reformat the unwrapped lines. Arguments: diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index f509bbf37..916ba5375 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -55,7 +55,7 @@ def FormatFile(filename, style_config=None, lines=None, print_diff=False, - verify=True, + verify=False, in_place=False, logger=None): """Format a single Python file and return the formatted code. @@ -102,7 +102,7 @@ def FormatCode(unformatted_source, style_config=None, lines=None, print_diff=False, - verify=True): + verify=False): """Format a string of Python code. This provides an alternative entry point to YAPF. diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index d50318306..7108679ec 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -3141,9 +3141,7 @@ class ABC(metaclass=type): uwlines = _ParseAndUnwrap(unformatted_code) with self.assertRaises(verifier.InternalError): reformatter.Reformat(uwlines, verify=True) - with self.assertRaises(verifier.InternalError): - # default should be True - reformatter.Reformat(uwlines) + reformatter.Reformat(uwlines) # verify should be False by default. def testNoVerify(self): unformatted_code = textwrap.dedent("""\ From ace8aa9993b65f66b1968ada789a67d3384db56f Mon Sep 17 00:00:00 2001 From: Samuel Dion-Girardeau Date: Thu, 8 Sep 2016 21:01:20 -0400 Subject: [PATCH 014/719] Fix typos in the README "code base" with a space is not really a typo per se, but the spelling is now uniform across the README. --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index ab6f3cfd8..8a80a7860 100644 --- a/README.rst +++ b/README.rst @@ -28,7 +28,7 @@ Daniel Jasper. In essence, the algorithm takes the code and reformats it to the best formatting that conforms to the style guide, even if the original code didn't violate the style guide. The idea is also similar to the 'gofmt' tool for the Go programming language: end all holy wars about formatting - if the whole -code base of a project is simply piped through YAPF whenever modifications are +codebase of a project is simply piped through YAPF whenever modifications are made, the style remains consistent throughout the project and there's no point arguing about style in every code review. @@ -349,7 +349,7 @@ Knobs ``I18N_FUNCTION_CALL`` The internationalization function call names. The presence of this function - stops reformattting on that line, because the string it has cannot be moved + stops reformatting on that line, because the string it has cannot be moved away from the i18n comment. ``INDENT_DICTIONARY_VALUE`` From aeb9f3f098895b84ad2f60b50f28b66b62d6eade Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 17 Sep 2016 14:39:26 -0700 Subject: [PATCH 015/719] Don't add space between power and unary ops Closes #289 --- CHANGELOG | 3 +++ yapf/yapflib/unwrapped_line.py | 2 +- yapftests/reformatter_test.py | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index dfdd18502..693cb7d27 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,9 @@ ## Changed - Turn "verification" off by default for external APIs. +## Fixed +- Don't add space after power operator if the next operator's a unary operator. + ## [0.11.1] 2016-08-17 ### Changed - Issue #228: Return exit code 0 on success, regardless of whether files were diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index a93789ef4..a25974d9b 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -231,7 +231,7 @@ def _SpaceRequiredBetween(left, right): # A string followed by something other than a subscript, closing bracket, # or dot should have a space after it. return True - if left.is_binary_op and _IsUnaryOperator(right): + if left.is_binary_op and lval != '**' and _IsUnaryOperator(right): # Space between the binary opertor and the unary operator. return True if _IsUnaryOperator(left) and _IsUnaryOperator(right): diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index 7108679ec..64af7d119 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -1453,14 +1453,15 @@ def f(): def testBinaryOperators(self): unformatted_code = textwrap.dedent("""\ a = b ** 37 + c = (20 ** -3) / (_GRID_ROWS ** (code_length - 10)) """) expected_formatted_code = textwrap.dedent("""\ a = b**37 + c = (20**-3) / (_GRID_ROWS**(code_length - 10)) """) uwlines = _ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - def testBinaryOperators(self): code = textwrap.dedent("""\ def f(): if True: From 9c52bacb7d4ab6fd921338f0286fb45eaa8eb435 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 25 Sep 2016 15:54:02 -0700 Subject: [PATCH 016/719] Split before a function call in arg list Do then when the function call fits on a line by itself. --- CHANGELOG | 3 +++ yapf/yapflib/format_decision_state.py | 23 +++++++++++++++++++++++ yapf/yapflib/style.py | 6 +++--- yapftests/reformatter_test.py | 27 ++++++++++++++++++++++++--- yapftests/yapf_test.py | 1 + 5 files changed, 54 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 693cb7d27..38a501c80 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,9 @@ ## Changed - Turn "verification" off by default for external APIs. +- If a function call in an argument list won't fit on the current line but will + fit on a line by itself, then split before the call so that it won't be split + up unnecessarily. ## Fixed - Don't add space after power operator if the next operator's a unary operator. diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 7c2644759..29d60e43a 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -269,6 +269,29 @@ def MustSplit(self): # original comments were on a separate line. return True + if not current.next_token: + return False + + opening = _GetOpeningParen(current) + if (opening and opening.value == '(' and current.is_name and + previous.value == ','): + # If we have a function call within an argument list and it won't fit on + # the remaining line, but it will fit on a line by itself, then go ahead + # and split before the call. + total_len = 0 + ntoken = current + while ntoken: + if ntoken.value == '(': + total_len = ntoken.matching_bracket.total_length - current.total_length + break + ntoken = ntoken.next_token + + if ntoken: + indent_amt = self.stack[-1].indent * style.Get('INDENT_WIDTH') + if (total_len + indent_amt < column_limit and + total_len + self.column >= column_limit): + return True + return False def AddTokenToState(self, newline, dry_run, must_split=False): diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index cebbc2792..07e369c91 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -317,8 +317,8 @@ def CreateStyleFromConfig(style_config): Raises: StyleConfigError: if an unknown style option was encountered. """ - styles = (CreatePEP8Style(), CreateGoogleStyle(), - CreateFacebookStyle(), CreateChromiumStyle()) + styles = (CreatePEP8Style(), CreateGoogleStyle(), CreateFacebookStyle(), + CreateChromiumStyle()) def_style = False if style_config is None: for style in styles: @@ -326,7 +326,7 @@ def CreateStyleFromConfig(style_config): def_style = True break if not def_style: - return _style + return _style return DEFAULT_STYLE_FACTORY() style_factory = _STYLE_NAME_TO_FACTORY.get(style_config.lower()) if style_factory is not None: diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index 64af7d119..37bc14282 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -1768,6 +1768,27 @@ class BuganizerFixes(ReformatterTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB30536435(self): + unformatted_code = textwrap.dedent("""\ + def main(unused_argv): + if True: + if True: + aaaaaaaaaaa.comment('import-from[{}] {} {}'.format( + bbbbbbbbb.usage, + ccccccccc.within, + imports.ddddddddddddddddddd(name_item.ffffffffffffffff))) + """) + expected_formatted_code = textwrap.dedent("""\ + def main(unused_argv): + if True: + if True: + aaaaaaaaaaa.comment('import-from[{}] {} {}'.format( + bbbbbbbbb.usage, ccccccccc.within, + imports.ddddddddddddddddddd(name_item.ffffffffffffffff))) + """) + uwlines = _ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB30442148(self): unformatted_code = textwrap.dedent("""\ def lulz(): @@ -3305,9 +3326,9 @@ def testNoSpacesAroundPowerOparator(self): def testSpacesAroundDefaultOrNamedAssign(self): try: style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: pep8, ' - 'SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN: True}')) + style.CreateStyleFromConfig( + '{based_on_style: pep8, ' + 'SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN: True}')) unformatted_code = textwrap.dedent("""\ f(a=5) """) diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 40a9d3a9b..e1dfe432a 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1143,5 +1143,6 @@ def testSimple(self): """) self._Check(unformatted_code, expected_formatted_code) + if __name__ == '__main__': unittest.main() From 779fc61eb9f525b222dd279274cb46279a86a06e Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 25 Sep 2016 16:03:04 -0700 Subject: [PATCH 017/719] Bump version to v0.12.0 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- yapf/yapflib/format_decision_state.py | 3 ++- yapf/yapflib/subtype_assigner.py | 10 +++++----- yapftests/yapf_test.py | 6 +++--- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 38a501c80..765e7c252 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.12.0] UNRELEASED +## [0.12.0] 2016-09-25 ### Added - Support formatting of typed names. Typed names are formatted a similar way to how named arguments are formatted, except that there's a space after the diff --git a/yapf/__init__.py b/yapf/__init__.py index e20294534..287bd5ad4 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.11.1' +__version__ = '0.12.0' def main(argv): diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 29d60e43a..396ac73dc 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -282,7 +282,8 @@ def MustSplit(self): ntoken = current while ntoken: if ntoken.value == '(': - total_len = ntoken.matching_bracket.total_length - current.total_length + total_len = (ntoken.matching_bracket.total_length - + current.total_length) break ntoken = ntoken.next_token diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index fac0f03e6..fb1122de8 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -282,8 +282,7 @@ def _ProcessArgLists(self, node): _AppendTokenSubtype( child, subtype=_ARGLIST_TOKEN_TO_SUBTYPE.get(child.value, - format_token.Subtype.NONE), - force=False) + format_token.Subtype.NONE)) def _SetDefaultOrNamedAssignArgListSubtype(node): @@ -307,7 +306,7 @@ def HasDefaultOrNamedAssignSubtype(node): child, format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) -def _AppendTokenSubtype(node, subtype, force=True): +def _AppendTokenSubtype(node, subtype): """Append the token's subtype only if it's not already set.""" pytree_utils.AppendNodeAnnotation(node, pytree_utils.Annotation.SUBTYPE, subtype) @@ -316,7 +315,7 @@ def _AppendTokenSubtype(node, subtype, force=True): def _AppendFirstLeafTokenSubtype(node, subtype, force=False): """Append the first leaf token's subtypes.""" if isinstance(node, pytree.Leaf): - _AppendTokenSubtype(node, subtype, force=force) + _AppendTokenSubtype(node, subtype) return _AppendFirstLeafTokenSubtype(node.children[0], subtype, force=force) @@ -324,13 +323,14 @@ def _AppendFirstLeafTokenSubtype(node, subtype, force=False): def _AppendSubtypeRec(node, subtype, force=True): """Append the leafs in the node to the given subtype.""" if isinstance(node, pytree.Leaf): - _AppendTokenSubtype(node, subtype, force=force) + _AppendTokenSubtype(node, subtype) return for child in node.children: _AppendSubtypeRec(child, subtype, force=force) def _InsertPseudoParentheses(node): + """Insert pseudo parentheses so that dicts can be formatted correctly.""" comment_node = None if isinstance(node, pytree.Node): if node.children[-1].type == token.COMMENT: diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index e1dfe432a..d18cc63e0 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -25,8 +25,8 @@ import unittest from yapf.yapflib import py3compat -from yapf.yapflib import yapf_api from yapf.yapflib import style +from yapf.yapflib import yapf_api ROOT_DIR = os.path.dirname(os.path.abspath(os.path.dirname(__file__))) @@ -1121,7 +1121,7 @@ def testBadSyntax(self): class DiffIndentTest(unittest.TestCase): @staticmethod - def own_style(): + def _OwnStyle(): my_style = style.CreatePEP8Style() my_style['INDENT_WIDTH'] = 3 my_style['CONTINUATION_INDENT_WIDTH'] = 3 @@ -1129,7 +1129,7 @@ def own_style(): def _Check(self, unformatted_code, expected_formatted_code): formatted_code, _ = yapf_api.FormatCode( - unformatted_code, style_config=style.SetGlobalStyle(self.own_style())) + unformatted_code, style_config=style.SetGlobalStyle(self._OwnStyle())) self.assertEqual(expected_formatted_code, formatted_code) def testSimple(self): From f9728212e3c633da6e265ca5d45922473f30ce77 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 25 Sep 2016 16:03:04 -0700 Subject: [PATCH 018/719] Bump version to v0.12.0 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- yapf/yapflib/format_decision_state.py | 3 ++- yapf/yapflib/subtype_assigner.py | 10 +++++----- yapftests/yapf_test.py | 6 +++--- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 38a501c80..765e7c252 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.12.0] UNRELEASED +## [0.12.0] 2016-09-25 ### Added - Support formatting of typed names. Typed names are formatted a similar way to how named arguments are formatted, except that there's a space after the diff --git a/yapf/__init__.py b/yapf/__init__.py index e20294534..287bd5ad4 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.11.1' +__version__ = '0.12.0' def main(argv): diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 29d60e43a..396ac73dc 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -282,7 +282,8 @@ def MustSplit(self): ntoken = current while ntoken: if ntoken.value == '(': - total_len = ntoken.matching_bracket.total_length - current.total_length + total_len = (ntoken.matching_bracket.total_length - + current.total_length) break ntoken = ntoken.next_token diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index fac0f03e6..fb1122de8 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -282,8 +282,7 @@ def _ProcessArgLists(self, node): _AppendTokenSubtype( child, subtype=_ARGLIST_TOKEN_TO_SUBTYPE.get(child.value, - format_token.Subtype.NONE), - force=False) + format_token.Subtype.NONE)) def _SetDefaultOrNamedAssignArgListSubtype(node): @@ -307,7 +306,7 @@ def HasDefaultOrNamedAssignSubtype(node): child, format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) -def _AppendTokenSubtype(node, subtype, force=True): +def _AppendTokenSubtype(node, subtype): """Append the token's subtype only if it's not already set.""" pytree_utils.AppendNodeAnnotation(node, pytree_utils.Annotation.SUBTYPE, subtype) @@ -316,7 +315,7 @@ def _AppendTokenSubtype(node, subtype, force=True): def _AppendFirstLeafTokenSubtype(node, subtype, force=False): """Append the first leaf token's subtypes.""" if isinstance(node, pytree.Leaf): - _AppendTokenSubtype(node, subtype, force=force) + _AppendTokenSubtype(node, subtype) return _AppendFirstLeafTokenSubtype(node.children[0], subtype, force=force) @@ -324,13 +323,14 @@ def _AppendFirstLeafTokenSubtype(node, subtype, force=False): def _AppendSubtypeRec(node, subtype, force=True): """Append the leafs in the node to the given subtype.""" if isinstance(node, pytree.Leaf): - _AppendTokenSubtype(node, subtype, force=force) + _AppendTokenSubtype(node, subtype) return for child in node.children: _AppendSubtypeRec(child, subtype, force=force) def _InsertPseudoParentheses(node): + """Insert pseudo parentheses so that dicts can be formatted correctly.""" comment_node = None if isinstance(node, pytree.Node): if node.children[-1].type == token.COMMENT: diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index e1dfe432a..d18cc63e0 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -25,8 +25,8 @@ import unittest from yapf.yapflib import py3compat -from yapf.yapflib import yapf_api from yapf.yapflib import style +from yapf.yapflib import yapf_api ROOT_DIR = os.path.dirname(os.path.abspath(os.path.dirname(__file__))) @@ -1121,7 +1121,7 @@ def testBadSyntax(self): class DiffIndentTest(unittest.TestCase): @staticmethod - def own_style(): + def _OwnStyle(): my_style = style.CreatePEP8Style() my_style['INDENT_WIDTH'] = 3 my_style['CONTINUATION_INDENT_WIDTH'] = 3 @@ -1129,7 +1129,7 @@ def own_style(): def _Check(self, unformatted_code, expected_formatted_code): formatted_code, _ = yapf_api.FormatCode( - unformatted_code, style_config=style.SetGlobalStyle(self.own_style())) + unformatted_code, style_config=style.SetGlobalStyle(self._OwnStyle())) self.assertEqual(expected_formatted_code, formatted_code) def testSimple(self): From d19a088b51f687fde7b410e2316c64e7be42d009 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 28 Sep 2016 02:19:31 -0700 Subject: [PATCH 019/719] Split before term paren rather than exceed col lim --- CHANGELOG | 5 +++++ yapf/yapflib/format_decision_state.py | 4 ++-- yapf/yapflib/split_penalty.py | 8 +++++++- yapftests/reformatter_test.py | 18 ++++++++++++++++++ yapftests/split_penalty_test.py | 17 +++++++++++------ 5 files changed, 43 insertions(+), 9 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 765e7c252..ed8eb7dc6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,11 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.12.1] UNRELEASED +### Fixed +- Prefer to split before a terminating r-paren in an argument list if the line + would otherwise go over the column limit. + ## [0.12.0] 2016-09-25 ### Added - Support formatting of typed names. Typed names are formatted a similar way to diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 396ac73dc..922c0675e 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -282,8 +282,8 @@ def MustSplit(self): ntoken = current while ntoken: if ntoken.value == '(': - total_len = (ntoken.matching_bracket.total_length - - current.total_length) + total_len = ( + ntoken.matching_bracket.total_length - current.total_length) break ntoken = ntoken.next_token diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 0f0810022..9960c3380 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -24,6 +24,7 @@ # TODO(morbo): Document the annotations in a centralized place. E.g., the # README file. UNBREAKABLE = 1000 * 1000 +VERY_STRONGLY_CONNECTED = 3000 DOTTED_NAME = 2500 STRONGLY_CONNECTED = 2000 CONTIGUOUS_LIST = 500 @@ -210,7 +211,12 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring last_child_node = last_child_node.prev_sibling if not style.Get('DEDENT_CLOSING_BRACKETS'): if _LastChildNode(last_child_node.prev_sibling).value != ',': - self._SetUnbreakable(last_child_node) + if last_child_node.value == ']': + self._SetUnbreakable(last_child_node) + else: + pytree_utils.SetNodeAnnotation( + last_child_node, pytree_utils.Annotation.SPLIT_PENALTY, + VERY_STRONGLY_CONNECTED) if _FirstChildNode(trailer).lineno == last_child_node.lineno: # If the trailer was originally on one line, then try to keep it diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index 37bc14282..599ffe711 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -1768,6 +1768,24 @@ class BuganizerFixes(ReformatterTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB26034238(self): + unformatted_code = textwrap.dedent("""\ + class Thing: + + def Function(self): + thing.Scrape('/aaaaaaaaa/bbbbbbbbbb/ccccc/dddd/eeeeeeeeeeeeee/ffffffffffffff').AndReturn(42) + """) + expected_formatted_code = textwrap.dedent("""\ + class Thing: + + def Function(self): + thing.Scrape( + '/aaaaaaaaa/bbbbbbbbbb/ccccc/dddd/eeeeeeeeeeeeee/ffffffffffffff' + ).AndReturn(42) + """) + uwlines = _ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB30536435(self): unformatted_code = textwrap.dedent("""\ def main(unused_argv): diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index 51f8f3e06..6bc80e015 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -24,6 +24,7 @@ from yapf.yapflib import split_penalty UNBREAKABLE = split_penalty.UNBREAKABLE +VERY_STRONGLY_CONNECTED = split_penalty.VERY_STRONGLY_CONNECTED DOTTED_NAME = split_penalty.DOTTED_NAME STRONGLY_CONNECTED = split_penalty.STRONGLY_CONNECTED CONTIGUOUS_LIST = split_penalty.CONTIGUOUS_LIST @@ -163,7 +164,9 @@ def testStronglyConnected(self): """) tree = self._ParseAndComputePenalties(code) self._CheckPenalties(tree, [ - ('a', None), ('=', None), ('{', None), + ('a', None), + ('=', None), + ('{', None), ("'x'", None), (':', STRONGLY_CONNECTED), ('42', None), @@ -174,12 +177,12 @@ def testStronglyConnected(self): ('a', UNBREAKABLE), (':', UNBREAKABLE), ('23', UNBREAKABLE), - (')', UNBREAKABLE), + (')', VERY_STRONGLY_CONNECTED), (':', STRONGLY_CONNECTED), ('37', None), (',', None), ('}', None), - ]) # yapf: disable + ]) # Test list comprehension. code = textwrap.dedent(r""" @@ -200,7 +203,7 @@ def testStronglyConnected(self): ('==', STRONGLY_CONNECTED), ('37', STRONGLY_CONNECTED), (']', STRONGLY_CONNECTED), - ]) # yapf: disable + ]) def testFuncCalls(self): code = 'foo(1, 2, 3)\n' @@ -213,7 +216,8 @@ def testFuncCalls(self): ('2', CONTIGUOUS_LIST), (',', CONTIGUOUS_LIST), ('3', CONTIGUOUS_LIST), - (')', UNBREAKABLE)]) # yapf: disable + (')', VERY_STRONGLY_CONNECTED), + ]) # Now a method call, which has more than one trailer code = 'foo.bar.baz(1, 2, 3)\n' @@ -230,7 +234,8 @@ def testFuncCalls(self): ('2', CONTIGUOUS_LIST), (',', CONTIGUOUS_LIST), ('3', CONTIGUOUS_LIST), - (')', UNBREAKABLE)]) # yapf: disable + (')', VERY_STRONGLY_CONNECTED), + ]) if __name__ == '__main__': From fb3199a49640bd0954eece0799e278328b3749c4 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 28 Sep 2016 19:13:16 -0700 Subject: [PATCH 020/719] Split before the first element in a dictionary --- CHANGELOG | 2 + yapf/yapflib/subtype_assigner.py | 14 ++++--- yapftests/reformatter_test.py | 65 ++++++++++++++++++++++---------- 3 files changed, 55 insertions(+), 26 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ed8eb7dc6..a6d71ff26 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,8 @@ ### Fixed - Prefer to split before a terminating r-paren in an argument list if the line would otherwise go over the column limit. +- Split before the first key in a dictionary if the dictionary cannot fit on a + single line. ## [0.12.0] 2016-09-25 ### Added diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index fb1122de8..b097174db 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -73,7 +73,6 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name if index < len(node.children): child = node.children[index + 1] dict_maker = isinstance(child, pytree.Leaf) and child.value == ':' - last_was_comma = False last_was_colon = False for child in node.children: if pytree_utils.NodeName(child) == 'comp_for': @@ -81,10 +80,7 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name format_token.Subtype.DICT_SET_GENERATOR) else: if dict_maker: - if last_was_comma: - _AppendFirstLeafTokenSubtype(child, - format_token.Subtype.DICTIONARY_KEY) - elif last_was_colon: + if last_was_colon: if pytree_utils.NodeName(child) == 'power': _AppendSubtypeRec(child, format_token.Subtype.NONE) else: @@ -92,7 +88,13 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name child, format_token.Subtype.DICTIONARY_VALUE) if style.Get('INDENT_DICTIONARY_VALUE'): _InsertPseudoParentheses(child) - last_was_comma = isinstance(child, pytree.Leaf) and child.value == ',' + elif (child is not None and + (isinstance(child, pytree.Node) or child.value not in '{:,')): + # Mark the first leaf of a key entry as a DICTIONARY_KEY. We + # normally want to split before them if the dictionary cannot exist + # on a single line. + _AppendFirstLeafTokenSubtype(child, + format_token.Subtype.DICTIONARY_KEY) last_was_colon = isinstance(child, pytree.Leaf) and child.value == ':' self.Visit(child) diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index 599ffe711..7a639084f 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -1127,9 +1127,10 @@ def testSplitStringsIfSurroundedByParens(self): a = foo.bar({'xxxxxxxxxxxxxxxxxxxxxxx' 'yyyyyyyyyyyyyyyyyyyyyyyyyy': baz[42]} + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbb' 'cccccccccccccccccccccccccccccccc' 'ddddddddddddddddddddddddddddd') """) expected_formatted_code = textwrap.dedent("""\ - a = foo.bar({'xxxxxxxxxxxxxxxxxxxxxxx' - 'yyyyyyyyyyyyyyyyyyyyyyyyyy': baz[42]} + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + a = foo.bar({ + 'xxxxxxxxxxxxxxxxxxxxxxx' + 'yyyyyyyyyyyyyyyyyyyyyyyyyy': baz[42] + } + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbb' 'cccccccccccccccccccccccccccccccc' 'ddddddddddddddddddddddddddddd') @@ -1768,6 +1769,20 @@ class BuganizerFixes(ReformatterTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB30760569(self): + unformatted_code = textwrap.dedent("""\ + {'1234567890123456789012345678901234567890123456789012345678901234567890': + '1234567890123456789012345678901234567890'} + """) + expected_formatted_code = textwrap.dedent("""\ + { + '1234567890123456789012345678901234567890123456789012345678901234567890': + '1234567890123456789012345678901234567890' + } + """) + uwlines = _ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB26034238(self): unformatted_code = textwrap.dedent("""\ class Thing: @@ -1987,13 +2002,15 @@ def _(): def testB25505359(self): code = textwrap.dedent("""\ _EXAMPLE = { - 'aaaaaaaaaaaaaa': [ - {'bbbb': 'cccccccccccccccccccccc', - 'dddddddddddd': [ - ]}, {'bbbb': 'ccccccccccccccccccc', - 'dddddddddddd': [ - ]} - ] + 'aaaaaaaaaaaaaa': [{ + 'bbbb': 'cccccccccccccccccccccc', + 'dddddddddddd': [ + ] + }, { + 'bbbb': 'ccccccccccccccccccc', + 'dddddddddddd': [ + ] + }] } """) uwlines = _ParseAndUnwrap(code) @@ -2013,8 +2030,9 @@ def testB25136704(self): class f: def test(self): - self.bbbbbbb[0]['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - {'xxxxxx': 'yyyyyy'}] = cccccc.ddd('1m', '10x1+1') + self.bbbbbbb[0]['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', { + 'xxxxxx': 'yyyyyy' + }] = cccccc.ddd('1m', '10x1+1') """) uwlines = _ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -2143,12 +2161,18 @@ class F(): def f(): self.assertDictEqual(accounts, { - 'foo': {'account': 'foo', - 'lines': 'l1\\nl2\\nl3\\n1 line(s) were elided.'}, - 'bar': {'account': 'bar', - 'lines': 'l5\\nl6\\nl7'}, - 'wiz': {'account': 'wiz', - 'lines': 'l8'} + 'foo': { + 'account': 'foo', + 'lines': 'l1\\nl2\\nl3\\n1 line(s) were elided.' + }, + 'bar': { + 'account': 'bar', + 'lines': 'l5\\nl6\\nl7' + }, + 'wiz': { + 'account': 'wiz', + 'lines': 'l8' + } }) """) uwlines = _ParseAndUnwrap(unformatted_code) @@ -2562,8 +2586,9 @@ def f(): def f(): if True: if True: - return aaaa.bbbbbbbbb(ccccccc=dddddddddddddd( - {('eeee', 'ffffffff'): str(j)})) + return aaaa.bbbbbbbbb(ccccccc=dddddddddddddd({ + ('eeee', 'ffffffff'): str(j) + })) """) uwlines = _ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) From e46a7e1929fc741ac03f5c9a4d7dc81fd3a94405 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 30 Sep 2016 00:45:59 -0700 Subject: [PATCH 021/719] Ignore 'pylint' comments for column length --- CHANGELOG | 2 ++ yapf/yapflib/reformatter.py | 12 ++++++++++-- yapftests/reformatter_test.py | 24 ++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a6d71ff26..30faec35f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,8 @@ would otherwise go over the column limit. - Split before the first key in a dictionary if the dictionary cannot fit on a single line. +- Don't count "pylint" comments when determining if the line goes over the + column limit. ## [0.12.0] 2016-09-25 ### Added diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 0722cb38a..5fa85c320 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -217,8 +217,16 @@ def _CanPlaceOnSingleLine(uwline): True if the line can or should be added to a single line. False otherwise. """ indent_amt = style.Get('INDENT_WIDTH') * uwline.depth - return (uwline.last.total_length + indent_amt <= style.Get('COLUMN_LIMIT') and - not any(tok.is_comment for tok in uwline.tokens[:-1])) + last = uwline.last + last_index = -1 + if last.is_comment and re.search(r'^#+\s+pylint:', last.value.strip(), + re.IGNORECASE): + last = last.previous_token + last_index = -2 + if last is None: + return True + return (last.total_length + indent_amt <= style.Get('COLUMN_LIMIT') and + not any(tok.is_comment for tok in uwline.tokens[:last_index])) def _FormatFinalLines(final_lines, verify): diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index 7a639084f..8e1364a49 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -1769,6 +1769,30 @@ class BuganizerFixes(ReformatterTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB31847238(self): + unformatted_code = textwrap.dedent("""\ + class _(): + + def aaaaa(self, bbbbb, cccccccccccccc=None): # pylint: disable=unused-argument + return 1 + + def xxxxx(self, yyyyy, zzzzzzzzzzzzzz=None): # A normal comment that runs over the column limit. + return 1 + """) + expected_formatted_code = textwrap.dedent("""\ + class _(): + + def aaaaa(self, bbbbb, cccccccccccccc=None): # pylint: disable=unused-argument + return 1 + + def xxxxx( + self, yyyyy, + zzzzzzzzzzzzzz=None): # A normal comment that runs over the column limit. + return 1 + """) + uwlines = _ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB30760569(self): unformatted_code = textwrap.dedent("""\ {'1234567890123456789012345678901234567890123456789012345678901234567890': From 44d33fd9604e32a0af38904334e108c4096d9fc2 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 30 Sep 2016 15:02:30 -0700 Subject: [PATCH 022/719] Remove some dead code relating to dict vals --- setup.py | 8 ++++++-- yapf/yapflib/format_decision_state.py | 19 ++++++++----------- yapf/yapflib/subtype_assigner.py | 7 ++----- yapftests/reformatter_test.py | 11 +++++++---- 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/setup.py b/setup.py index 59042c009..c1a4e8344 100644 --- a/setup.py +++ b/setup.py @@ -64,5 +64,9 @@ def run(self): 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Quality Assurance', ], - entry_points={'console_scripts': ['yapf = yapf:run_main'],}, - cmdclass={'test': RunTests,},) + entry_points={ + 'console_scripts': ['yapf = yapf:run_main'], + }, + cmdclass={ + 'test': RunTests, + },) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 922c0675e..5bd24ef44 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -188,7 +188,7 @@ def MustSplit(self): opening_column = len(pptoken.value) if pptoken else 0 - indent_amt - 1 if previous.value == '(': return opening_column >= style.Get('CONTINUATION_INDENT_WIDTH') - opening = _GetOpeningParen(current) + opening = _GetOpeningBracket(current) if opening: arglist_length = (opening.matching_bracket.total_length - opening.total_length + self.stack[-1].indent) @@ -197,7 +197,7 @@ def MustSplit(self): if style.Get('SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED'): # Split before arguments in a function call or definition if the # arguments are terminated by a comma. - opening = _GetOpeningParen(current) + opening = _GetOpeningBracket(current) if opening and opening.previous_token and opening.previous_token.is_name: if previous.value in '(,': if opening.matching_bracket.previous_token.value == ',': @@ -208,11 +208,6 @@ def MustSplit(self): # Retain the split after the container opening. return True - if (previous.value == ':' and _IsDictionaryValue(current) and - current.lineno != previous.lineno): - # Retain the split between the dictionary key and value. - return True - if previous.value == '{': closing = previous.matching_bracket length = closing.total_length - previous.total_length + self.column @@ -272,7 +267,7 @@ def MustSplit(self): if not current.next_token: return False - opening = _GetOpeningParen(current) + opening = _GetOpeningBracket(current) if (opening and opening.value == '(' and current.is_name and previous.value == ','): # If we have a function call within an argument list and it won't fit on @@ -513,7 +508,8 @@ def _IsFunctionCallWithArguments(token): def _IsDictionaryValue(token): while token: - if format_token.Subtype.DICTIONARY_VALUE in token.subtypes: + if (format_token.Subtype.DICTIONARY_VALUE in token.subtypes or + token.is_pseudo_paren): return True token = token.previous_token return False @@ -527,10 +523,11 @@ def _GetLengthOfSubtype(token, subtype, exclude=None): return current.total_length - token.total_length + 1 -def _GetOpeningParen(current): +def _GetOpeningBracket(current): previous = current - if previous and previous.matching_bracket: + if previous and previous.matching_bracket and not previous.is_pseudo_paren: return previous.matching_bracket + previous = previous.previous_token while previous is not None and previous.matching_bracket is None: previous = previous.previous_token if not previous: diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index b097174db..bc7a0c205 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -81,11 +81,8 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name else: if dict_maker: if last_was_colon: - if pytree_utils.NodeName(child) == 'power': - _AppendSubtypeRec(child, format_token.Subtype.NONE) - else: - _AppendFirstLeafTokenSubtype( - child, format_token.Subtype.DICTIONARY_VALUE) + _AppendFirstLeafTokenSubtype(child, + format_token.Subtype.DICTIONARY_VALUE) if style.Get('INDENT_DICTIONARY_VALUE'): _InsertPseudoParentheses(child) elif (child is not None and diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index 8e1364a49..88fdd7537 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -1552,10 +1552,13 @@ class A(object): def method(self): filters = { 'expressions': [ - {'field': { - 'search_field': - {'user_field': 'latest_party__number_of_guests'}, - }} + { + 'field': { + 'search_field': { + 'user_field': 'latest_party__number_of_guests' + }, + } + } ] } """) From f51d265de4ade5f98a1b433cddfc30dfeae08aee Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 30 Sep 2016 15:12:29 -0700 Subject: [PATCH 023/719] Extract fits on line calculation --- yapf/yapflib/format_decision_state.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 5bd24ef44..61aaacc35 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -143,8 +143,7 @@ def MustSplit(self): else: last_token = _LastTokenInLine(bracket.matching_bracket) - length = last_token.total_length - bracket.total_length - if length + self.column >= column_limit: + if not self._FitsOnLine(bracket, last_token): self.stack[-1].split_before_closing_bracket = True return True @@ -210,8 +209,8 @@ def MustSplit(self): if previous.value == '{': closing = previous.matching_bracket - length = closing.total_length - previous.total_length + self.column - if length > column_limit and closing.previous_token.value == ',': + if (not self._FitsOnLine(previous, closing) and + closing.previous_token.value == ','): self.stack[-1].split_before_closing_bracket = True return True @@ -233,9 +232,7 @@ def MustSplit(self): previous_previous_token = previous.previous_token if (current.is_name and previous_previous_token and previous_previous_token.is_name and previous.value == '('): - arg_length = previous.matching_bracket.total_length - arg_length -= previous.total_length - if arg_length + self.column > column_limit: + if not self._FitsOnLine(previous, previous.matching_bracket): if _IsFunctionCallWithArguments(current): # There is a function call, with more than 1 argument, where # the first argument is itself a function call with arguments. @@ -245,9 +242,7 @@ def MustSplit(self): # argument to keep things looking good. return True elif current.OpensScope(): - arg_length = current.matching_bracket.total_length - arg_length -= current.total_length - if arg_length + self.column > column_limit: + if not self._FitsOnLine(current, current.matching_bracket): # There is a data literal that will need to be split and could mess # up the formatting. return True @@ -494,6 +489,11 @@ def _MoveStateToNextToken(self): return penalty + def _FitsOnLine(self, start, end): + column_limit = style.Get('COLUMN_LIMIT') + length = end.total_length - start.total_length + return length + self.column < column_limit + def _IsFunctionCallWithArguments(token): while token: From 86773bf290010e32574f8f525b009da100e35dc4 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 30 Sep 2016 15:25:33 -0700 Subject: [PATCH 024/719] Split before a dict values when dict doesn't fit on one line --- yapf/yapflib/format_decision_state.py | 7 +++++++ yapftests/reformatter_test.py | 30 ++++++++++++++------------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 61aaacc35..274a3c9b9 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -202,6 +202,13 @@ def MustSplit(self): if opening.matching_bracket.previous_token.value == ',': return True + if previous.is_pseudo_paren and _IsDictionaryValue(current): + # Split before the dictionary value if we can't fit the whole dictionary + # on one line. + opening = _GetOpeningBracket(current) + if not self._FitsOnLine(opening, opening.matching_bracket): + return True + if (previous.value in '{[' and current.lineno != previous.lineno and format_token.Subtype.SUBSCRIPT_BRACKET not in previous.subtypes): # Retain the split after the container opening. diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index 88fdd7537..d34ba6514 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -1290,12 +1290,12 @@ class Test: def testSomething(self): expected = { - ('aaaaaaaaaaaaa', - 'bbbb'): 'ccccccccccccccccccccccccccccccccccccccccccc', - ('aaaaaaaaaaaaa', - 'bbbb'): 'ccccccccccccccccccccccccccccccccccccccccccc', - ('aaaaaaaaaaaaa', - 'bbbb'): 'ccccccccccccccccccccccccccccccccccccccccccc', + ('aaaaaaaaaaaaa', 'bbbb'): + 'ccccccccccccccccccccccccccccccccccccccccccc', + ('aaaaaaaaaaaaa', 'bbbb'): + 'ccccccccccccccccccccccccccccccccccccccccccc', + ('aaaaaaaaaaaaa', 'bbbb'): + 'ccccccccccccccccccccccccccccccccccccccccccc', } """) uwlines = _ParseAndUnwrap(unformatted_code) @@ -2140,8 +2140,8 @@ def foo(): extra_env={ "OOOOOOOOOOOOOOOOOOOOO": FLAGS.zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, - "PPPPPPPPPPPPPPPPPPPPP": FLAGS.aaaaaaaaaaaaaa + - FLAGS.bbbbbbbbbbbbbbbbbbb, + "PPPPPPPPPPPPPPPPPPPPP": + FLAGS.aaaaaaaaaaaaaa + FLAGS.bbbbbbbbbbbbbbbbbbb, }) """) uwlines = _ParseAndUnwrap(unformatted_code) @@ -2272,8 +2272,9 @@ def _(): dict( ffffffffffffffff, **{ - 'mmmmmm:ssssss': m.rrrrrrrrrrr( - '|'.join(iiiiiiiiiiiiii), iiiiii=True) + 'mmmmmm:ssssss': + m.rrrrrrrrrrr( + '|'.join(iiiiiiiiiiiiii), iiiiii=True) })) | m.wwwwww(m.rrrr('1h')) | m.ggggggg(bbbbbbbbbbbbbbb)) @@ -2348,8 +2349,8 @@ def testB20849933(self): def main(unused_argv): if True: aaaaaaaa = { - 'xxx': '%s/cccccc/ddddddddddddddddddd.jar' % - (eeeeee.FFFFFFFFFFFFFFFFFF), + 'xxx': + '%s/cccccc/ddddddddddddddddddd.jar' % (eeeeee.FFFFFFFFFFFFFFFFFF), } """) uwlines = _ParseAndUnwrap(code) @@ -2370,8 +2371,9 @@ def testB20605036(self): 'aaaa': { # A comment for no particular reason. 'xxxxxxxx': 'bbbbbbbbb', - 'yyyyyyyyyyyyyyyyyy': 'cccccccccccccccccccccccccccccc' - 'dddddddddddddddddddddddddddddddddddddddddd', + 'yyyyyyyyyyyyyyyyyy': + 'cccccccccccccccccccccccccccccc' + 'dddddddddddddddddddddddddddddddddddddddddd', } } """) From 556d154dba64ae0291396082be93321ca4d5b138 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 30 Sep 2016 16:04:24 -0700 Subject: [PATCH 025/719] Remove dead code --- yapf/yapflib/format_decision_state.py | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 274a3c9b9..7dc77612f 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -202,12 +202,14 @@ def MustSplit(self): if opening.matching_bracket.previous_token.value == ',': return True - if previous.is_pseudo_paren and _IsDictionaryValue(current): - # Split before the dictionary value if we can't fit the whole dictionary - # on one line. - opening = _GetOpeningBracket(current) - if not self._FitsOnLine(opening, opening.matching_bracket): - return True + if (format_token.Subtype.DICTIONARY_VALUE in current.subtypes or + previous.is_pseudo_paren): + if previous.is_pseudo_paren: + # Split before the dictionary value if we can't fit the whole dictionary + # on one line. + opening = _GetOpeningBracket(current) + if not self._FitsOnLine(opening, opening.matching_bracket): + return True if (previous.value in '{[' and current.lineno != previous.lineno and format_token.Subtype.SUBSCRIPT_BRACKET not in previous.subtypes): @@ -513,15 +515,6 @@ def _IsFunctionCallWithArguments(token): return False -def _IsDictionaryValue(token): - while token: - if (format_token.Subtype.DICTIONARY_VALUE in token.subtypes or - token.is_pseudo_paren): - return True - token = token.previous_token - return False - - def _GetLengthOfSubtype(token, subtype, exclude=None): current = token while (current.next_token and subtype in current.subtypes and From 5ac2fdf916fa49dc361b7777dabb6913d4a2c241 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 1 Oct 2016 23:02:32 -0700 Subject: [PATCH 026/719] Lambdas aren't named assigns --- CHANGELOG | 2 ++ yapf/yapflib/format_decision_state.py | 3 ++- yapf/yapflib/format_token.py | 21 +++++++++++---------- yapf/yapflib/subtype_assigner.py | 15 +++++++++------ yapf/yapflib/unwrapped_line.py | 3 +++ yapftests/reformatter_test.py | 12 ++++++------ 6 files changed, 33 insertions(+), 23 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 30faec35f..95812de0a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,8 @@ single line. - Don't count "pylint" comments when determining if the line goes over the column limit. +- Don't count the argument list of a lambda as a named assign in a function + call. ## [0.12.0] 2016-09-25 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 7dc77612f..7e50b8079 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -168,6 +168,7 @@ def MustSplit(self): return True if (style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and + not current.is_comment and format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in current.subtypes): if (previous.value not in {'=', ':', '*', '**'} and @@ -528,7 +529,7 @@ def _GetOpeningBracket(current): if previous and previous.matching_bracket and not previous.is_pseudo_paren: return previous.matching_bracket previous = previous.previous_token - while previous is not None and previous.matching_bracket is None: + while previous and not previous.matching_bracket: previous = previous.previous_token if not previous: break diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 32d11c9da..659756492 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -41,16 +41,17 @@ class Subtype(object): SUBSCRIPT_COLON = 3 SUBSCRIPT_BRACKET = 4 DEFAULT_OR_NAMED_ASSIGN = 5 - VARARGS_STAR = 6 - KWARGS_STAR_STAR = 7 - ASSIGN_OPERATOR = 8 - DICTIONARY_KEY = 9 - DICTIONARY_VALUE = 10 - DICT_SET_GENERATOR = 11 - COMP_FOR = 12 - COMP_IF = 13 - DEFAULT_OR_NAMED_ASSIGN_ARG_LIST = 14 - FUNC_DEF = 15 + DEFAULT_OR_NAMED_ASSIGN_ARG_LIST = 6 + VARARGS_LIST = 7 + VARARGS_STAR = 8 + KWARGS_STAR_STAR = 9 + ASSIGN_OPERATOR = 10 + DICTIONARY_KEY = 11 + DICTIONARY_VALUE = 12 + DICT_SET_GENERATOR = 13 + COMP_FOR = 14 + COMP_IF = 15 + FUNC_DEF = 16 class FormatToken(object): diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index bc7a0c205..d1bf9aec1 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -81,10 +81,11 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name else: if dict_maker: if last_was_colon: - _AppendFirstLeafTokenSubtype(child, - format_token.Subtype.DICTIONARY_VALUE) if style.Get('INDENT_DICTIONARY_VALUE'): _InsertPseudoParentheses(child) + else: + _AppendFirstLeafTokenSubtype(child, + format_token.Subtype.DICTIONARY_VALUE) elif (child is not None and (isinstance(child, pytree.Node) or child.value not in '{:,')): # Mark the first leaf of a key entry as a DICTIONARY_KEY. We @@ -260,8 +261,10 @@ def Visit_varargslist(self, node): # pylint: disable=invalid-name # ('*' [vname] (',' vname ['=' test])* [',' '**' vname] # | '**' vname) # | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) - self._ProcessArgLists(node) - _SetDefaultOrNamedAssignArgListSubtype(node) + for child in node.children: + self.Visit(child) + if isinstance(child, pytree.Leaf) and child.value == '=': + _AppendTokenSubtype(child, format_token.Subtype.VARARGS_LIST) def Visit_comp_for(self, node): # pylint: disable=invalid-name # comp_for ::= 'for' exprlist 'in' testlist_safe [comp_iter] @@ -311,12 +314,12 @@ def _AppendTokenSubtype(node, subtype): subtype) -def _AppendFirstLeafTokenSubtype(node, subtype, force=False): +def _AppendFirstLeafTokenSubtype(node, subtype): """Append the first leaf token's subtypes.""" if isinstance(node, pytree.Leaf): _AppendTokenSubtype(node, subtype) return - _AppendFirstLeafTokenSubtype(node.children[0], subtype, force=force) + _AppendFirstLeafTokenSubtype(node.children[0], subtype) def _AppendSubtypeRec(node, subtype, force=True): diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index a25974d9b..d8a9b0f97 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -257,6 +257,9 @@ def _SpaceRequiredBetween(left, right): # A named argument or default parameter shouldn't have spaces around it. # However, a typed argument should have a space after the colon. return lval == ':' or style.Get('SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN') + if (format_token.Subtype.VARARGS_LIST in left.subtypes or + format_token.Subtype.VARARGS_LIST in right.subtypes): + return False if (format_token.Subtype.VARARGS_STAR in left.subtypes or format_token.Subtype.KWARGS_STAR_STAR in left.subtypes): # Don't add a space after a vararg's star or a keyword's star-star. diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index d34ba6514..fa2eadf3f 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -1303,9 +1303,10 @@ def testSomething(self): def testEndingComment(self): code = textwrap.dedent("""\ - a = f(a="something", - b="something requiring comment which is quite long", # comment about b (pushes line over 79) - c="something else, about which comment doesn't make sense") + a = f( + a="something", + b="something requiring comment which is quite long", # comment about b (pushes line over 79) + c="something else, about which comment doesn't make sense") """) uwlines = _ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -2513,9 +2514,8 @@ def bar(self): def testB19194420(self): code = textwrap.dedent("""\ - method.Set( - 'long argument goes here that causes the line to break', - lambda arg2=0.5: arg2) + method.Set('long argument goes here that causes the line to break', + lambda arg2=0.5: arg2) """) uwlines = _ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) From a34d1581936bb00fc245b058c6d1cb4b0b27ceb2 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 1 Oct 2016 23:57:05 -0700 Subject: [PATCH 027/719] Put dict elems on single line if all elems fit on single lines --- CHANGELOG | 5 ++ yapf/yapflib/format_decision_state.py | 66 +++++++++++++++++--------- yapf/yapflib/subtype_assigner.py | 4 +- yapftests/reformatter_test.py | 67 +++++++++++++++++++++++++-- 4 files changed, 113 insertions(+), 29 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 95812de0a..f4c9f3dc4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,11 @@ # This project adheres to [Semantic Versioning](http://semver.org/). ## [0.12.1] UNRELEASED +### Changed +- Dictionary values will be placed on the same line as the key if *all* of the + elements in the dictionary can be placed on one line. Otherwise, the + dictionary values will be placed on the next line. + ### Fixed - Prefer to split before a terminating r-paren in an argument list if the line would otherwise go over the column limit. diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 7e50b8079..9a7e26ad5 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -79,6 +79,7 @@ def __init__(self, line, first_indent): self.first_indent = first_indent self.newline = False self.previous = None + self.column_limit = style.Get('COLUMN_LIMIT') self._MoveStateToNextToken() def Clone(self): @@ -123,7 +124,6 @@ def MustSplit(self): """Returns True if the line must split before the next token.""" current = self.next_token previous = current.previous_token - column_limit = style.Get('COLUMN_LIMIT') if current.must_break_before: return True @@ -167,8 +167,7 @@ def MustSplit(self): if format_token.Subtype.DICT_SET_GENERATOR in current.subtypes: return True - if (style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and - not current.is_comment and + if (style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and not current.is_comment and format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in current.subtypes): if (previous.value not in {'=', ':', '*', '**'} and @@ -192,7 +191,7 @@ def MustSplit(self): if opening: arglist_length = (opening.matching_bracket.total_length - opening.total_length + self.stack[-1].indent) - return arglist_length > column_limit + return arglist_length > self.column_limit if style.Get('SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED'): # Split before arguments in a function call or definition if the @@ -204,13 +203,14 @@ def MustSplit(self): return True if (format_token.Subtype.DICTIONARY_VALUE in current.subtypes or - previous.is_pseudo_paren): - if previous.is_pseudo_paren: - # Split before the dictionary value if we can't fit the whole dictionary - # on one line. + (previous.is_pseudo_paren and previous.value == '(')): + if not current.OpensScope(): opening = _GetOpeningBracket(current) - if not self._FitsOnLine(opening, opening.matching_bracket): - return True + if previous.is_pseudo_paren: + # Split before the dictionary value if we can't fit the whole + # dictionary on one line. + if not self._AllDictElementsFitOnOneLine(opening): + return True if (previous.value in '{[' and current.lineno != previous.lineno and format_token.Subtype.SUBSCRIPT_BRACKET not in previous.subtypes): @@ -229,14 +229,14 @@ def MustSplit(self): # Split at the beginning of a list comprehension. length = _GetLengthOfSubtype(current, format_token.Subtype.COMP_FOR, format_token.Subtype.COMP_IF) - if length + self.column > column_limit: + if length + self.column > self.column_limit: return True if (format_token.Subtype.COMP_IF in current.subtypes and format_token.Subtype.COMP_IF not in previous.subtypes): # Split at the beginning of an if expression. length = _GetLengthOfSubtype(current, format_token.Subtype.COMP_IF) - if length + self.column > column_limit: + if length + self.column > self.column_limit: return True previous_previous_token = previous.previous_token @@ -269,9 +269,6 @@ def MustSplit(self): # original comments were on a separate line. return True - if not current.next_token: - return False - opening = _GetOpeningBracket(current) if (opening and opening.value == '(' and current.is_name and previous.value == ','): @@ -289,8 +286,8 @@ def MustSplit(self): if ntoken: indent_amt = self.stack[-1].indent * style.Get('INDENT_WIDTH') - if (total_len + indent_amt < column_limit and - total_len + self.column >= column_limit): + if (total_len + indent_amt < self.column_limit and + total_len + self.column >= self.column_limit): return True return False @@ -487,9 +484,8 @@ def _MoveStateToNextToken(self): # Calculate the penalty for overflowing the column limit. penalty = 0 - column_limit = style.Get('COLUMN_LIMIT') - if not current.is_pylint_comment and self.column > column_limit: - excess_characters = self.column - column_limit + if not current.is_pylint_comment and self.column > self.column_limit: + excess_characters = self.column - self.column_limit penalty += style.Get('SPLIT_PENALTY_EXCESS_CHARACTER') * excess_characters if is_multiline_string: @@ -500,9 +496,23 @@ def _MoveStateToNextToken(self): return penalty def _FitsOnLine(self, start, end): - column_limit = style.Get('COLUMN_LIMIT') + """Determines if line between start and end can fit on the current line.""" length = end.total_length - start.total_length - return length + self.column < column_limit + return length + self.column < self.column_limit + + def _AllDictElementsFitOnOneLine(self, opening): + closing = opening.matching_bracket + current, previous = opening.next_token, opening + start = None + while current and current != closing: + if format_token.Subtype.DICTIONARY_KEY in current.subtypes: + if start and not self._FitsOnLine(start, current.previous_token): + return False + start = current + if current.OpensScope(): + current = current.matching_bracket + current = current.next_token + return start and self._FitsOnLine(start, current.previous_token) def _IsFunctionCallWithArguments(token): @@ -525,6 +535,18 @@ def _GetLengthOfSubtype(token, subtype, exclude=None): def _GetOpeningBracket(current): + if current.matching_bracket and not current.is_pseudo_paren: + return current.matching_bracket + while current: + if current.ClosesScope(): + current = current.matching_bracket + elif current.is_pseudo_paren: + current = current.previous_token + elif current.OpensScope(): + return current + current = current.previous_token + return None + previous = current if previous and previous.matching_bracket and not previous.is_pseudo_paren: return previous.matching_bracket diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index d1bf9aec1..b99e0d69f 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -84,8 +84,8 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name if style.Get('INDENT_DICTIONARY_VALUE'): _InsertPseudoParentheses(child) else: - _AppendFirstLeafTokenSubtype(child, - format_token.Subtype.DICTIONARY_VALUE) + _AppendFirstLeafTokenSubtype( + child, format_token.Subtype.DICTIONARY_VALUE) elif (child is not None and (isinstance(child, pytree.Node) or child.value not in '{:,')): # Mark the first leaf of a key entry as a DICTIONARY_KEY. We diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index fa2eadf3f..91f42fbcc 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -1198,7 +1198,8 @@ def bar(self): def testDictSetGenerator(self): code = textwrap.dedent("""\ foo = { - variable: 'hello world. How are you today?' + variable: + 'hello world. How are you today?' for variable in fnord if variable != 37 } """) @@ -1766,6 +1767,58 @@ def testImportAsList(self): uwlines = _ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testDictionaryValuesOnOwnLines(self): + unformatted_code = textwrap.dedent("""\ + a = { + 'aaaaaaaaaaaaaaaaaaaaaaaa': + Check('ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ', '=', True), + 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb': + Check('YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY', '=', True), + 'ccccccccccccccc': + Check('XXXXXXXXXXXXXXXXXXX', '!=', 'SUSPENDED'), + 'dddddddddddddddddddddddddddddd': + Check('WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW', '=', False), + 'eeeeeeeeeeeeeeeeeeeeeeeeeeeee': + Check('VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV', '=', False), + 'ffffffffffffffffffffffffff': + Check('UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU', '=', True), + 'ggggggggggggggggg': + Check('TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT', '=', True), + 'hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh': + Check('SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS', '=', True), + 'iiiiiiiiiiiiiiiiiiiiiiii': + Check('RRRRRRRRRRRRRRRRRRRRRRRRRRR', '=', True), + 'jjjjjjjjjjjjjjjjjjjjjjjjjj': + Check('QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ', '=', False), + } + """) + expected_formatted_code = textwrap.dedent("""\ + a = { + 'aaaaaaaaaaaaaaaaaaaaaaaa': + Check('ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ', '=', True), + 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb': + Check('YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY', '=', True), + 'ccccccccccccccc': + Check('XXXXXXXXXXXXXXXXXXX', '!=', 'SUSPENDED'), + 'dddddddddddddddddddddddddddddd': + Check('WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW', '=', False), + 'eeeeeeeeeeeeeeeeeeeeeeeeeeeee': + Check('VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV', '=', False), + 'ffffffffffffffffffffffffff': + Check('UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU', '=', True), + 'ggggggggggggggggg': + Check('TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT', '=', True), + 'hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh': + Check('SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS', '=', True), + 'iiiiiiiiiiiiiiiiiiiiiiii': + Check('RRRRRRRRRRRRRRRRRRRRRRRRRRR', '=', True), + 'jjjjjjjjjjjjjjjjjjjjjjjjjj': + Check('QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ', '=', False), + } + """) + uwlines = _ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + class BuganizerFixes(ReformatterTest): @@ -2115,7 +2168,8 @@ def testB25131481(self): { 'materialize': lambda x: some_type_of_function('materialize ' + x.command_def), - '#': lambda x: x # do nothing + '#': + lambda x: x # do nothing }) """) uwlines = _ParseAndUnwrap(unformatted_code) @@ -2371,7 +2425,8 @@ def testB20605036(self): foo = { 'aaaa': { # A comment for no particular reason. - 'xxxxxxxx': 'bbbbbbbbb', + 'xxxxxxxx': + 'bbbbbbbbb', 'yyyyyyyyyyyyyyyyyy': 'cccccccccccccccccccccccccccccc' 'dddddddddddddddddddddddddddddddddddddddddd', @@ -2397,8 +2452,10 @@ def testB20128830(self): code = textwrap.dedent("""\ a = { 'xxxxxxxxxxxxxxxxxxxx': { - 'aaaa': 'mmmmmmm', - 'bbbbb': 'mmmmmmmmmmmmmmmmmmmmm', + 'aaaa': + 'mmmmmmm', + 'bbbbb': + 'mmmmmmmmmmmmmmmmmmmmm', 'cccccccccc': [ 'nnnnnnnnnnn', 'ooooooooooo', From b5d8a0e7d2a2192915dfc03371b41196ba85889a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 2 Oct 2016 00:05:18 -0700 Subject: [PATCH 028/719] Bump version to v0.12.1 --- yapf/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 287bd5ad4..9fad86d13 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.12.0' +__version__ = '0.12.1' def main(argv): From 5de98046502a43489d97b41f783bb1a435415408 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 2 Oct 2016 00:20:35 -0700 Subject: [PATCH 029/719] Remove dead code. --- yapf/yapflib/format_decision_state.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 9a7e26ad5..58019f9f4 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -547,18 +547,6 @@ def _GetOpeningBracket(current): current = current.previous_token return None - previous = current - if previous and previous.matching_bracket and not previous.is_pseudo_paren: - return previous.matching_bracket - previous = previous.previous_token - while previous and not previous.matching_bracket: - previous = previous.previous_token - if not previous: - break - if previous.ClosesScope(): - previous = previous.matching_bracket.previous_token - return previous - def _LastTokenInLine(current): while not current.is_comment and current.next_token: From e543f26c178b1eb0c49c5a8e1c3061e05ff231e6 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 2 Oct 2016 01:01:48 -0700 Subject: [PATCH 030/719] Add docstring and remove unused var --- yapf/yapflib/format_decision_state.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 58019f9f4..232641c31 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -501,8 +501,9 @@ def _FitsOnLine(self, start, end): return length + self.column < self.column_limit def _AllDictElementsFitOnOneLine(self, opening): + """Determine if all dict elems can fit on one line.""" closing = opening.matching_bracket - current, previous = opening.next_token, opening + current = opening.next_token start = None while current and current != closing: if format_token.Subtype.DICTIONARY_KEY in current.subtypes: From 086531ef6f594eb3c4cb32bb7a2d59167502644a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 2 Oct 2016 16:46:11 -0700 Subject: [PATCH 031/719] Set the default factory when setting the global style Closes #308 --- CHANGELOG | 10 +++++++- yapf/yapflib/file_resources.py | 2 +- yapf/yapflib/style.py | 45 +++++++++++++++++++++++++--------- yapftests/__init__.py | 14 ++++++++++- yapftests/reformatter_test.py | 34 +++++++++++++++++++++++++ 5 files changed, 90 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f4c9f3dc4..1da11fbb8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,15 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.12.1] UNRELEASED +## [0.12.2] UNRELEASED +### Fixed +- If `style.SetGlobalStyle()` was called and then + `yapf_api.FormatCode` was called, the style set by the first call would be + lost, because it would return the style created by `DEFAULT_STYLE_FACTORY`, + which is set to PEP8 by default. Fix this by making the first call set which + factory we call as the "default" style. + +## [0.12.1] 2016-10-02 ### Changed - Dictionary values will be placed on the same line as the key if *all* of the elements in the dictionary can be placed on one line. Otherwise, the diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index eee93ea20..fd164c292 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -37,7 +37,7 @@ def GetDefaultStyleForDir(dirname): dirname: (unicode) The name of the directory. Returns: - The filename if found, otherwise return the glboal default (pep8). + The filename if found, otherwise return the global default (pep8). """ dirname = os.path.abspath(dirname) while True: diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 07e369c91..558659e84 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -39,6 +39,9 @@ def Help(): def SetGlobalStyle(style): """Set a style dict.""" global _style + factory = _GetStyleFactory(style) + if factory: + _GLOBAL_STYLE_FACTORY = factory _style = style @@ -204,8 +207,8 @@ def CreatePEP8Style(): SPLIT_PENALTY_AFTER_OPENING_BRACKET=30, SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=30, SPLIT_PENALTY_BEFORE_IF_EXPR=0, - USE_TABS=False - ) # yapf: disable + USE_TABS=False, + ) def CreateGoogleStyle(): @@ -248,7 +251,21 @@ def CreateFacebookStyle(): chromium=CreateChromiumStyle, google=CreateGoogleStyle, facebook=CreateFacebookStyle, -) # yapf: disable +) + +_DEFAULT_STYLE_TO_FACTORY = [ + (CreateChromiumStyle(), CreateChromiumStyle), + (CreateFacebookStyle(), CreateFacebookStyle), + (CreateGoogleStyle(), CreateGoogleStyle), + (CreatePEP8Style(), CreatePEP8Style), +] + + +def _GetStyleFactory(style): + for def_style, factory in _DEFAULT_STYLE_TO_FACTORY: + if style == def_style: + return factory + return None def _StringListConverter(s): @@ -297,8 +314,8 @@ def _BoolConverter(s): SPLIT_PENALTY_AFTER_OPENING_BRACKET=int, SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=int, SPLIT_PENALTY_BEFORE_IF_EXPR=int, - USE_TABS=_BoolConverter -) # yapf: disable + USE_TABS=_BoolConverter, +) def CreateStyleFromConfig(style_config): @@ -308,7 +325,7 @@ def CreateStyleFromConfig(style_config): style_config: either a style name or a file name. The file is expected to contain settings. It can have a special BASED_ON_STYLE setting naming the style which it derives from. If no such setting is found, it derives from - the default style. When style_config is None, the DEFAULT_STYLE_FACTORY + the default style. When style_config is None, the _GLOBAL_STYLE_FACTORY config is created. Returns: @@ -317,17 +334,20 @@ def CreateStyleFromConfig(style_config): Raises: StyleConfigError: if an unknown style option was encountered. """ - styles = (CreatePEP8Style(), CreateGoogleStyle(), CreateFacebookStyle(), - CreateChromiumStyle()) + + def GlobalStyles(): + for style, _ in _DEFAULT_STYLE_TO_FACTORY: + yield style + def_style = False if style_config is None: - for style in styles: + for style in GlobalStyles(): if _style == style: def_style = True break if not def_style: return _style - return DEFAULT_STYLE_FACTORY() + return _GLOBAL_STYLE_FACTORY() style_factory = _STYLE_NAME_TO_FACTORY.get(style_config.lower()) if style_factory is not None: return style_factory() @@ -398,7 +418,7 @@ def _CreateStyleFromConfigParser(config): based_on = config.get('yapf', 'based_on_style').lower() base_style = _STYLE_NAME_TO_FACTORY[based_on]() else: - base_style = DEFAULT_STYLE_FACTORY() + base_style = _GLOBAL_STYLE_FACTORY() # Read all options specified in the file and update the style. for option, value in config.items(section): @@ -420,6 +440,7 @@ def _CreateStyleFromConfigParser(config): # requesting a formatting style. DEFAULT_STYLE = 'pep8' DEFAULT_STYLE_FACTORY = CreatePEP8Style +_GLOBAL_STYLE_FACTORY = CreatePEP8Style # The name of the file to use for global style definition. GLOBAL_STYLE = (os.path.join( @@ -437,4 +458,4 @@ def _CreateStyleFromConfigParser(config): # Refactor this so that the style is passed around through yapf rather than # being global. _style = None -SetGlobalStyle(DEFAULT_STYLE_FACTORY()) +SetGlobalStyle(_GLOBAL_STYLE_FACTORY()) diff --git a/yapftests/__init__.py b/yapftests/__init__.py index 8b1378917..67076fe58 100644 --- a/yapftests/__init__.py +++ b/yapftests/__init__.py @@ -1 +1,13 @@ - +# Copyright 2015-2016 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index 91f42fbcc..020de7425 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -2968,6 +2968,40 @@ def testB13900309(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) +class TestsForStyleConfig(ReformatterTest): + + def setUp(self): + self.current_style = style.DEFAULT_STYLE + + def testSetGlobalStyle(self): + try: + style.SetGlobalStyle(style.CreateChromiumStyle()) + unformatted_code = textwrap.dedent(u"""\ + for i in range(5): + print('bar') + """) + expected_formatted_code = textwrap.dedent(u"""\ + for i in range(5): + print('bar') + """) + uwlines = _ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreatePEP8Style()) + style.DEFAULT_STYLE = self.current_style + + unformatted_code = textwrap.dedent(u"""\ + for i in range(5): + print('bar') + """) + expected_formatted_code = textwrap.dedent(u"""\ + for i in range(5): + print('bar') + """) + uwlines = _ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + class TestsForPEP8Style(ReformatterTest): @classmethod From dfd2f1802d7ea7abedeae98a927ac09ffdee3312 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 3 Oct 2016 20:30:43 -0700 Subject: [PATCH 032/719] Don't force a split before non-function call arguments --- CHANGELOG | 1 + yapf/yapflib/format_decision_state.py | 34 +++++++++++++-------------- yapftests/reformatter_test.py | 18 +++++++++++++- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1da11fbb8..0732660c5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,7 @@ lost, because it would return the style created by `DEFAULT_STYLE_FACTORY`, which is set to PEP8 by default. Fix this by making the first call set which factory we call as the "default" style. +- Don't force a split before non-function call arguments. ## [0.12.1] 2016-10-02 ### Changed diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 232641c31..286954743 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -269,26 +269,26 @@ def MustSplit(self): # original comments were on a separate line. return True - opening = _GetOpeningBracket(current) - if (opening and opening.value == '(' and current.is_name and - previous.value == ','): + if current.is_name and previous.value == ',': # If we have a function call within an argument list and it won't fit on # the remaining line, but it will fit on a line by itself, then go ahead # and split before the call. - total_len = 0 - ntoken = current - while ntoken: - if ntoken.value == '(': - total_len = ( - ntoken.matching_bracket.total_length - current.total_length) - break - ntoken = ntoken.next_token - - if ntoken: - indent_amt = self.stack[-1].indent * style.Get('INDENT_WIDTH') - if (total_len + indent_amt < self.column_limit and - total_len + self.column >= self.column_limit): - return True + opening = _GetOpeningBracket(current) + if (opening and opening.value == '(' and opening.previous_token and + opening.previous_token.is_name): + is_func_call = False + token = current + while token: + if token.value == '(': + is_func_call = True + break + if not token.is_name and token.value != '.': + break + token = token.next_token + + if is_func_call: + if not self._FitsOnLine(current, opening.matching_bracket): + return True return False diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index 020de7425..5a7d983ff 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -1054,7 +1054,8 @@ def b(self): def testTrailerOnSingleLine(self): code = textwrap.dedent("""\ - urlpatterns = patterns('', url(r'^$', 'homepage_view'), + urlpatterns = patterns('', + url(r'^$', 'homepage_view'), url(r'^/login/$', 'login_view'), url(r'^/login/$', 'logout_view'), url(r'^/user/(?P\\w+)/$', 'profile_view')) @@ -1826,6 +1827,21 @@ class BuganizerFixes(ReformatterTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB31911533(self): + code = textwrap.dedent("""\ + class _(): + + @parameterized.NamedParameters( + ('IncludingModInfoWithHeaderList', AAAA, aaaa), + ('IncludingModInfoWithoutHeaderList', BBBB, bbbbb), + ('ExcludingModInfoWithHeaderList', CCCCC, cccc), + ('ExcludingModInfoWithoutHeaderList', DDDDD, ddddd),) + def _(): + pass + """) + uwlines = _ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB31847238(self): unformatted_code = textwrap.dedent("""\ class _(): From bd461a4b1871d87ac1d256af669e431ce40fddf0 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 3 Oct 2016 20:58:08 -0700 Subject: [PATCH 033/719] Don't split a dict arg if it fits on the line --- CHANGELOG | 2 ++ setup.py | 8 ++----- yapf/yapflib/format_decision_state.py | 7 ++++++ yapf/yapflib/reformatter.py | 4 ++-- yapf/yapflib/style.py | 9 +++---- yapftests/reformatter_test.py | 34 ++++++++++++++++++++++++++- 6 files changed, 49 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0732660c5..c4f37b71c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,8 @@ which is set to PEP8 by default. Fix this by making the first call set which factory we call as the "default" style. - Don't force a split before non-function call arguments. +- A dictionary being used as an argument to a function call and which can exist + on a single line shouldn't be split. ## [0.12.1] 2016-10-02 ### Changed diff --git a/setup.py b/setup.py index c1a4e8344..59042c009 100644 --- a/setup.py +++ b/setup.py @@ -64,9 +64,5 @@ def run(self): 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Quality Assurance', ], - entry_points={ - 'console_scripts': ['yapf = yapf:run_main'], - }, - cmdclass={ - 'test': RunTests, - },) + entry_points={'console_scripts': ['yapf = yapf:run_main'],}, + cmdclass={'test': RunTests,},) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 286954743..406a0672d 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -161,6 +161,13 @@ def MustSplit(self): if (format_token.Subtype.DICTIONARY_KEY in current.subtypes and not current.is_comment): # Place each dictionary entry on its own line. + if previous.value == '{' and previous.previous_token: + opening = _GetOpeningBracket(previous.previous_token) + if (opening and opening.value == '(' and opening.previous_token and + opening.previous_token.is_name): + # This is a dictionary that's an argument to a function. + if self._FitsOnLine(previous, previous.matching_bracket): + return False return True # TODO(morbo): This should be controlled with a knob. diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 5fa85c320..341ecece9 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -219,8 +219,8 @@ def _CanPlaceOnSingleLine(uwline): indent_amt = style.Get('INDENT_WIDTH') * uwline.depth last = uwline.last last_index = -1 - if last.is_comment and re.search(r'^#+\s+pylint:', last.value.strip(), - re.IGNORECASE): + if last.is_comment and re.search(r'^#+\s+pylint:', + last.value.strip(), re.IGNORECASE): last = last.previous_token last_index = -2 if last is None: diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 558659e84..ca744639b 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -207,8 +207,7 @@ def CreatePEP8Style(): SPLIT_PENALTY_AFTER_OPENING_BRACKET=30, SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=30, SPLIT_PENALTY_BEFORE_IF_EXPR=0, - USE_TABS=False, - ) + USE_TABS=False,) def CreateGoogleStyle(): @@ -250,8 +249,7 @@ def CreateFacebookStyle(): pep8=CreatePEP8Style, chromium=CreateChromiumStyle, google=CreateGoogleStyle, - facebook=CreateFacebookStyle, -) + facebook=CreateFacebookStyle,) _DEFAULT_STYLE_TO_FACTORY = [ (CreateChromiumStyle(), CreateChromiumStyle), @@ -314,8 +312,7 @@ def _BoolConverter(s): SPLIT_PENALTY_AFTER_OPENING_BRACKET=int, SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=int, SPLIT_PENALTY_BEFORE_IF_EXPR=int, - USE_TABS=_BoolConverter, -) + USE_TABS=_BoolConverter,) def CreateStyleFromConfig(style_config): diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index 5a7d983ff..4d2db263b 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -1820,6 +1820,37 @@ def testDictionaryValuesOnOwnLines(self): uwlines = _ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testDictionaryOnOwnLine(self): + unformatted_code = textwrap.dedent("""\ + doc = test_utils.CreateTestDocumentViaController( + content={ 'a': 'b' }, + branch_key=branch.key, + collection_key=collection.key) + """) + expected_formatted_code = textwrap.dedent("""\ + doc = test_utils.CreateTestDocumentViaController( + content={'a': 'b'}, branch_key=branch.key, collection_key=collection.key) + """) + uwlines = _ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + unformatted_code = textwrap.dedent("""\ + doc = test_utils.CreateTestDocumentViaController( + content={ 'a': 'b' }, + branch_key=branch.key, + collection_key=collection.key, + collection_key2=collection.key2) + """) + expected_formatted_code = textwrap.dedent("""\ + doc = test_utils.CreateTestDocumentViaController( + content={'a': 'b'}, + branch_key=branch.key, + collection_key=collection.key, + collection_key2=collection.key2) + """) + uwlines = _ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + class BuganizerFixes(ReformatterTest): @@ -3001,7 +3032,8 @@ def testSetGlobalStyle(self): print('bar') """) uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) style.DEFAULT_STYLE = self.current_style From aa2f5935c3dc37dbabc559f6cd4d6813f407b07c Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 3 Oct 2016 22:33:34 -0700 Subject: [PATCH 034/719] Split containers without relying on orig format --- CHANGELOG | 2 + yapf/yapflib/format_decision_state.py | 25 ++++++- yapftests/reformatter_test.py | 100 +++++++++++++------------- 3 files changed, 73 insertions(+), 54 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c4f37b71c..b1b54c682 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,8 @@ - Don't force a split before non-function call arguments. - A dictionary being used as an argument to a function call and which can exist on a single line shouldn't be split. +- Don't rely upon the original line break to determine if we should split + before the elements in a container. ## [0.12.1] 2016-10-02 ### Changed diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 406a0672d..95d900f01 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -219,10 +219,29 @@ def MustSplit(self): if not self._AllDictElementsFitOnOneLine(opening): return True - if (previous.value in '{[' and current.lineno != previous.lineno and + if (previous.OpensScope() and not current.OpensScope() and format_token.Subtype.SUBSCRIPT_BRACKET not in previous.subtypes): - # Retain the split after the container opening. - return True + if previous.value == '(': + pptoken = previous.previous_token + if not pptoken or not pptoken.is_name: + # Split after the opening of a tuple if it doesn't fit on the current + # line and it's not a function call. + if self._FitsOnLine(previous, previous.matching_bracket): + return False + else: + # Split after the opening of a container if it doesn't fit on the + # current line or if it has a comment. + if not self._FitsOnLine(previous, previous.matching_bracket): + return True + if not current.is_comment: + contains_comments = False + token = previous + while token != previous.matching_bracket: + if token.is_comment: + contains_comments = True + break + token = token.next_token + return contains_comments if previous.value == '{': closing = previous.matching_bracket diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index 4d2db263b..dd4f50f63 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -951,35 +951,38 @@ def testSplitListWithTerminatingComma(self): 'quuuuux', 'quuuuuux', 'quuuuuuux', lambda a, b: 37,] """) expected_formatted_code = textwrap.dedent("""\ - FOO = ['bar', - 'baz', - 'mux', - 'qux', - 'quux', - 'quuux', - 'quuuux', - 'quuuuux', - 'quuuuuux', - 'quuuuuuux', - lambda a, b: 37,] + FOO = [ + 'bar', + 'baz', + 'mux', + 'qux', + 'quux', + 'quuux', + 'quuuux', + 'quuuuux', + 'quuuuuux', + 'quuuuuuux', + lambda a, b: 37, + ] """) uwlines = _ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSplitListWithInterspersedComments(self): code = textwrap.dedent("""\ - FOO = ['bar', # bar - 'baz', # baz - 'mux', # mux - 'qux', # qux - 'quux', # quux - 'quuux', # quuux - 'quuuux', # quuuux - 'quuuuux', # quuuuux - 'quuuuuux', # quuuuuux - 'quuuuuuux', # quuuuuuux - lambda a, b: 37 # lambda - ] + FOO = [ + 'bar', # bar + 'baz', # baz + 'mux', # mux + 'qux', # qux + 'quux', # quux + 'quuux', # quuux + 'quuuux', # quuuux + 'quuuuux', # quuuuux + 'quuuuuux', # quuuuuux + 'quuuuuuux', # quuuuuuux + lambda a, b: 37 # lambda + ] """) uwlines = _ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1190,8 +1193,9 @@ def testExcessCharacters(self): class foo: def bar(self): - self.write(s=['%s%s %s' % ('many of really', 'long strings', - '+ just makes up 81')]) + self.write(s=[ + '%s%s %s' % ('many of really', 'long strings', '+ just makes up 81') + ]) """) uwlines = _ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1554,15 +1558,13 @@ def testStableDictionaryFormatting(self): class A(object): def method(self): filters = { - 'expressions': [ - { - 'field': { - 'search_field': { - 'user_field': 'latest_party__number_of_guests' - }, - } + 'expressions': [{ + 'field': { + 'search_field': { + 'user_field': 'latest_party__number_of_guests' + }, } - ] + }] } """) uwlines = _ParseAndUnwrap(code) @@ -1600,8 +1602,9 @@ def a(): if True: if True: if True: - columns = [x for x, y in self._heap_this_is_very_long - if x.route[0] == choice] + columns = [ + x for x, y in self._heap_this_is_very_long if x.route[0] == choice + ] self._heap = [x for x in self._heap if x.route and x.route[0] == choice] """) uwlines = _ParseAndUnwrap(code) @@ -2132,12 +2135,10 @@ def testB25505359(self): _EXAMPLE = { 'aaaaaaaaaaaaaa': [{ 'bbbb': 'cccccccccccccccccccccc', - 'dddddddddddd': [ - ] + 'dddddddddddd': [] }, { 'bbbb': 'ccccccccccccccccccc', - 'dddddddddddd': [ - ] + 'dddddddddddd': [] }] } """) @@ -2536,9 +2537,7 @@ def testB19626808(self): code = textwrap.dedent("""\ if True: aaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbb( - 'ccccccccccc', ddddddddd='eeeee').fffffffff([ - ggggggggggggggggggggg - ]) + 'ccccccccccc', ddddddddd='eeeee').fffffffff([ggggggggggggggggggggg]) """) uwlines = _ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -2628,9 +2627,10 @@ def testB19073499(self): code = textwrap.dedent("""\ instance = (aaaaaaa.bbbbbbb().ccccccccccccccccc().ddddddddddd({ 'aa': 'context!' - }).eeeeeeeeeeeeeeeeeee({ # Inline comment about why fnord has the value 6. - 'fnord': 6 - })) + }).eeeeeeeeeeeeeeeeeee( + { # Inline comment about why fnord has the value 6. + 'fnord': 6 + })) """) uwlines = _ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -3901,12 +3901,10 @@ def testDedentSet(self): class _(): def _(): assert set(self.constraint_links.get_links()) == set( - [ - (2, 10, 100), - (2, 10, 200), - (2, 20, 100), - (2, 20, 200), - ] + [(2, 10, 100), + (2, 10, 200), + (2, 20, 100), + (2, 20, 200), ] ) """) uwlines = _ParseAndUnwrap(unformatted_code) From b10276d71958d56a8ae88b9a6a4ef1c8746033a6 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 3 Oct 2016 22:49:52 -0700 Subject: [PATCH 035/719] Split container elems if there's a comment --- CHANGELOG | 3 +- yapf/yapflib/format_decision_state.py | 20 +++--- yapftests/reformatter_test.py | 89 ++++++++++++++++++++++++--- 3 files changed, 92 insertions(+), 20 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b1b54c682..692937036 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,7 +13,8 @@ - A dictionary being used as an argument to a function call and which can exist on a single line shouldn't be split. - Don't rely upon the original line break to determine if we should split - before the elements in a container. + before the elements in a container. Especially split if there's a comment in + the container. ## [0.12.1] 2016-10-02 ### Changed diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 95d900f01..cecd08f5e 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -221,6 +221,17 @@ def MustSplit(self): if (previous.OpensScope() and not current.OpensScope() and format_token.Subtype.SUBSCRIPT_BRACKET not in previous.subtypes): + + if not current.is_comment: + pprevious = previous.previous_token + if pprevious and not pprevious.is_keyword and not pprevious.is_name: + # We want to split if there's a comment in the container. + token = current + while token != previous.matching_bracket: + if token.is_comment: + return True + token = token.next_token + if previous.value == '(': pptoken = previous.previous_token if not pptoken or not pptoken.is_name: @@ -233,15 +244,6 @@ def MustSplit(self): # current line or if it has a comment. if not self._FitsOnLine(previous, previous.matching_bracket): return True - if not current.is_comment: - contains_comments = False - token = previous - while token != previous.matching_bracket: - if token.is_comment: - contains_comments = True - break - token = token.next_token - return contains_comments if previous.value == '{': closing = previous.matching_bracket diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index dd4f50f63..564f8301a 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -1854,6 +1854,73 @@ def testDictionaryOnOwnLine(self): uwlines = _ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testDictionaryOnOwnLine(self): + unformatted_code = textwrap.dedent("""\ + _A = { + 'cccccccccc': ('^^1',), + 'rrrrrrrrrrrrrrrrrrrrrrrrr': ('^7913', # AAAAAAAAAAAAAA. + ), + 'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee': ('^6242', # BBBBBBBBBBBBBBB. + ), + 'vvvvvvvvvvvvvvvvvvv': ('^27959', # CCCCCCCCCCCCCCCCCC. + '^19746', # DDDDDDDDDDDDDDDDDDDDDDD. + '^22907', # EEEEEEEEEEEEEEEEEEEEEEEE. + '^21098', # FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF. + '^22826', # GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG. + '^22769', # HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH. + '^22935', # IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII. + '^3982', # JJJJJJJJJJJJJ. + ), + 'uuuuuuuuuuuu': ('^19745', # LLLLLLLLLLLLLLLLLLLLLLLLLL. + '^21324', # MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM. + '^22831', # NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN. + '^17081', # OOOOOOOOOOOOOOOOOOOOO. + ), + 'eeeeeeeeeeeeee': ( + '^9416', # Reporter email. Not necessarily the reporter. + '^^3', # This appears to be the raw email field. + ), + 'cccccccccc': ('^21109', # PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP. + ), + } + """) + expected_formatted_code = textwrap.dedent("""\ + _A = { + 'cccccccccc': ('^^1',), + 'rrrrrrrrrrrrrrrrrrrrrrrrr': ( + '^7913', # AAAAAAAAAAAAAA. + ), + 'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee': ( + '^6242', # BBBBBBBBBBBBBBB. + ), + 'vvvvvvvvvvvvvvvvvvv': ( + '^27959', # CCCCCCCCCCCCCCCCCC. + '^19746', # DDDDDDDDDDDDDDDDDDDDDDD. + '^22907', # EEEEEEEEEEEEEEEEEEEEEEEE. + '^21098', # FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF. + '^22826', # GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG. + '^22769', # HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH. + '^22935', # IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII. + '^3982', # JJJJJJJJJJJJJ. + ), + 'uuuuuuuuuuuu': ( + '^19745', # LLLLLLLLLLLLLLLLLLLLLLLLLL. + '^21324', # MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM. + '^22831', # NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN. + '^17081', # OOOOOOOOOOOOOOOOOOOOO. + ), + 'eeeeeeeeeeeeee': ( + '^9416', # Reporter email. Not necessarily the reporter. + '^^3', # This appears to be the raw email field. + ), + 'cccccccccc': ( + '^21109', # PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP. + ), + } + """) + uwlines = _ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + class BuganizerFixes(ReformatterTest): @@ -2625,12 +2692,13 @@ def testB19194420(self): def testB19073499(self): code = textwrap.dedent("""\ - instance = (aaaaaaa.bbbbbbb().ccccccccccccccccc().ddddddddddd({ - 'aa': 'context!' - }).eeeeeeeeeeeeeeeeeee( - { # Inline comment about why fnord has the value 6. - 'fnord': 6 - })) + instance = ( + aaaaaaa.bbbbbbb().ccccccccccccccccc().ddddddddddd({ + 'aa': 'context!' + }).eeeeeeeeeeeeeeeeeee( + { # Inline comment about why fnord has the value 6. + 'fnord': 6 + })) """) uwlines = _ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -3175,10 +3243,11 @@ def testAlignClosingBracketWithVisualIndentation(self): ) """) expected_formatted_code = textwrap.dedent("""\ - TEST_LIST = ('foo', - 'bar', # first comment - 'baz' # second comment - ) + TEST_LIST = ( + 'foo', + 'bar', # first comment + 'baz' # second comment + ) """) uwlines = _ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) From ffc1cd007379bebd8b77d87f009bd94e3e3afc74 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 4 Oct 2016 22:55:47 -0700 Subject: [PATCH 036/719] No spaces between a star and args in a lambda expr --- CHANGELOG | 1 + yapf/yapflib/subtype_assigner.py | 1 + yapftests/reformatter_test.py | 10 ++++++++++ 3 files changed, 12 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 692937036..602c0fa8e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -15,6 +15,7 @@ - Don't rely upon the original line break to determine if we should split before the elements in a container. Especially split if there's a comment in the container. +- Don't add spaces between star and args in a lambda expression. ## [0.12.1] 2016-10-02 ### Changed diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index b99e0d69f..d8e886fd8 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -261,6 +261,7 @@ def Visit_varargslist(self, node): # pylint: disable=invalid-name # ('*' [vname] (',' vname ['=' test])* [',' '**' vname] # | '**' vname) # | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) + self._ProcessArgLists(node) for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == '=': diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index 564f8301a..b1a62f9e7 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -1928,6 +1928,16 @@ class BuganizerFixes(ReformatterTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB31937033(self): + code = textwrap.dedent("""\ + class _(): + + def __init__(self, metric, fields_cb=None): + self._fields_cb = fields_cb or (lambda *unused_args, **unused_kwargs: {}) + """) + uwlines = _ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB31911533(self): code = textwrap.dedent("""\ class _(): From 6df903cc5776be02836ec2ba2dbe8fe5a1cc7e92 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 5 Oct 2016 00:34:25 -0700 Subject: [PATCH 037/719] Split before first elem in list If the list terminates with a comma, then we want to split before all elements including the first element, assuming that there's more than one element in the lsit. Closes #313 --- CHANGELOG | 2 + yapf/yapflib/comment_splicer.py | 8 ++-- yapf/yapflib/file_resources.py | 6 ++- yapf/yapflib/format_decision_state.py | 4 +- yapf/yapflib/pytree_unwrapper.py | 10 ++++- yapf/yapflib/reformatter.py | 4 +- yapf/yapflib/style.py | 1 + yapf/yapflib/unwrapped_line.py | 4 +- yapftests/file_resources_test.py | 20 ++++++---- yapftests/format_decision_state_test.py | 6 ++- yapftests/pytree_unwrapper_test.py | 6 ++- yapftests/pytree_utils_test.py | 4 +- yapftests/reformatter_test.py | 52 +++++++++++++++++++++---- yapftests/unwrapped_line_test.py | 13 ++++--- yapftests/yapf_test.py | 2 +- 15 files changed, 100 insertions(+), 42 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 602c0fa8e..57e40d01e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,8 @@ before the elements in a container. Especially split if there's a comment in the container. - Don't add spaces between star and args in a lambda expression. +- If a nested data structure terminates in a comma, then split before the first + element, but only if there's more than one element in the list. ## [0.12.1] 2016-10-02 ### Changed diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index d7c9536c1..8c4feaf24 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -260,10 +260,10 @@ def _CreateCommentsFromPrefix(comment_prefix, # line, not on the same line with other code), it's important to insert it into # an appropriate parent of the node it's attached to. An appropriate parent # is the first "standaline line node" in the parent chain of a node. -_STANDALONE_LINE_NODES = frozenset(['suite', 'if_stmt', 'while_stmt', - 'for_stmt', 'try_stmt', 'with_stmt', - 'funcdef', 'classdef', 'decorated', - 'file_input']) +_STANDALONE_LINE_NODES = frozenset([ + 'suite', 'if_stmt', 'while_stmt', 'for_stmt', 'try_stmt', 'with_stmt', + 'funcdef', 'classdef', 'decorated', 'file_input' +]) def _FindNodeWithStandaloneLineParent(node): diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index fd164c292..a49233f31 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -110,8 +110,10 @@ def _FindPythonFiles(filenames, recursive, exclude): python_files.append(filename) if exclude: - return [f for f in python_files - if not any(fnmatch.fnmatch(f, p) for p in exclude)] + return [ + f for f in python_files + if not any(fnmatch.fnmatch(f, p) for p in exclude) + ] return python_files diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index cecd08f5e..618d904cb 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -33,8 +33,8 @@ from yapf.yapflib import style from yapf.yapflib import unwrapped_line -_COMPOUND_STMTS = frozenset({'for', 'while', 'if', 'elif', 'with', 'except', - 'def', 'class'}) +_COMPOUND_STMTS = frozenset( + {'for', 'while', 'if', 'elif', 'with', 'except', 'def', 'class'}) class FormatDecisionState(object): diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index ebfe8d1bf..4d17f027c 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -53,8 +53,10 @@ def UnwrapPyTree(tree): return uwlines # Grammar tokens considered as whitespace for the purpose of unwrapping. -_WHITESPACE_TOKENS = frozenset([grammar_token.NEWLINE, grammar_token.DEDENT, - grammar_token.INDENT, grammar_token.ENDMARKER]) +_WHITESPACE_TOKENS = frozenset([ + grammar_token.NEWLINE, grammar_token.DEDENT, grammar_token.INDENT, + grammar_token.ENDMARKER +]) class PyTreeUnwrapper(pytree_visitor.PyTreeVisitor): @@ -332,11 +334,15 @@ def _AdjustSplitPenalty(uwline): def _DetermineMustSplitAnnotation(node): """Enforce a split in the list if the list ends with a comma.""" if not _ContainsComments(node): + if sum(1 for ch in node.children + if pytree_utils.NodeName(ch) == 'COMMA') < 2: + return if (not isinstance(node.children[-1], pytree.Leaf) or node.children[-1].value != ','): return num_children = len(node.children) index = 0 + _SetMustSplitOnFirstLeaf(node.children[0]) while index < num_children - 1: child = node.children[index] if isinstance(child, pytree.Leaf) and child.value == ',': diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 341ecece9..d7a52e723 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -281,8 +281,8 @@ def __repr__(self): # pragma: no cover # An item in the prioritized BFS search queue. The 'StateNode's 'state' has # the given '_OrderedPenalty'. -_QueueItem = collections.namedtuple('QueueItem', ['ordered_penalty', - 'state_node']) +_QueueItem = collections.namedtuple('QueueItem', + ['ordered_penalty', 'state_node']) def _AnalyzeSolutionSpace(initial_state): diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index ca744639b..4da837d1e 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -39,6 +39,7 @@ def Help(): def SetGlobalStyle(style): """Set a style dict.""" global _style + global _GLOBAL_STYLE_FACTORY factory = _GetStyleFactory(style) if factory: _GLOBAL_STYLE_FACTORY = factory diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index d8a9b0f97..25892db28 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -143,8 +143,8 @@ def __str__(self): # pragma: no cover return self.AsCode() def __repr__(self): # pragma: no cover - tokens_repr = ','.join(['{0}({1!r})'.format(tok.name, tok.value) - for tok in self._tokens]) + tokens_repr = ','.join( + ['{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens]) return 'UnwrappedLine(depth={0}, tokens=[{1}])'.format(self.depth, tokens_repr) diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 0f2cfd013..9987a6c1a 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -113,9 +113,10 @@ def test_recursive_find_in_dir(self): tdir1 = self._make_test_dir('test1') tdir2 = self._make_test_dir('test2/testinner/') tdir3 = self._make_test_dir('test3/foo/bar/bas/xxx') - files = [os.path.join(tdir1, 'testfile1.py'), - os.path.join(tdir2, 'testfile2.py'), - os.path.join(tdir3, 'testfile3.py')] + files = [ + os.path.join(tdir1, 'testfile1.py'), + os.path.join(tdir2, 'testfile2.py'), os.path.join(tdir3, 'testfile3.py') + ] _touch_files(files) self.assertEqual( @@ -128,17 +129,20 @@ def test_recursive_find_in_dir_with_exclude(self): tdir1 = self._make_test_dir('test1') tdir2 = self._make_test_dir('test2/testinner/') tdir3 = self._make_test_dir('test3/foo/bar/bas/xxx') - files = [os.path.join(tdir1, 'testfile1.py'), - os.path.join(tdir2, 'testfile2.py'), - os.path.join(tdir3, 'testfile3.py')] + files = [ + os.path.join(tdir1, 'testfile1.py'), + os.path.join(tdir2, 'testfile2.py'), os.path.join(tdir3, 'testfile3.py') + ] _touch_files(files) self.assertEqual( sorted( file_resources.GetCommandLineFiles( [self.test_tmpdir], recursive=True, exclude=['*test*3.py'])), - sorted([os.path.join(tdir1, 'testfile1.py'), - os.path.join(tdir2, 'testfile2.py')])) + sorted([ + os.path.join(tdir1, 'testfile1.py'), + os.path.join(tdir2, 'testfile2.py') + ])) class IsPythonFileTest(unittest.TestCase): diff --git a/yapftests/format_decision_state_test.py b/yapftests/format_decision_state_test.py index bbdf2a168..755207a31 100644 --- a/yapftests/format_decision_state_test.py +++ b/yapftests/format_decision_state_test.py @@ -55,8 +55,10 @@ def _ParseAndUnwrap(self, code, dumptree=False): def _FilterLine(self, uwline): """Filter out nonsemantic tokens from the UnwrappedLines.""" - return [ft for ft in uwline.tokens - if ft.name not in pytree_utils.NONSEMANTIC_TOKENS] + return [ + ft for ft in uwline.tokens + if ft.name not in pytree_utils.NONSEMANTIC_TOKENS + ] def testSimpleFunctionDefWithNoSplitting(self): code = textwrap.dedent(r""" diff --git a/yapftests/pytree_unwrapper_test.py b/yapftests/pytree_unwrapper_test.py index 057e03753..7d9806716 100644 --- a/yapftests/pytree_unwrapper_test.py +++ b/yapftests/pytree_unwrapper_test.py @@ -57,8 +57,10 @@ def _CheckUnwrappedLines(self, uwlines, list_of_expected): """ actual = [] for uwl in uwlines: - filtered_values = [ft.value for ft in uwl.tokens - if ft.name not in pytree_utils.NONSEMANTIC_TOKENS] + filtered_values = [ + ft.value for ft in uwl.tokens + if ft.name not in pytree_utils.NONSEMANTIC_TOKENS + ] actual.append((uwl.depth, filtered_values)) self.assertEqual(list_of_expected, actual) diff --git a/yapftests/pytree_utils_test.py b/yapftests/pytree_utils_test.py index 6c650c046..161c93906 100644 --- a/yapftests/pytree_utils_test.py +++ b/yapftests/pytree_utils_test.py @@ -91,8 +91,8 @@ def _BuildSimpleTree(self): lpar2 = pytree.Leaf(token.LPAR, '(') simple_stmt = pytree.Node(_GRAMMAR_SYMBOL2NUMBER['simple_stmt'], [pytree.Leaf(token.NAME, 'foo')]) - return pytree.Node(_GRAMMAR_SYMBOL2NUMBER['suite'], [lpar1, lpar2, - simple_stmt]) + return pytree.Node(_GRAMMAR_SYMBOL2NUMBER['suite'], + [lpar1, lpar2, simple_stmt]) def _MakeNewNodeRPAR(self): return pytree.Leaf(token.RPAR, ')') diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index b1a62f9e7..6cc5944b5 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -489,9 +489,10 @@ def testOpeningAndClosingBrackets(self): foo( ( 1, 2, 3, ) ) """) expected_formatted_code = textwrap.dedent("""\ - foo((1, - 2, - 3,)) + foo(( + 1, + 2, + 3,)) """) uwlines = _ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1854,7 +1855,7 @@ def testDictionaryOnOwnLine(self): uwlines = _ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - def testDictionaryOnOwnLine(self): + def testNestedListsInDictionary(self): unformatted_code = textwrap.dedent("""\ _A = { 'cccccccccc': ('^^1',), @@ -1921,6 +1922,39 @@ def testDictionaryOnOwnLine(self): uwlines = _ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testNestedDictionary(self): + unformatted_code = textwrap.dedent("""\ + class _(): + def _(): + breadcrumbs = [{'name': 'Admin', + 'url': url_for(".home")}, + {'title': title},] + breadcrumbs = [{'name': 'Admin', + 'url': url_for(".home")}, + {'title': title}] + """) + expected_formatted_code = textwrap.dedent("""\ + class _(): + def _(): + breadcrumbs = [ + { + 'name': 'Admin', + 'url': url_for(".home") + }, + { + 'title': title + }, + ] + breadcrumbs = [{ + 'name': 'Admin', + 'url': url_for(".home") + }, { + 'title': title + }] + """) + uwlines = _ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + class BuganizerFixes(ReformatterTest): @@ -3980,10 +4014,12 @@ def testDedentSet(self): class _(): def _(): assert set(self.constraint_links.get_links()) == set( - [(2, 10, 100), - (2, 10, 200), - (2, 20, 100), - (2, 20, 200), ] + [ + (2, 10, 100), + (2, 10, 200), + (2, 20, 100), + (2, 20, 200), + ] ) """) uwlines = _ParseAndUnwrap(unformatted_code) diff --git a/yapftests/unwrapped_line_test.py b/yapftests/unwrapped_line_test.py index d3e988944..c9632f8f9 100644 --- a/yapftests/unwrapped_line_test.py +++ b/yapftests/unwrapped_line_test.py @@ -33,8 +33,10 @@ def _MakeFormatTokenLeaf(token_type, token_value): def _MakeFormatTokenList(token_type_values): - return [_MakeFormatTokenLeaf(token_type, token_value) - for token_type, token_value in token_type_values] + return [ + _MakeFormatTokenLeaf(token_type, token_value) + for token_type, token_value in token_type_values + ] class UnwrappedLineBasicTest(unittest.TestCase): @@ -82,9 +84,10 @@ def _ParseAndUnwrap(self, code): uwlines = pytree_unwrapper.UnwrapPyTree(tree) for i, uwline in enumerate(uwlines): - uwlines[i] = unwrapped_line.UnwrappedLine( - uwline.depth, [ft for ft in uwline.tokens - if ft.name not in pytree_utils.NONSEMANTIC_TOKENS]) + uwlines[i] = unwrapped_line.UnwrappedLine(uwline.depth, [ + ft for ft in uwline.tokens + if ft.name not in pytree_utils.NONSEMANTIC_TOKENS + ]) return uwlines def testFuncDef(self): diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index d18cc63e0..327487a82 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -233,7 +233,7 @@ def testFormatFileDiff(self): """) file1 = self._MakeTempFileWithContents('testfile1.py', unformatted_code) diff = yapf_api.FormatFile(file1, print_diff=True)[0] - self.assertTrue(u'+ pass' in diff) + self.assertTrue(u'+ pass' in diff) def testFormatFileInPlace(self): unformatted_code = 'True==False\n' From 26384ecf11de76a40389d7c32d886fcac936fb28 Mon Sep 17 00:00:00 2001 From: Diogo de Campos Date: Wed, 5 Oct 2016 14:38:52 +0200 Subject: [PATCH 038/719] Added __hash__ and __eq__ to _ParenState This should fix some state duplication in sets, and speed up overall process --- yapf/yapflib/format_decision_state.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 618d904cb..b24d4ba25 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -633,3 +633,10 @@ def __copy__(self): def __repr__(self): return '[indent::%d, last_space::%d, closing_scope_indent::%d]' % ( self.indent, self.last_space, self.closing_scope_indent) + + def __eq__(self, other): + return hash(self) == hash(other) + + def __hash__(self, *args, **kwargs): + return hash((self.indent, self.last_space, self.closing_scope_indent, + self.split_before_closing_bracket, self.num_line_splits)) From 276e94c9052a3a7d21d891b049a6876d1e45b8ad Mon Sep 17 00:00:00 2001 From: Diogo de Campos Date: Thu, 6 Oct 2016 11:14:15 +0200 Subject: [PATCH 039/719] Make acessing FormatToken.value faster --- yapf/yapflib/format_token.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 659756492..23fcf0098 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -103,6 +103,11 @@ def __init__(self, node): else: self.spaces_required_before = 0 + if self.is_continuation: + self.value = self.node.value.rstrip() + else: + self.value = self.node.value + def AddWhitespacePrefix(self, newlines_before, spaces=0, indent_level=0): """Register a token's whitespace prefix. @@ -121,6 +126,9 @@ def AddWhitespacePrefix(self, newlines_before, spaces=0, indent_level=0): comment_lines = [s.lstrip() for s in self.value.splitlines()] self.node.value = ('\n' + indent_before).join(comment_lines) + # Update our own value since we are changing node value + self.value = self.node.value + if not self.whitespace_prefix: self.whitespace_prefix = ( '\n' * (self.newlines or newlines_before) + indent_before) @@ -175,12 +183,6 @@ def __repr__(self): msg += ', pseudo)' if self.is_pseudo_paren else ')' return msg - @property - def value(self): - if self.is_continuation: - return self.node.value.rstrip() - return self.node.value - @property @py3compat.lru_cache() def node_split_penalty(self): From 9d471853c2b12aadfd896469e8674bac4562f0c9 Mon Sep 17 00:00:00 2001 From: Diogo de Campos Date: Fri, 7 Oct 2016 10:38:26 +0200 Subject: [PATCH 040/719] Added __ne__ to _ParenState --- yapf/yapflib/format_decision_state.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index b24d4ba25..5e644d9ce 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -637,6 +637,9 @@ def __repr__(self): def __eq__(self, other): return hash(self) == hash(other) + def __ne__(self, other): + return not self == other + def __hash__(self, *args, **kwargs): return hash((self.indent, self.last_space, self.closing_scope_indent, self.split_before_closing_bracket, self.num_line_splits)) From 0256657bf07096809240a306eda3ec4e76ebdeb5 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 9 Oct 2016 03:30:53 -0700 Subject: [PATCH 041/719] Count dict entry start's length for "fits on line" --- yapf/yapflib/format_decision_state.py | 28 +++++++++++++++++---------- yapf/yapflib/subtype_assigner.py | 5 ++++- yapftests/pytree_utils_test.py | 3 ++- yapftests/reformatter_test.py | 17 +++++++++++++++- 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 5e644d9ce..3494b3e62 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -125,6 +125,9 @@ def MustSplit(self): current = self.next_token previous = current.previous_token + if current.is_pseudo_paren: + return False + if current.must_break_before: return True @@ -216,7 +219,7 @@ def MustSplit(self): if previous.is_pseudo_paren: # Split before the dictionary value if we can't fit the whole # dictionary on one line. - if not self._AllDictElementsFitOnOneLine(opening): + if not self._EachDictEntryFitsOnOneLine(opening): return True if (previous.OpensScope() and not current.OpensScope() and @@ -525,23 +528,28 @@ def _MoveStateToNextToken(self): def _FitsOnLine(self, start, end): """Determines if line between start and end can fit on the current line.""" - length = end.total_length - start.total_length + length = end.total_length - start.total_length + len(start.value) return length + self.column < self.column_limit - def _AllDictElementsFitOnOneLine(self, opening): - """Determine if all dict elems can fit on one line.""" + def _EachDictEntryFitsOnOneLine(self, opening): + """Determine if each dict elems can fit on one line.""" closing = opening.matching_bracket - current = opening.next_token - start = None + entry_start = opening.next_token + current = opening.next_token.next_token while current and current != closing: if format_token.Subtype.DICTIONARY_KEY in current.subtypes: - if start and not self._FitsOnLine(start, current.previous_token): + length = current.previous_token.total_length - entry_start.total_length + length += len(entry_start.value) + if length + self.stack[-2].indent >= self.column_limit: return False - start = current + entry_start = current if current.OpensScope(): current = current.matching_bracket - current = current.next_token - return start and self._FitsOnLine(start, current.previous_token) + else: + current = current.next_token + length = current.total_length - entry_start.total_length + length += len(entry_start.value) + return length + self.stack[-2].indent + 2 < self.column_limit def _IsFunctionCallWithArguments(token): diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index d8e886fd8..f848aabbf 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -364,9 +364,12 @@ def _InsertPseudoParentheses(node): node.append_child(rparen) if comment_node: node.append_child(comment_node) + _AppendFirstLeafTokenSubtype(node, format_token.Subtype.DICTIONARY_VALUE) else: - new_node = pytree.Node(syms.atom, [lparen, node.clone(), rparen]) + clone = node.clone() + new_node = pytree.Node(syms.atom, [lparen, clone, rparen]) node.replace(new_node) + _AppendFirstLeafTokenSubtype(clone, format_token.Subtype.DICTIONARY_VALUE) def _GetFirstLeafNode(node): diff --git a/yapftests/pytree_utils_test.py b/yapftests/pytree_utils_test.py index 161c93906..8861a4070 100644 --- a/yapftests/pytree_utils_test.py +++ b/yapftests/pytree_utils_test.py @@ -188,7 +188,8 @@ def testSubtype(self): self.assertSetEqual( pytree_utils.GetNodeAnnotation(self._leaf, - pytree_utils.Annotation.SUBTYPE), {_FOO}) + pytree_utils.Annotation.SUBTYPE), + {_FOO}) pytree_utils.RemoveSubtypeAnnotation(self._leaf, _FOO) diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index 6cc5944b5..88cb3d1c8 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -1955,6 +1955,19 @@ def _(): uwlines = _ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testImportAsList(self): + code = textwrap.dedent("""\ + class _(): + + @mock.patch.dict( + os.environ, + {'HTTP_' + xsrf._XSRF_TOKEN_HEADER.replace('-', '_'): 'atoken'}) + def _(): + pass + """) + uwlines = _ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + class BuganizerFixes(ReformatterTest): @@ -3989,7 +4002,9 @@ class _(): def _(): effect_line = FrontInput( effect_line_offset, line_content, - LineSource('localhost', xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) + LineSource( + 'localhost', xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + ) ) """) uwlines = _ParseAndUnwrap(unformatted_code) From 4d0d923bcc165242e151644e6ab67bd1fc2f654d Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 9 Oct 2016 20:40:15 -0700 Subject: [PATCH 042/719] Bump version to v0.12.2 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 57e40d01e..1237c4a6b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.12.2] UNRELEASED +## [0.12.2] 2016-10-09 ### Fixed - If `style.SetGlobalStyle()` was called and then `yapf_api.FormatCode` was called, the style set by the first call would be diff --git a/yapf/__init__.py b/yapf/__init__.py index 9fad86d13..c442761ce 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.12.1' +__version__ = '0.12.2' def main(argv): From 1e2cc8c2ab2ec3d38a2e998c2b959a2d050d2427 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 9 Oct 2016 21:08:01 -0700 Subject: [PATCH 043/719] Rename duplicate function name. --- yapftests/reformatter_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index 88cb3d1c8..f66001bc8 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -1955,7 +1955,7 @@ def _(): uwlines = _ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - def testImportAsList(self): + def testDictionaryElementsOnOneLine(self): code = textwrap.dedent("""\ class _(): From 8a00b0eacb909f19a671ad2a2899d0fa9da2bd5e Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 11 Oct 2016 13:40:38 -0700 Subject: [PATCH 044/719] Ignore blank lines before disabled comment line Fixes #318 --- CHANGELOG | 8 ++++++++ yapf/yapflib/reformatter.py | 3 ++- yapf/yapflib/yapf_api.py | 3 ++- yapftests/yapf_test.py | 20 ++++++++++++++++++++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1237c4a6b..62228ab82 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,14 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.12.3] UNRELEASED +### Fixed +- Functions or classes with comments before them were reformatting the comments + even if the code was supposed to be ignored by the formatter. We now don't + adjust the whitespace before a function's comment if the comment is a + "disabled" line. We also don't count "# yapf: {disable|enable}" as a disabled + line, which seems logical. + ## [0.12.2] 2016-10-09 ### Fixed - If `style.SetGlobalStyle()` was called and then diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index d7a52e723..d7788e487 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -466,7 +466,8 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, if not indent_depth: # This is a top-level class or function. is_inline_comment = prev_last_token.whitespace_prefix.count('\n') == 0 - if prev_last_token.is_comment and not is_inline_comment: + if (not prev_uwline.disable and prev_last_token.is_comment and + not is_inline_comment): # This token follows a non-inline comment. if _NoBlankLinesBeforeCurrentToken(prev_last_token.value, first_token, prev_last_token): diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 916ba5375..4614ee1e9 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -218,11 +218,12 @@ def _MarkLinesToFormat(uwlines, lines): uwline = uwlines[index] if uwline.is_comment: if _DisableYAPF(uwline.first.value.strip()): + index += 1 while index < len(uwlines): uwline = uwlines[index] - uwline.disable = True if uwline.is_comment and _EnableYAPF(uwline.first.value.strip()): break + uwline.disable = True index += 1 elif re.search(DISABLE_PATTERN, uwline.last.value.strip(), re.IGNORECASE): uwline.disable = True diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 327487a82..259ec27d6 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -524,6 +524,26 @@ def g(): expected_formatted_code, extra_options=['--lines', '1-2']) + def testOmitFormattingLinesBeforeDisabledFunctionComment(self): + unformatted_code = textwrap.dedent(u"""\ + import sys + + # Comment + def some_func(x): + x = ["badly" , "formatted","line" ] + """) + expected_formatted_code = textwrap.dedent(u"""\ + import sys + + # Comment + def some_func(x): + x = ["badly", "formatted", "line"] + """) + self.assertYapfReformats( + unformatted_code, + expected_formatted_code, + extra_options=['--lines', '5-5']) + def testReformattingSkippingLines(self): unformatted_code = textwrap.dedent(u"""\ def h(): From 8cba82b91cc2eb1987d31641ba6e2f6bfdf77553 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 11 Oct 2016 20:26:23 -0700 Subject: [PATCH 045/719] Don't split before a dict val in a comp_for --- CHANGELOG | 2 ++ yapf/yapflib/subtype_assigner.py | 26 +++++++++++++------------- yapftests/reformatter_test.py | 3 +-- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 62228ab82..54ac59119 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,8 @@ adjust the whitespace before a function's comment if the comment is a "disabled" line. We also don't count "# yapf: {disable|enable}" as a disabled line, which seems logical. +- It's not really more readable to split before a dictionary value if it's part + of a dictionary comprehension. ## [0.12.2] 2016-10-09 ### Fixed diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index f848aabbf..da08b38c7 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -63,22 +63,23 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name # dictsetmaker ::= (test ':' test (comp_for | # (',' test ':' test)* [','])) | # (test (comp_for | (',' test)* [','])) + for child in node.children: + self.Visit(child) + + comp_for = False dict_maker = False - if len(node.children) > 1: - index = 0 - while index < len(node.children): - if node.children[index].type != token.COMMENT: - break - index += 1 - if index < len(node.children): - child = node.children[index + 1] - dict_maker = isinstance(child, pytree.Leaf) and child.value == ':' - last_was_colon = False + for child in node.children: if pytree_utils.NodeName(child) == 'comp_for': + comp_for = True _AppendFirstLeafTokenSubtype(child, format_token.Subtype.DICT_SET_GENERATOR) - else: + elif pytree_utils.NodeName(child) == 'COLON': + dict_maker = True + + if not comp_for and dict_maker: + last_was_colon = False + for child in node.children: if dict_maker: if last_was_colon: if style.Get('INDENT_DICTIONARY_VALUE'): @@ -93,8 +94,7 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name # on a single line. _AppendFirstLeafTokenSubtype(child, format_token.Subtype.DICTIONARY_KEY) - last_was_colon = isinstance(child, pytree.Leaf) and child.value == ':' - self.Visit(child) + last_was_colon = pytree_utils.NodeName(child) == 'COLON' def Visit_expr_stmt(self, node): # pylint: disable=invalid-name # expr_stmt ::= testlist_star_expr (augassign (yield_expr|testlist) diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index f66001bc8..ceec57f03 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -1204,8 +1204,7 @@ def bar(self): def testDictSetGenerator(self): code = textwrap.dedent("""\ foo = { - variable: - 'hello world. How are you today?' + variable: 'hello world. How are you today?' for variable in fnord if variable != 37 } """) From 4aa40ab39beb01a22fac339702df099ebf7ae57f Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 13 Oct 2016 01:27:38 -0700 Subject: [PATCH 046/719] Enforce two blank lines after def/class definition Closes #311 --- CHANGELOG | 2 ++ yapf/yapflib/blank_line_calculator.py | 3 +-- yapf/yapflib/comment_splicer.py | 2 ++ yapf/yapflib/pytree_unwrapper.py | 1 + yapf/yapflib/pytree_utils.py | 2 ++ yapf/yapflib/reformatter.py | 1 + yapf/yapflib/style.py | 2 ++ yapf/yapflib/subtype_assigner.py | 1 + yapftests/blank_line_calculator_test.py | 1 + yapftests/reformatter_test.py | 3 +-- 10 files changed, 14 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 54ac59119..5b85e4d6b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,8 @@ line, which seems logical. - It's not really more readable to split before a dictionary value if it's part of a dictionary comprehension. +- Enforce two blank lines after a function or class definition, even before a + comment. This is related to PEP8 error E305. ## [0.12.2] 2016-10-09 ### Fixed diff --git a/yapf/yapflib/blank_line_calculator.py b/yapf/yapflib/blank_line_calculator.py index 677062051..2076e5866 100644 --- a/yapf/yapflib/blank_line_calculator.py +++ b/yapf/yapflib/blank_line_calculator.py @@ -116,8 +116,7 @@ def DefaultNodeVisit(self, node): if self.last_was_class_or_function: if pytree_utils.NodeName(node) in _PYTHON_STATEMENTS: leaf = _GetFirstChildLeaf(node) - if pytree_utils.NodeName(leaf) != 'COMMENT': - self._SetNumNewlines(leaf, self._GetNumNewlines(leaf)) + self._SetNumNewlines(leaf, self._GetNumNewlines(leaf)) self.last_was_class_or_function = False super(_BlankLineCalculator, self).DefaultNodeVisit(node) diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index 8c4feaf24..2ff3053e1 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -249,6 +249,7 @@ def _CreateCommentsFromPrefix(comment_prefix, return comments + # "Standalone line nodes" are tree nodes that have to start a new line in Python # code (and cannot follow a ';' or ':'). Other nodes, like 'expr_stmt', serve as # parents of other nodes but can come later in a line. This is a list of @@ -284,6 +285,7 @@ def _FindNodeWithStandaloneLineParent(node): # any pytree. return _FindNodeWithStandaloneLineParent(node.parent) + # "Statement nodes" are standalone statements. The don't have to start a new # line. _STATEMENT_NODES = frozenset(['simple_stmt']) | _STANDALONE_LINE_NODES diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index 4d17f027c..e651061b5 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -52,6 +52,7 @@ def UnwrapPyTree(tree): uwlines.sort(key=lambda x: x.lineno) return uwlines + # Grammar tokens considered as whitespace for the purpose of unwrapping. _WHITESPACE_TOKENS = frozenset([ grammar_token.NEWLINE, grammar_token.DEDENT, grammar_token.INDENT, diff --git a/yapf/yapflib/pytree_utils.py b/yapf/yapflib/pytree_utils.py index 9fea5e69b..1bebcb8ac 100644 --- a/yapf/yapflib/pytree_utils.py +++ b/yapf/yapflib/pytree_utils.py @@ -67,6 +67,7 @@ def NodeName(node): else: return pygram.python_grammar.number2symbol[node.type] + # lib2to3 thoughtfully provides pygram.python_grammar_no_print_statement for # parsing Python 3 code that wouldn't parse otherwise (when 'print' is used in a # context where a keyword is disallowed). @@ -197,6 +198,7 @@ def _InsertNodeAt(new_node, target, after=False): raise RuntimeError('unable to find insertion point for target node', (target,)) + # The following constant and functions implement a simple custom annotation # mechanism for pytree nodes. We attach new attributes to nodes. Each attribute # is prefixed with _NODE_ANNOTATION_PREFIX. These annotations should only be diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index d7788e487..338395156 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -273,6 +273,7 @@ def __repr__(self): # pragma: no cover return 'StateNode(state=[\n{0}\n], newline={1})'.format(self.state, self.newline) + # A tuple of (penalty, count) that is used to prioritize the BFS. In case of # equal penalties, we prefer states that were inserted first. During state # generation, we make sure that we insert states first that break the line as diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 4da837d1e..b45383c3e 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -276,6 +276,7 @@ def _BoolConverter(s): """Option value converter for a boolean.""" return py3compat.CONFIGPARSER_BOOLEAN_STATES[s.lower()] + # Different style options need to have their values interpreted differently when # read from the config file. This dict maps an option name to a "converter" # function that accepts the string read for the option's value from the file and @@ -434,6 +435,7 @@ def _CreateStyleFromConfigParser(config): value, option)) return base_style + # The default style - used if yapf is not invoked without specifically # requesting a formatting style. DEFAULT_STYLE = 'pep8' diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index da08b38c7..a0af020f0 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -44,6 +44,7 @@ def AssignSubtypes(tree): subtype_assigner = _SubtypeAssigner() subtype_assigner.Visit(tree) + # Map tokens in argument lists to their respective subtype. _ARGLIST_TOKEN_TO_SUBTYPE = { '=': format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN, diff --git a/yapftests/blank_line_calculator_test.py b/yapftests/blank_line_calculator_test.py index 69d95ce9b..189fcd37d 100644 --- a/yapftests/blank_line_calculator_test.py +++ b/yapftests/blank_line_calculator_test.py @@ -195,6 +195,7 @@ def foo(self): def foo(): pass + # multiline before a # class definition diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index ceec57f03..4e5d0bfa5 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -197,7 +197,6 @@ def testComments(self): unformatted_code = textwrap.dedent("""\ class Foo(object): pass - # End class Foo # Attached comment class Bar(object): @@ -220,7 +219,6 @@ class Qux(object): expected_formatted_code = textwrap.dedent("""\ class Foo(object): pass - # End class Foo # Attached comment @@ -238,6 +236,7 @@ class Bar(object): class Baz(object): pass + # Intermediate comment From 45d60103f8e35df73aaf5a7ea8784cc53635280f Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 13 Oct 2016 11:26:26 -0700 Subject: [PATCH 047/719] No blank line between decorator and comment Closes #322 --- CHANGELOG | 3 ++- yapf/yapflib/blank_line_calculator.py | 3 ++- yapftests/blank_line_calculator_test.py | 19 ++++++++++++++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5b85e4d6b..b64e9d2c7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,7 +12,8 @@ - It's not really more readable to split before a dictionary value if it's part of a dictionary comprehension. - Enforce two blank lines after a function or class definition, even before a - comment. This is related to PEP8 error E305. + comment. (But not between a decorator and a comment.) This is related to PEP8 + error E305. ## [0.12.2] 2016-10-09 ### Fixed diff --git a/yapf/yapflib/blank_line_calculator.py b/yapf/yapflib/blank_line_calculator.py index 2076e5866..81f6de210 100644 --- a/yapf/yapflib/blank_line_calculator.py +++ b/yapf/yapflib/blank_line_calculator.py @@ -137,7 +137,8 @@ def _SetBlankLinesBetweenCommentAndClassFunc(self, node): # Standalone comments are wrapped in a simple_stmt node with the comment # node as its only child. self.Visit(node.children[index].children[0]) - self._SetNumNewlines(node.children[index].children[0], _ONE_BLANK_LINE) + if not self.last_was_decorator: + self._SetNumNewlines(node.children[index].children[0], _ONE_BLANK_LINE) index += 1 if (index and node.children[index].lineno - 1 == node.children[index - 1].children[0].lineno): diff --git a/yapftests/blank_line_calculator_test.py b/yapftests/blank_line_calculator_test.py index 189fcd37d..d3f6af274 100644 --- a/yapftests/blank_line_calculator_test.py +++ b/yapftests/blank_line_calculator_test.py @@ -245,7 +245,7 @@ class Foo(object): uwlines = _ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - def testComemntsBeforeDecorator(self): + def testCommentsBeforeDecorator(self): code = textwrap.dedent("""\ # The @foo operator adds bork to a(). @foo() @@ -266,6 +266,23 @@ def a(): uwlines = _ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testCommentsAfterDecorator(self): + code = textwrap.dedent("""\ + class _(): + + def _(): + pass + + @pytest.mark.xfail(reason="#709 and #710") + # also + #@pytest.mark.xfail(setuptools.tests.is_ascii, + # reason="https://github.com/pypa/setuptools/issues/706") + def test_unicode_filename_in_sdist(self, sdist_unicode, tmpdir, monkeypatch): + pass + """) + uwlines = _ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testInnerClasses(self): unformatted_code = textwrap.dedent("""\ class DeployAPIClient(object): From fa12bc0f6c90006a8a066d986402d08b6a2a9906 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 14 Oct 2016 00:36:21 -0700 Subject: [PATCH 048/719] Mark lines to format in O(n) time --- CHANGELOG | 1 + yapf/yapflib/yapf_api.py | 35 ++++++++++++++++++++++++++++------- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b64e9d2c7..02895cbf1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,7 @@ - Enforce two blank lines after a function or class definition, even before a comment. (But not between a decorator and a comment.) This is related to PEP8 error E305. +- Remove O(n^2) algorithm from the line disabling logic. ## [0.12.2] 2016-10-09 ### Fixed diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 4614ee1e9..b6cffe6f0 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -204,15 +204,36 @@ def _MarkLinesToFormat(uwlines, lines): for uwline in uwlines: uwline.disable = True - for start, end in sorted(lines): - for uwline in uwlines: - if uwline.lineno > end: + # Sort and combine overlapping ranges. + lines = sorted(lines) + line_ranges = [lines[0]] if len(lines[0]) else [] + index = 1 + while index < len(lines): + current = line_ranges[-1] + if lines[index][0] <= current[1]: + # The ranges overlap, so combine them. + line_ranges[-1] = (current[0], max(lines[index][1], current[1])) + else: + line_ranges.append(lines[index]) + index += 1 + + # Mark lines to format as not being disabled. + index = 0 + for start, end in sorted(line_ranges): + while index < len(uwlines) and uwlines[index].last.lineno < start: + index += 1 + if index >= len(uwlines): + break + + while index < len(uwlines): + if uwlines[index].lineno > end: break - if uwline.lineno >= start: - uwline.disable = False - elif uwline.last.lineno >= start: - uwline.disable = False + if uwlines[index].lineno >= start or uwlines[index].last.lineno >= start: + uwlines[index].disable = False + index += 1 + # Now go through the lines and disable any lines explicitly marked as + # disabled. index = 0 while index < len(uwlines): uwline = uwlines[index] From 88db54bca3b27ac61caa045346dc994bc8969045 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 16 Oct 2016 00:30:02 -0500 Subject: [PATCH 049/719] Retain the line endings of the original src code There are more line endings in heaven and earth, Kernighan, than are dreamt of in your philosophy. Closes #288 --- CHANGELOG | 5 +- yapf/__init__.py | 21 ++- yapf/yapflib/file_resources.py | 27 +++- yapf/yapflib/py3compat.py | 5 +- yapf/yapflib/yapf_api.py | 17 ++- yapftests/file_resources_test.py | 2 +- yapftests/main_test.py | 34 ++++- yapftests/yapf_test.py | 229 ++++++++++++++++--------------- 8 files changed, 203 insertions(+), 137 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 02895cbf1..8bc23fda8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.12.3] UNRELEASED +## [0.13.0] UNRELEASED +### Added +- Added support to retain the original line endings of the source code. + ### Fixed - Functions or classes with comments before them were reformatting the comments even if the code was supposed to be ignored by the formatter. We now don't diff --git a/yapf/__init__.py b/yapf/__init__.py index c442761ce..750587767 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -151,23 +151,27 @@ def main(argv): original_source.append(py3compat.raw_input()) except EOFError: break + style_config = args.style if style_config is None and not args.no_local_style: style_config = file_resources.GetDefaultStyleForDir(os.getcwd()) + + source = [line.rstrip() for line in original_source] reformatted_source, changed = yapf_api.FormatCode( - py3compat.unicode('\n'.join(original_source) + '\n'), + py3compat.unicode('\n'.join(source) + '\n'), filename='', style_config=style_config, lines=lines, verify=args.verify) - sys.stdout.write(reformatted_source) + file_resources.WriteReformattedCode('', reformatted_source) return 0 files = file_resources.GetCommandLineFiles(args.files, args.recursive, args.exclude) if not files: raise errors.YapfError('Input filenames did not match any python files') - changed = FormatFiles( + + FormatFiles( files, lines, style_config=args.style, @@ -200,18 +204,14 @@ def FormatFiles(filenames, print_diff: (bool) Instead of returning the reformatted source, return a diff that turns the formatted source into reformatter source. verify: (bool) True if reformatted code should be verified for syntax. - - Returns: - True if the source code changed in any of the files being formatted. """ - changed = False for filename in filenames: logging.info('Reformatting %s', filename) if style_config is None and not no_local_style: style_config = ( file_resources.GetDefaultStyleForDir(os.path.dirname(filename))) try: - reformatted_code, encoding, has_change = yapf_api.FormatFile( + yapf_api.FormatFile( filename, in_place=in_place, style_config=style_config, @@ -219,14 +219,9 @@ def FormatFiles(filenames, print_diff=print_diff, verify=verify, logger=logging.warning) - if has_change and reformatted_code is not None: - file_resources.WriteReformattedCode(filename, reformatted_code, - in_place, encoding) - changed |= has_change except SyntaxError as e: e.filename = filename raise - return changed def _GetLines(line_strings): diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index a49233f31..1671706af 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -28,6 +28,11 @@ from yapf.yapflib import style +CR = '\r' +LF = '\n' +CRLF = '\r\n' + + def GetDefaultStyleForDir(dirname): """Return default style name for a given directory. @@ -72,7 +77,8 @@ def GetCommandLineFiles(command_line_file_list, recursive, exclude): return _FindPythonFiles(command_line_file_list, recursive, exclude) -def WriteReformattedCode(filename, reformatted_code, in_place, encoding): +def WriteReformattedCode(filename, reformatted_code, newline=os.linesep, + in_place=False, encoding=''): """Emit the reformatted code. Write the reformatted code into the file, if in_place is True. Otherwise, @@ -81,6 +87,7 @@ def WriteReformattedCode(filename, reformatted_code, in_place, encoding): Arguments: filename: (unicode) The name of the unformatted file. reformatted_code: (unicode) The reformatted code. + newline: (unicode) The original line ending of the source file. in_place: (bool) If True, then write the reformatted code to the file. encoding: (unicode) The encoding of the file. """ @@ -89,7 +96,20 @@ def WriteReformattedCode(filename, reformatted_code, in_place, encoding): filename, mode='w', encoding=encoding) as fd: fd.write(reformatted_code) else: - py3compat.EncodeAndWriteToStdout(reformatted_code, encoding) + py3compat.EncodeAndWriteToStdout(reformatted_code) + + +def LineEnding(lines): + """Retrieve the line ending of the original source.""" + endings = {CRLF: 0, CR: 0, LF: 0} + for line in lines: + if line.endswith(CRLF): + endings[CRLF] += 1 + elif line.endswith(CR): + endings[CR] += 1 + elif line.endswith(LF): + endings[LF] += 1 + return (sorted(endings, key=endings.get, reverse=True) or [LF])[0] def _FindPythonFiles(filenames, recursive, exclude): @@ -128,7 +148,8 @@ def IsPythonFile(filename): encoding = tokenize.detect_encoding(fd.readline)[0] # Check for correctness of encoding. - with py3compat.open_with_encoding(filename, encoding=encoding) as fd: + with py3compat.open_with_encoding( + filename, mode='r', encoding=encoding) as fd: fd.read() except UnicodeDecodeError: encoding = 'latin-1' diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py index c19cab0b8..a888aa15e 100644 --- a/yapf/yapflib/py3compat.py +++ b/yapf/yapflib/py3compat.py @@ -23,7 +23,8 @@ BytesIO = io.BytesIO import codecs - open_with_encoding = codecs.open + def open_with_encoding(filename, mode, encoding, newline=''): + return codecs.open(filename, mode=mode, encoding=encoding) import functools lru_cache = functools.lru_cache @@ -61,7 +62,7 @@ def fake_wrapper(user_function): CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser._boolean_states # pylint: disable=protected-access -def EncodeAndWriteToStdout(s, encoding): +def EncodeAndWriteToStdout(s, encoding='utf-8'): """Encode the given string and emit to stdout. The string may contain non-ascii characters. This is a problem when stdout is diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index b6cffe6f0..2e41b2b2c 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -80,7 +80,7 @@ def FormatFile(filename, if in_place and print_diff: raise ValueError('Cannot pass both in_place and print_diff.') - original_source, encoding = ReadFile(filename, logger) + original_source, newline, encoding = ReadFile(filename, logger) reformatted_source, changed = FormatCode( original_source, style_config=style_config, @@ -88,10 +88,13 @@ def FormatFile(filename, lines=lines, print_diff=print_diff, verify=verify) + if reformatted_source.rstrip('\n'): + lines = reformatted_source.rstrip('\n').split('\n') + reformatted_source = newline.join(line for line in lines) + newline if in_place: if original_source and original_source != reformatted_source: file_resources.WriteReformattedCode(filename, reformatted_source, - in_place, encoding) + newline, in_place, encoding) return None, encoding, changed return reformatted_source, encoding, changed @@ -184,10 +187,14 @@ def ReadFile(filename, logger=None): raise try: + # Preserves line endings. with py3compat.open_with_encoding( - filename, mode='r', encoding=encoding) as fd: - source = fd.read() - return source, encoding + filename, mode='r', encoding=encoding, newline='') as fd: + lines = fd.readlines() + + line_ending = file_resources.LineEnding(lines) + source = '\n'.join(line.rstrip('\r\n') for line in lines) + '\n' + return source, line_ending, encoding except IOError as err: # pragma: no cover if logger: logger(err) diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 9987a6c1a..743df5f20 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -212,7 +212,7 @@ def tearDownClass(cls): shutil.rmtree(cls.test_tmpdir) def test_write_to_file(self): - s = u'foobar' + s = u'foobar\n' with tempfile.NamedTemporaryFile(dir=self.test_tmpdir) as testfile: file_resources.WriteReformattedCode( testfile.name, s, in_place=True, encoding='utf-8') diff --git a/yapftests/main_test.py b/yapftests/main_test.py index 73b4a81f6..abdf28310 100644 --- a/yapftests/main_test.py +++ b/yapftests/main_test.py @@ -25,10 +25,42 @@ # Note: io.StringIO is different in Python 2, so try for python 2 first. from io import StringIO +from yapf.yapflib import py3compat + + +class IO(object): + """IO is a thin wrapper around StringIO. + + This is strictly to wrap the Python 3 StringIO object so that it can supply a + "buffer" attribute. + """ + + class Buffer(object): + + def __init__(self): + self.string_io = StringIO() + + def write(self, s): + if py3compat.PY3 and isinstance(s, bytes): + s = str(s, 'utf-8') + self.string_io.write(s) + + def getvalue(self): + return self.string_io.getvalue() + + def __init__(self): + self.buffer = self.Buffer() + + def write(self, s): + self.buffer.write(s) + + def getvalue(self): + return self.buffer.getvalue() + @contextmanager def captured_output(): - new_out, new_err = StringIO(), StringIO() + new_out, new_err = IO(), IO() old_out, old_err = sys.stdout, sys.stderr try: sys.stdout, sys.stderr = new_out, new_err diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 259ec27d6..bba17fb42 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -42,16 +42,16 @@ def _Check(self, unformatted_code, expected_formatted_code): self.assertEqual(expected_formatted_code, formatted_code) def testSimple(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ print('foo') """) self._Check(unformatted_code, unformatted_code) def testNoEndingNewline(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ if True: pass""") - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ if True: pass """) @@ -78,34 +78,34 @@ def assertCodeEqual(self, expected_code, code): def _MakeTempFileWithContents(self, filename, contents): path = os.path.join(self.test_tmpdir, filename) - with open(path, 'w') as f: - f.write(contents) + with py3compat.open_with_encoding(path, mode='w', encoding='utf-8') as f: + f.write(py3compat.unicode(contents)) return path def testFormatFile(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ if True: pass """) - file1 = self._MakeTempFileWithContents('testfile1.py', unformatted_code) + f = self._MakeTempFileWithContents('testfile1.py', unformatted_code) - expected_formatted_code_pep8 = textwrap.dedent(u"""\ + expected_formatted_code_pep8 = textwrap.dedent("""\ if True: pass """) - expected_formatted_code_chromium = textwrap.dedent(u"""\ + expected_formatted_code_chromium = textwrap.dedent("""\ if True: pass """) - formatted_code = yapf_api.FormatFile(file1, style_config='pep8')[0] + formatted_code, _, _ = yapf_api.FormatFile(f, style_config='pep8') self.assertCodeEqual(expected_formatted_code_pep8, formatted_code) - formatted_code = yapf_api.FormatFile(file1, style_config='chromium')[0] + formatted_code, _, _ = yapf_api.FormatFile(f, style_config='chromium') self.assertCodeEqual(expected_formatted_code_chromium, formatted_code) def testDisableLinesPattern(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ if a: b # yapf: disable @@ -113,9 +113,9 @@ def testDisableLinesPattern(self): if h: i """) - file1 = self._MakeTempFileWithContents('testfile1.py', unformatted_code) + f = self._MakeTempFileWithContents('testfile1.py', unformatted_code) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ if a: b # yapf: disable @@ -123,11 +123,11 @@ def testDisableLinesPattern(self): if h: i """) - formatted_code = yapf_api.FormatFile(file1, style_config='pep8')[0] + formatted_code, _, _ = yapf_api.FormatFile(f, style_config='pep8') self.assertCodeEqual(expected_formatted_code, formatted_code) def testDisableAndReenableLinesPattern(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ if a: b # yapf: disable @@ -136,9 +136,9 @@ def testDisableAndReenableLinesPattern(self): if h: i """) - file1 = self._MakeTempFileWithContents('testfile1.py', unformatted_code) + f = self._MakeTempFileWithContents('testfile1.py', unformatted_code) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ if a: b # yapf: disable @@ -147,11 +147,11 @@ def testDisableAndReenableLinesPattern(self): if h: i """) - formatted_code = yapf_api.FormatFile(file1, style_config='pep8')[0] + formatted_code, _, _ = yapf_api.FormatFile(f, style_config='pep8') self.assertCodeEqual(expected_formatted_code, formatted_code) def testDisablePartOfMultilineComment(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ if a: b # This is a multiline comment that disables YAPF. @@ -162,9 +162,9 @@ def testDisablePartOfMultilineComment(self): if h: i """) - file1 = self._MakeTempFileWithContents('testfile1.py', unformatted_code) + f = self._MakeTempFileWithContents('testfile1.py', unformatted_code) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ if a: b # This is a multiline comment that disables YAPF. @@ -175,7 +175,7 @@ def testDisablePartOfMultilineComment(self): if h: i """) - formatted_code = yapf_api.FormatFile(file1, style_config='pep8')[0] + formatted_code, _, _ = yapf_api.FormatFile(f, style_config='pep8') self.assertCodeEqual(expected_formatted_code, formatted_code) code = textwrap.dedent("""\ @@ -190,62 +190,62 @@ def foo_function(): # yapf: enable """) - file1 = self._MakeTempFileWithContents('testfile1.py', code) - formatted_code = yapf_api.FormatFile(file1, style_config='pep8')[0] + f = self._MakeTempFileWithContents('testfile1.py', code) + formatted_code, _, _ = yapf_api.FormatFile(f, style_config='pep8') self.assertCodeEqual(code, formatted_code) def testFormatFileLinesSelection(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ if a: b if f: g if h: i """) - file1 = self._MakeTempFileWithContents('testfile1.py', unformatted_code) + f = self._MakeTempFileWithContents('testfile1.py', unformatted_code) - expected_formatted_code_lines1and2 = textwrap.dedent(u"""\ + expected_formatted_code_lines1and2 = textwrap.dedent("""\ if a: b if f: g if h: i """) - formatted_code = yapf_api.FormatFile( - file1, style_config='pep8', lines=[(1, 2)])[0] + formatted_code, _, _ = yapf_api.FormatFile( + f, style_config='pep8', lines=[(1, 2)]) self.assertCodeEqual(expected_formatted_code_lines1and2, formatted_code) - expected_formatted_code_lines3 = textwrap.dedent(u"""\ + expected_formatted_code_lines3 = textwrap.dedent("""\ if a: b if f: g if h: i """) - formatted_code = yapf_api.FormatFile( - file1, style_config='pep8', lines=[(3, 3)])[0] + formatted_code, _, _ = yapf_api.FormatFile( + f, style_config='pep8', lines=[(3, 3)]) self.assertCodeEqual(expected_formatted_code_lines3, formatted_code) def testFormatFileDiff(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ if True: pass """) - file1 = self._MakeTempFileWithContents('testfile1.py', unformatted_code) - diff = yapf_api.FormatFile(file1, print_diff=True)[0] + f = self._MakeTempFileWithContents('testfile1.py', unformatted_code) + diff, _, _ = yapf_api.FormatFile(f, print_diff=True) self.assertTrue(u'+ pass' in diff) def testFormatFileInPlace(self): unformatted_code = 'True==False\n' formatted_code = 'True == False\n' - file1 = self._MakeTempFileWithContents('testfile1.py', unformatted_code) - result, _, _ = yapf_api.FormatFile(file1, in_place=True) + f = self._MakeTempFileWithContents('testfile1.py', unformatted_code) + result, _, _ = yapf_api.FormatFile(f, in_place=True) self.assertEqual(result, None) - with open(file1) as f: - self.assertCodeEqual(formatted_code, f.read()) + with open(f) as fd: + self.assertCodeEqual(formatted_code, fd.read()) self.assertRaises( - ValueError, yapf_api.FormatFile, file1, in_place=True, print_diff=True) + ValueError, yapf_api.FormatFile, f, in_place=True, print_diff=True) def testNoFile(self): stream = py3compat.StringIO() @@ -265,8 +265,8 @@ def testCommentsUnformatted(self): # quark 'two'] # yapf: disable """) - file1 = self._MakeTempFileWithContents('testfile1.py', code) - formatted_code = yapf_api.FormatFile(file1, style_config='pep8')[0] + f = self._MakeTempFileWithContents('testfile1.py', code) + formatted_code, _, _ = yapf_api.FormatFile(f, style_config='pep8') self.assertCodeEqual(code, formatted_code) def testDisabledHorizontalFormattingOnNewLine(self): @@ -276,8 +276,8 @@ def testDisabledHorizontalFormattingOnNewLine(self): 1] # yapf: enable """) - file1 = self._MakeTempFileWithContents('testfile1.py', code) - formatted_code = yapf_api.FormatFile(file1, style_config='pep8')[0] + f = self._MakeTempFileWithContents('testfile1.py', code) + formatted_code, _, _ = yapf_api.FormatFile(f, style_config='pep8') self.assertCodeEqual(code, formatted_code) def testDisabledSemiColonSeparatedStatements(self): @@ -285,8 +285,8 @@ def testDisabledSemiColonSeparatedStatements(self): # yapf: disable if True: a ; b """) - file1 = self._MakeTempFileWithContents('testfile1.py', code) - formatted_code = yapf_api.FormatFile(file1, style_config='pep8')[0] + f = self._MakeTempFileWithContents('testfile1.py', code) + formatted_code, _, _ = yapf_api.FormatFile(f, style_config='pep8') self.assertCodeEqual(code, formatted_code) def testDisabledMultilineStringInDictionary(self): @@ -304,8 +304,14 @@ def testDisabledMultilineStringInDictionary(self): }, ] """) - file1 = self._MakeTempFileWithContents('testfile1.py', code) - formatted_code = yapf_api.FormatFile(file1, style_config='chromium')[0] + f = self._MakeTempFileWithContents('testfile1.py', code) + formatted_code, _, _ = yapf_api.FormatFile(f, style_config='chromium') + self.assertCodeEqual(code, formatted_code) + + def testCRLFLineEnding(self): + code = 'class _():\r\n pass\r\n' + f = self._MakeTempFileWithContents('testfile1.py', code) + formatted_code, _, _ = yapf_api.FormatFile(f, style_config='chromium') self.assertCodeEqual(code, formatted_code) @@ -356,11 +362,11 @@ def foo(): YAPF_BINARY + ['--diff', testfile.name], stdout=outfile) def testInPlaceReformatting(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def foo(): x = 37 """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def foo(): x = 37 """) @@ -407,37 +413,38 @@ def testInPlaceReformattingEmpty(self): p = subprocess.Popen(YAPF_BINARY + ['--in-place', testfile.name]) p.wait() - with io.open(testfile.name, mode='r', newline='') as fd: + with py3compat.open_with_encoding( + testfile.name, mode='r', encoding='utf-8') as fd: reformatted_code = fd.read() self.assertEqual(reformatted_code, expected_formatted_code) def testReadFromStdin(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def foo(): x = 37 """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def foo(): x = 37 """) self.assertYapfReformats(unformatted_code, expected_formatted_code) def testReadFromStdinWithEscapedStrings(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ s = "foo\\nbar" """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ s = "foo\\nbar" """) self.assertYapfReformats(unformatted_code, expected_formatted_code) def testSetChromiumStyle(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def foo(): # trail x = 37 """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def foo(): # trail x = 37 """) @@ -447,11 +454,11 @@ def foo(): # trail extra_options=['--style=chromium']) def testSetCustomStyleBasedOnChromium(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def foo(): # trail x = 37 """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def foo(): # trail x = 37 """) @@ -470,16 +477,16 @@ def foo(): # trail extra_options=['--style={0}'.format(f.name)]) def testReadSingleLineCodeFromStdin(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ if True: pass """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ if True: pass """) self.assertYapfReformats(unformatted_code, expected_formatted_code) def testEncodingVerification(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ '''The module docstring.''' # -*- coding: utf-8 -*- def f(): @@ -495,7 +502,7 @@ def f(): YAPF_BINARY + ['--diff', testfile.name], stdout=outfile) def testReformattingSpecificLines(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass @@ -505,7 +512,7 @@ def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -525,14 +532,14 @@ def g(): extra_options=['--lines', '1-2']) def testOmitFormattingLinesBeforeDisabledFunctionComment(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ import sys # Comment def some_func(x): x = ["badly" , "formatted","line" ] """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ import sys # Comment @@ -545,7 +552,7 @@ def some_func(x): extra_options=['--lines', '5-5']) def testReformattingSkippingLines(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass @@ -556,7 +563,7 @@ def g(): pass # yapf: enable """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -572,7 +579,7 @@ def g(): self.assertYapfReformats(unformatted_code, expected_formatted_code) def testReformattingSkippingToEndOfFile(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass @@ -589,7 +596,7 @@ def e(): 'bbbbbbb'): pass """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -611,7 +618,7 @@ def e(): self.assertYapfReformats(unformatted_code, expected_formatted_code) def testReformattingSkippingSingleLine(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass @@ -620,7 +627,7 @@ def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): # yapf: disable pass """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -634,13 +641,13 @@ def g(): self.assertYapfReformats(unformatted_code, expected_formatted_code) def testDisableWholeDataStructure(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ A = set([ 'hello', 'world', ]) # yapf: disable """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ A = set([ 'hello', 'world', @@ -649,13 +656,13 @@ def testDisableWholeDataStructure(self): self.assertYapfReformats(unformatted_code, expected_formatted_code) def testDisableButAdjustIndentations(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ class SplitPenaltyTest(unittest.TestCase): def testUnbreakable(self): self._CheckPenalties(tree, [ ]) # yapf: disable """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ class SplitPenaltyTest(unittest.TestCase): def testUnbreakable(self): self._CheckPenalties(tree, [ @@ -664,7 +671,7 @@ def testUnbreakable(self): self.assertYapfReformats(unformatted_code, expected_formatted_code) def testRetainingHorizontalWhitespace(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass @@ -673,7 +680,7 @@ def g(): if (xxxxxxxxxxxx.yyyyyyyy (zzzzzzzzzzzzz [0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): # yapf: disable pass """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -687,7 +694,7 @@ def g(): self.assertYapfReformats(unformatted_code, expected_formatted_code) def testRetainingVerticalWhitespace(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass @@ -699,7 +706,7 @@ def g(): pass """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -717,7 +724,7 @@ def g(): expected_formatted_code, extra_options=['--lines', '1-2']) - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ if a: b @@ -734,7 +741,7 @@ def g(): # trailing whitespace """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ if a: b @@ -754,7 +761,7 @@ def g(): expected_formatted_code, extra_options=['--lines', '3-3', '--lines', '13-13']) - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ ''' docstring @@ -811,7 +818,7 @@ def f(): extra_options=['--lines', '1-1']) def testDisableWhenSpecifyingLines(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ # yapf: disable A = set([ 'hello', @@ -823,7 +830,7 @@ def testDisableWhenSpecifyingLines(self): 'world', ]) # yapf: disable """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ # yapf: disable A = set([ 'hello', @@ -841,7 +848,7 @@ def testDisableWhenSpecifyingLines(self): extra_options=['--lines', '1-10']) def testDisableFormattingInDataLiteral(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def horrible(): oh_god() why_would_you() @@ -860,7 +867,7 @@ def still_horrible(): 'that' ] """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def horrible(): oh_god() why_would_you() @@ -881,7 +888,7 @@ def still_horrible(): extra_options=['--lines', '14-15']) def testRetainVerticalFormattingBetweenDisabledAndEnabledLines(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ class A(object): def aaaaaaaaaaaaa(self): c = bbbbbbbbb.ccccccccc('challenge', 0, 1, 10) @@ -892,7 +899,7 @@ def aaaaaaaaaaaaa(self): gggggggggggg.hhhhhhhhh(c, c.ffffffffffff)) iiiii = jjjjjjjjjjjjjj.iiiii """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ class A(object): def aaaaaaaaaaaaa(self): c = bbbbbbbbb.ccccccccc('challenge', 0, 1, 10) @@ -907,7 +914,7 @@ def aaaaaaaaaaaaa(self): extra_options=['--lines', '4-7']) def testFormatLinesSpecifiedInMiddleOfExpression(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ class A(object): def aaaaaaaaaaaaa(self): c = bbbbbbbbb.ccccccccc('challenge', 0, 1, 10) @@ -918,7 +925,7 @@ def aaaaaaaaaaaaa(self): gggggggggggg.hhhhhhhhh(c, c.ffffffffffff)) iiiii = jjjjjjjjjjjjjj.iiiii """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ class A(object): def aaaaaaaaaaaaa(self): c = bbbbbbbbb.ccccccccc('challenge', 0, 1, 10) @@ -933,7 +940,7 @@ def aaaaaaaaaaaaa(self): extra_options=['--lines', '5-6']) def testCommentFollowingMultilineString(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def foo(): '''First line. Second line. @@ -941,7 +948,7 @@ def foo(): x = '''hello world''' # second comment return 42 # another comment """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def foo(): '''First line. Second line. @@ -956,12 +963,12 @@ def foo(): def testDedentClosingBracket(self): # no line-break on the first argument, not dedenting closing brackets - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def overly_long_function_name(first_argument_on_the_same_line, second_argument_makes_the_line_too_long): pass """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def overly_long_function_name(first_argument_on_the_same_line, second_argument_makes_the_line_too_long): pass @@ -979,19 +986,19 @@ def overly_long_function_name(first_argument_on_the_same_line, # extra_options=['--style=facebook']) # line-break before the first argument, dedenting closing brackets if set - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def overly_long_function_name( first_argument_on_the_same_line, second_argument_makes_the_line_too_long): pass """) - expected_formatted_pep8_code = textwrap.dedent(u"""\ + expected_formatted_pep8_code = textwrap.dedent("""\ def overly_long_function_name( first_argument_on_the_same_line, \ second_argument_makes_the_line_too_long): pass """) - expected_formatted_fb_code = textwrap.dedent(u"""\ + expected_formatted_fb_code = textwrap.dedent("""\ def overly_long_function_name( first_argument_on_the_same_line, second_argument_makes_the_line_too_long ): @@ -1009,12 +1016,12 @@ def overly_long_function_name( # extra_options=['--style=pep8']) def testCoalesceBrackets(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ some_long_function_name_foo({ 'first_argument_of_the_thing': id, 'second_argument_of_the_thing': "some thing"} )""") - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ some_long_function_name_foo({ 'first_argument_of_the_thing': id, 'second_argument_of_the_thing': "some thing" @@ -1035,12 +1042,12 @@ def testCoalesceBrackets(self): extra_options=['--style={0}'.format(f.name)]) def testPseudoParenSpaces(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def foo(): def bar(): return {msg_id: author for author, msg_id in reader} """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def foo(): def bar(): return {msg_id: author for author, msg_id in reader} @@ -1051,7 +1058,7 @@ def bar(): extra_options=['--lines', '1-1', '--style', 'chromium']) def testMultilineCommentFormattingDisabled(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ # This is a comment FOO = { aaaaaaaa.ZZZ: [ @@ -1065,7 +1072,7 @@ def testMultilineCommentFormattingDisabled(self): '#': lambda x: x # do nothing } """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ # This is a comment FOO = { aaaaaaaa.ZZZ: [ @@ -1085,14 +1092,14 @@ def testMultilineCommentFormattingDisabled(self): extra_options=['--lines', '1-1', '--style', 'chromium']) def testTrailingCommentsWithDisabledFormatting(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ import os SCOPES = [ 'hello world' # This is a comment. ] """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ import os SCOPES = [ @@ -1105,12 +1112,12 @@ def testTrailingCommentsWithDisabledFormatting(self): extra_options=['--lines', '1-1', '--style', 'chromium']) def testUseTabs(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def foo_function(): if True: pass """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def foo_function(): if True: pass @@ -1153,11 +1160,11 @@ def _Check(self, unformatted_code, expected_formatted_code): self.assertEqual(expected_formatted_code, formatted_code) def testSimple(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ for i in range(5): print('bar') """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ for i in range(5): print('bar') """) From 49443fa8a405f4ff76ebc2ff006a2a14762fd298 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 16 Oct 2016 22:54:01 -0700 Subject: [PATCH 050/719] Bump version to v0.13.0 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- yapf/yapflib/file_resources.py | 28 +++++++++++++++------------- yapf/yapflib/py3compat.py | 1 + yapf/yapflib/yapf_api.py | 7 ++++--- 5 files changed, 22 insertions(+), 18 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8bc23fda8..8964ae64f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.13.0] UNRELEASED +## [0.13.0] 2016-10-16 ### Added - Added support to retain the original line endings of the source code. diff --git a/yapf/__init__.py b/yapf/__init__.py index 750587767..9b800bcfe 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.12.2' +__version__ = '0.13.0' def main(argv): diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 1671706af..599c80373 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -27,7 +27,6 @@ from yapf.yapflib import py3compat from yapf.yapflib import style - CR = '\r' LF = '\n' CRLF = '\r\n' @@ -77,8 +76,11 @@ def GetCommandLineFiles(command_line_file_list, recursive, exclude): return _FindPythonFiles(command_line_file_list, recursive, exclude) -def WriteReformattedCode(filename, reformatted_code, newline=os.linesep, - in_place=False, encoding=''): +def WriteReformattedCode(filename, + reformatted_code, + newline=os.linesep, + in_place=False, + encoding=''): """Emit the reformatted code. Write the reformatted code into the file, if in_place is True. Otherwise, @@ -100,16 +102,16 @@ def WriteReformattedCode(filename, reformatted_code, newline=os.linesep, def LineEnding(lines): - """Retrieve the line ending of the original source.""" - endings = {CRLF: 0, CR: 0, LF: 0} - for line in lines: - if line.endswith(CRLF): - endings[CRLF] += 1 - elif line.endswith(CR): - endings[CR] += 1 - elif line.endswith(LF): - endings[LF] += 1 - return (sorted(endings, key=endings.get, reverse=True) or [LF])[0] + """Retrieve the line ending of the original source.""" + endings = {CRLF: 0, CR: 0, LF: 0} + for line in lines: + if line.endswith(CRLF): + endings[CRLF] += 1 + elif line.endswith(CR): + endings[CR] += 1 + elif line.endswith(LF): + endings[LF] += 1 + return (sorted(endings, key=endings.get, reverse=True) or [LF])[0] def _FindPythonFiles(filenames, recursive, exclude): diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py index a888aa15e..a981d439b 100644 --- a/yapf/yapflib/py3compat.py +++ b/yapf/yapflib/py3compat.py @@ -23,6 +23,7 @@ BytesIO = io.BytesIO import codecs + def open_with_encoding(filename, mode, encoding, newline=''): return codecs.open(filename, mode=mode, encoding=encoding) diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 2e41b2b2c..def49c2a1 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -93,8 +93,8 @@ def FormatFile(filename, reformatted_source = newline.join(line for line in lines) + newline if in_place: if original_source and original_source != reformatted_source: - file_resources.WriteReformattedCode(filename, reformatted_source, - newline, in_place, encoding) + file_resources.WriteReformattedCode(filename, reformatted_source, newline, + in_place, encoding) return None, encoding, changed return reformatted_source, encoding, changed @@ -235,7 +235,8 @@ def _MarkLinesToFormat(uwlines, lines): while index < len(uwlines): if uwlines[index].lineno > end: break - if uwlines[index].lineno >= start or uwlines[index].last.lineno >= start: + if (uwlines[index].lineno >= start or + uwlines[index].last.lineno >= start): uwlines[index].disable = False index += 1 From 12a71bef2fdb2476afa0a82045b4fb4c3a530e1f Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 16 Oct 2016 23:28:44 -0700 Subject: [PATCH 051/719] Remove unused arguments. --- yapf/yapflib/file_resources.py | 2 -- yapf/yapflib/py3compat.py | 2 +- yapf/yapflib/yapf_api.py | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 599c80373..dab68ca3d 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -78,7 +78,6 @@ def GetCommandLineFiles(command_line_file_list, recursive, exclude): def WriteReformattedCode(filename, reformatted_code, - newline=os.linesep, in_place=False, encoding=''): """Emit the reformatted code. @@ -89,7 +88,6 @@ def WriteReformattedCode(filename, Arguments: filename: (unicode) The name of the unformatted file. reformatted_code: (unicode) The reformatted code. - newline: (unicode) The original line ending of the source file. in_place: (bool) If True, then write the reformatted code to the file. encoding: (unicode) The encoding of the file. """ diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py index a981d439b..81d4847ce 100644 --- a/yapf/yapflib/py3compat.py +++ b/yapf/yapflib/py3compat.py @@ -24,7 +24,7 @@ import codecs - def open_with_encoding(filename, mode, encoding, newline=''): + def open_with_encoding(filename, mode, encoding, newline=''): # pylint: disable=unused-argument return codecs.open(filename, mode=mode, encoding=encoding) import functools diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index def49c2a1..acfbb825f 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -93,7 +93,7 @@ def FormatFile(filename, reformatted_source = newline.join(line for line in lines) + newline if in_place: if original_source and original_source != reformatted_source: - file_resources.WriteReformattedCode(filename, reformatted_source, newline, + file_resources.WriteReformattedCode(filename, reformatted_source, in_place, encoding) return None, encoding, changed From 5e54f88ea42983886def00eebebf08a388a98809 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 17 Oct 2016 14:26:41 -0700 Subject: [PATCH 052/719] Output the formatting diff Closes #324 --- CHANGELOG | 4 ++++ yapf/__init__.py | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 8964ae64f..3785f3b79 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.13.1] 2016-10-17 +### Fixed +- Correct emitting a diff that was accidentally removed. + ## [0.13.0] 2016-10-16 ### Added - Added support to retain the original line endings of the source code. diff --git a/yapf/__init__.py b/yapf/__init__.py index 9b800bcfe..2650e7702 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -211,7 +211,7 @@ def FormatFiles(filenames, style_config = ( file_resources.GetDefaultStyleForDir(os.path.dirname(filename))) try: - yapf_api.FormatFile( + reformatted_code, encoding, _ = yapf_api.FormatFile( filename, in_place=in_place, style_config=style_config, @@ -219,6 +219,9 @@ def FormatFiles(filenames, print_diff=print_diff, verify=verify, logger=logging.warning) + if not in_place and reformatted_code: + file_resources.WriteReformattedCode(filename, reformatted_code, + in_place, encoding) except SyntaxError as e: e.filename = filename raise From 9df4aec8f86573d1bb475ed4c97d079c4b996af9 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 17 Oct 2016 14:40:23 -0700 Subject: [PATCH 053/719] Bump version to v0.13.1 --- yapf/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 2650e7702..a46555162 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.13.0' +__version__ = '0.13.1' def main(argv): From b5d19bcf8705100a9f55cb83fffe8065e8aa2236 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 22 Oct 2016 01:18:51 -0700 Subject: [PATCH 054/719] Don't count newlines as part of cmt prefix indent Closes #327 --- CHANGELOG | 6 ++++++ yapf/yapflib/comment_splicer.py | 2 ++ yapftests/reformatter_test.py | 17 +++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 3785f3b79..c1f63c54b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,12 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.13.2] 2016-10-22 +### Fixed +- REGRESSION: A comment may have a prefix with newlines in it. When calculating + the prefix indent, we cannot take the newlines into account. Otherwise, the + comment will be misplaced causing the code to fail. + ## [0.13.1] 2016-10-17 ### Fixed - Correct emitting a diff that was accidentally removed. diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index 2ff3053e1..1759bf787 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -61,6 +61,8 @@ def _VisitNodeRec(node): # child in the next iteration... child_prefix = child.prefix.lstrip('\n') prefix_indent = child_prefix[:child_prefix.find('#')] + if '\n' in prefix_indent: + prefix_indent = prefix_indent[prefix_indent.find('\n') + 1:] child.prefix = '' if child.type == token.NEWLINE: diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index 4e5d0bfa5..bff7a4a76 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -4056,6 +4056,23 @@ def _pack_results_for_constraint_or(cls, combination, constraints): reformatted_code = reformatter.Reformat(uwlines) self.assertCodeEqual(code, reformatted_code) + def testCommentWithNewlinesInPrefix(self): + code = textwrap.dedent("""\ + def foo(): + if 0: + return False + + #a deadly comment + elif 1: + return True + + + print(foo()) + """) + uwlines = _ParseAndUnwrap(code) + reformatted_code = reformatter.Reformat(uwlines) + self.assertCodeEqual(code, reformatted_code) + def _ParseAndUnwrap(code, dumptree=False): """Produces unwrapped lines from the given code. From 22f532a1fd5f34696f77125857725f405091a1c2 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 22 Oct 2016 01:20:11 -0700 Subject: [PATCH 055/719] Bump version to v0.13.2 --- yapf/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index a46555162..5f0dce13a 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.13.1' +__version__ = '0.13.2' def main(argv): From 734b692728b5b377ca2c1aebe4804e83a59ed988 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 23 Oct 2016 02:10:01 -0700 Subject: [PATCH 056/719] Split out reformatter tests into modules --- yapftests/reformatter_basic_test.py | 1946 ++++++++++ yapftests/reformatter_buganizer_test.py | 1215 ++++++ yapftests/reformatter_facebook_test.py | 396 ++ yapftests/reformatter_pep8_test.py | 301 ++ yapftests/reformatter_python3_test.py | 167 + yapftests/reformatter_style_config_test.py | 61 + yapftests/reformatter_test.py | 4026 +------------------- yapftests/reformatter_verify_test.py | 111 + 8 files changed, 4199 insertions(+), 4024 deletions(-) create mode 100644 yapftests/reformatter_basic_test.py create mode 100644 yapftests/reformatter_buganizer_test.py create mode 100644 yapftests/reformatter_facebook_test.py create mode 100644 yapftests/reformatter_pep8_test.py create mode 100644 yapftests/reformatter_python3_test.py create mode 100644 yapftests/reformatter_style_config_test.py create mode 100644 yapftests/reformatter_verify_test.py diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py new file mode 100644 index 000000000..edf9b3d8f --- /dev/null +++ b/yapftests/reformatter_basic_test.py @@ -0,0 +1,1946 @@ +# Copyright 2015-2016 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Basic tests for yapf.reformatter.""" + +import textwrap +import unittest + +from yapf.yapflib import pytree_utils +from yapf.yapflib import reformatter +from yapf.yapflib import style +from yapf.yapflib import verifier + +from yapftests import reformatter_test + + +class BasicReformatterTest(reformatter_test.ReformatterTest): + + @classmethod + def setUpClass(cls): + style.SetGlobalStyle(style.CreateChromiumStyle()) + + def testSimple(self): + unformatted_code = textwrap.dedent("""\ + if a+b: + pass + """) + expected_formatted_code = textwrap.dedent("""\ + if a + b: + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSimpleFunctions(self): + unformatted_code = textwrap.dedent("""\ + def g(): + pass + + def f(): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def g(): + pass + + + def f(): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSimpleFunctionsWithTrailingComments(self): + unformatted_code = textwrap.dedent("""\ + def g(): # Trailing comment + if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and + xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): + pass + + def f( # Intermediate comment + ): + if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and + xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def g(): # Trailing comment + if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and + xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): + pass + + + def f( # Intermediate comment + ): + if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and + xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testBlankLinesAtEndOfFile(self): + unformatted_code = textwrap.dedent("""\ + def foobar(): # foo + pass + + + + """) + expected_formatted_code = textwrap.dedent("""\ + def foobar(): # foo + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + unformatted_code = textwrap.dedent("""\ + x = { 'a':37,'b':42, + + 'c':927} + + """) + expected_formatted_code = textwrap.dedent("""\ + x = {'a': 37, 'b': 42, 'c': 927} + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testMultipleUgliness(self): + unformatted_code = textwrap.dedent("""\ + x = { 'a':37,'b':42, + + 'c':927} + + y = 'hello ''world' + z = 'hello '+'world' + a = 'hello {}'.format('world') + class foo ( object ): + def f (self ): + return 37*-+2 + def g(self, x,y=42): + return y + def f ( a ) : + return 37+-+a[42-x : y**3] + """) + expected_formatted_code = textwrap.dedent("""\ + x = {'a': 37, 'b': 42, 'c': 927} + + y = 'hello ' 'world' + z = 'hello ' + 'world' + a = 'hello {}'.format('world') + + + class foo(object): + + def f(self): + return 37 * -+2 + + def g(self, x, y=42): + return y + + + def f(a): + return 37 + -+a[42 - x:y**3] + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testComments(self): + unformatted_code = textwrap.dedent("""\ + class Foo(object): + pass + + # Attached comment + class Bar(object): + pass + + global_assignment = 42 + + # Comment attached to class with decorator. + # Comment attached to class with decorator. + @noop + @noop + class Baz(object): + pass + + # Intermediate comment + + class Qux(object): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + class Foo(object): + pass + + + # Attached comment + class Bar(object): + pass + + + global_assignment = 42 + + + # Comment attached to class with decorator. + # Comment attached to class with decorator. + @noop + @noop + class Baz(object): + pass + + + # Intermediate comment + + + class Qux(object): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSingleComment(self): + code = textwrap.dedent("""\ + # Thing 1 + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testCommentsInDataLiteral(self): + code = textwrap.dedent("""\ + def f(): + return collections.OrderedDict({ + # First comment. + 'fnord': 37, + + # Second comment. + # Continuation of second comment. + 'bork': 42, + + # Ending comment. + }) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testEndingWhitespaceAfterSimpleStatement(self): + code = textwrap.dedent("""\ + import foo as bar + # Thing 1 + # Thing 2 + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testDocstrings(self): + unformatted_code = textwrap.dedent('''\ + u"""Module-level docstring.""" + import os + class Foo(object): + + """Class-level docstring.""" + # A comment for qux. + def qux(self): + + + """Function-level docstring. + + A multiline function docstring. + """ + print('hello {}'.format('world')) + return 42 + ''') + expected_formatted_code = textwrap.dedent('''\ + u"""Module-level docstring.""" + import os + + + class Foo(object): + """Class-level docstring.""" + + # A comment for qux. + def qux(self): + """Function-level docstring. + + A multiline function docstring. + """ + print('hello {}'.format('world')) + return 42 + ''') + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testDocstringAndMultilineComment(self): + unformatted_code = textwrap.dedent('''\ + """Hello world""" + # A multiline + # comment + class bar(object): + """class docstring""" + # class multiline + # comment + def foo(self): + """Another docstring.""" + # Another multiline + # comment + pass + ''') + expected_formatted_code = textwrap.dedent('''\ + """Hello world""" + + + # A multiline + # comment + class bar(object): + """class docstring""" + + # class multiline + # comment + def foo(self): + """Another docstring.""" + # Another multiline + # comment + pass + ''') + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testMultilineDocstringAndMultilineComment(self): + unformatted_code = textwrap.dedent('''\ + """Hello world + + RIP Dennis Richie. + """ + # A multiline + # comment + class bar(object): + """class docstring + + A classy class. + """ + # class multiline + # comment + def foo(self): + """Another docstring. + + A functional function. + """ + # Another multiline + # comment + pass + ''') + expected_formatted_code = textwrap.dedent('''\ + """Hello world + + RIP Dennis Richie. + """ + + + # A multiline + # comment + class bar(object): + """class docstring + + A classy class. + """ + + # class multiline + # comment + def foo(self): + """Another docstring. + + A functional function. + """ + # Another multiline + # comment + pass + ''') + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testTupleCommaBeforeLastParen(self): + unformatted_code = textwrap.dedent("""\ + a = ( 1, ) + """) + expected_formatted_code = textwrap.dedent("""\ + a = (1,) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testNoBreakOutsideOfBracket(self): + # FIXME(morbo): How this is formatted is not correct. But it's syntactically + # correct. + unformatted_code = textwrap.dedent("""\ + def f(): + assert port >= minimum, \ +'Unexpected port %d when minimum was %d.' % (port, minimum) + """) + expected_formatted_code = textwrap.dedent("""\ + def f(): + assert port >= minimum, 'Unexpected port %d when minimum was %d.' % (port, + minimum) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testBlankLinesBeforeDecorators(self): + unformatted_code = textwrap.dedent("""\ + @foo() + class A(object): + @bar() + @baz() + def x(self): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + @foo() + class A(object): + + @bar() + @baz() + def x(self): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testCommentBetweenDecorators(self): + unformatted_code = textwrap.dedent("""\ + @foo() + # frob + @bar + def x (self): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + @foo() + # frob + @bar + def x(self): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testListComprehension(self): + unformatted_code = textwrap.dedent("""\ + def given(y): + [k for k in () + if k in y] + """) + expected_formatted_code = textwrap.dedent("""\ + def given(y): + [k for k in () if k in y] + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testOpeningAndClosingBrackets(self): + unformatted_code = textwrap.dedent("""\ + foo( ( 1, 2, 3, ) ) + """) + expected_formatted_code = textwrap.dedent("""\ + foo(( + 1, + 2, + 3,)) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSingleLineFunctions(self): + unformatted_code = textwrap.dedent("""\ + def foo(): return 42 + """) + expected_formatted_code = textwrap.dedent("""\ + def foo(): + return 42 + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testNoQueueSeletionInMiddleOfLine(self): + # If the queue isn't properly consttructed, then a token in the middle of + # the line may be selected as the one with least penalty. The tokens after + # that one are then splatted at the end of the line with no formatting. + # FIXME(morbo): The formatting here isn't ideal. + unformatted_code = textwrap.dedent("""\ + find_symbol(node.type) + "< " + " ".join(find_pattern(n) for n in \ +node.child) + " >" + """) + expected_formatted_code = textwrap.dedent("""\ + find_symbol(node.type) + "< " + " ".join(find_pattern(n) + for n in node.child) + " >" + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testNoSpacesBetweenSubscriptsAndCalls(self): + unformatted_code = textwrap.dedent("""\ + aaaaaaaaaa = bbbbbbbb.ccccccccc() [42] (a, 2) + """) + expected_formatted_code = textwrap.dedent("""\ + aaaaaaaaaa = bbbbbbbb.ccccccccc()[42](a, 2) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testNoSpacesBetweenOpeningBracketAndStartingOperator(self): + # Unary operator. + unformatted_code = textwrap.dedent("""\ + aaaaaaaaaa = bbbbbbbb.ccccccccc[ -1 ]( -42 ) + """) + expected_formatted_code = textwrap.dedent("""\ + aaaaaaaaaa = bbbbbbbb.ccccccccc[-1](-42) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + # Varargs and kwargs. + unformatted_code = textwrap.dedent("""\ + aaaaaaaaaa = bbbbbbbb.ccccccccc( *varargs ) + aaaaaaaaaa = bbbbbbbb.ccccccccc( **kwargs ) + """) + expected_formatted_code = textwrap.dedent("""\ + aaaaaaaaaa = bbbbbbbb.ccccccccc(*varargs) + aaaaaaaaaa = bbbbbbbb.ccccccccc(**kwargs) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testMultilineCommentReformatted(self): + unformatted_code = textwrap.dedent("""\ + if True: + # This is a multiline + # comment. + pass + """) + expected_formatted_code = textwrap.dedent("""\ + if True: + # This is a multiline + # comment. + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testDictionaryMakerFormatting(self): + unformatted_code = textwrap.dedent("""\ + _PYTHON_STATEMENTS = frozenset({ + lambda x, y: 'simple_stmt': 'small_stmt', 'expr_stmt': 'print_stmt', 'del_stmt': + 'pass_stmt', lambda: 'break_stmt': 'continue_stmt', 'return_stmt': 'raise_stmt', + 'yield_stmt': 'import_stmt', lambda: 'global_stmt': 'exec_stmt', 'assert_stmt': + 'if_stmt', 'while_stmt': 'for_stmt', + }) + """) + expected_formatted_code = textwrap.dedent("""\ + _PYTHON_STATEMENTS = frozenset({ + lambda x, y: 'simple_stmt': 'small_stmt', + 'expr_stmt': 'print_stmt', + 'del_stmt': 'pass_stmt', + lambda: 'break_stmt': 'continue_stmt', + 'return_stmt': 'raise_stmt', + 'yield_stmt': 'import_stmt', + lambda: 'global_stmt': 'exec_stmt', + 'assert_stmt': 'if_stmt', + 'while_stmt': 'for_stmt', + }) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSimpleMultilineCode(self): + unformatted_code = textwrap.dedent("""\ + if True: + aaaaaaaaaaaaaa.bbbbbbbbbbbbbb.ccccccc(zzzzzzzzzzzz, \ +xxxxxxxxxxx, yyyyyyyyyyyy, vvvvvvvvv) + aaaaaaaaaaaaaa.bbbbbbbbbbbbbb.ccccccc(zzzzzzzzzzzz, \ +xxxxxxxxxxx, yyyyyyyyyyyy, vvvvvvvvv) + """) + expected_formatted_code = textwrap.dedent("""\ + if True: + aaaaaaaaaaaaaa.bbbbbbbbbbbbbb.ccccccc(zzzzzzzzzzzz, xxxxxxxxxxx, yyyyyyyyyyyy, + vvvvvvvvv) + aaaaaaaaaaaaaa.bbbbbbbbbbbbbb.ccccccc(zzzzzzzzzzzz, xxxxxxxxxxx, yyyyyyyyyyyy, + vvvvvvvvv) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testMultilineComment(self): + code = textwrap.dedent("""\ + if Foo: + # Hello world + # Yo man. + # Yo man. + # Yo man. + # Yo man. + a = 42 + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testMultilineString(self): + code = textwrap.dedent("""\ + code = textwrap.dedent('''\ + if Foo: + # Hello world + # Yo man. + # Yo man. + # Yo man. + # Yo man. + a = 42 + ''') + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + unformatted_code = textwrap.dedent('''\ + def f(): + email_text += """This is a really long docstring that goes over the column limit and is multi-line.

+ Czar: """+despot["Nicholas"]+"""
+ Minion: """+serf["Dmitri"]+"""
+ Residence: """+palace["Winter"]+"""
+ + """ + ''') + expected_formatted_code = textwrap.dedent('''\ + def f(): + email_text += """This is a really long docstring that goes over the column limit and is multi-line.

+ Czar: """ + despot["Nicholas"] + """
+ Minion: """ + serf["Dmitri"] + """
+ Residence: """ + palace["Winter"] + """
+ + """ + ''') + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSimpleMultilineWithComments(self): + code = textwrap.dedent("""\ + if ( # This is the first comment + a and # This is the second comment + # This is the third comment + b): # A trailing comment + # Whoa! A normal comment!! + pass # Another trailing comment + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testMatchingParenSplittingMatching(self): + unformatted_code = textwrap.dedent("""\ + def f(): + raise RuntimeError('unable to find insertion point for target node', + (target,)) + """) + expected_formatted_code = textwrap.dedent("""\ + def f(): + raise RuntimeError('unable to find insertion point for target node', + (target,)) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testContinuationIndent(self): + unformatted_code = textwrap.dedent('''\ + class F: + def _ProcessArgLists(self, node): + """Common method for processing argument lists.""" + for child in node.children: + if isinstance(child, pytree.Leaf): + self._SetTokenSubtype( + child, subtype=_ARGLIST_TOKEN_TO_SUBTYPE.get( + child.value, format_token.Subtype.NONE)) + ''') + expected_formatted_code = textwrap.dedent('''\ + class F: + + def _ProcessArgLists(self, node): + """Common method for processing argument lists.""" + for child in node.children: + if isinstance(child, pytree.Leaf): + self._SetTokenSubtype( + child, + subtype=_ARGLIST_TOKEN_TO_SUBTYPE.get(child.value, + format_token.Subtype.NONE)) + ''') + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testTrailingCommaAndBracket(self): + unformatted_code = textwrap.dedent('''\ + a = { 42, } + b = ( 42, ) + c = [ 42, ] + ''') + expected_formatted_code = textwrap.dedent('''\ + a = {42,} + b = (42,) + c = [42,] + ''') + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testI18n(self): + code = textwrap.dedent("""\ + N_('Some years ago - never mind how long precisely - having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world.') # A comment is here. + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + code = textwrap.dedent("""\ + foo('Fake function call') #. Some years ago - never mind how long precisely - having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testI18nCommentsInDataLiteral(self): + code = textwrap.dedent("""\ + def f(): + return collections.OrderedDict({ + #. First i18n comment. + 'bork': 'foo', + + #. Second i18n comment. + 'snork': 'bar#.*=\\\\0', + }) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testClosingBracketIndent(self): + code = textwrap.dedent('''\ + def f(): + + def g(): + while ( + xxxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz]) == 'aaaaaaaaaaa' and + xxxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): + pass + ''') + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testClosingBracketsInlinedInCall(self): + unformatted_code = textwrap.dedent("""\ + class Foo(object): + + def bar(self): + self.aaaaaaaa = xxxxxxxxxxxxxxxxxxx.yyyyyyyyyyyyy( + self.cccccc.ddddddddd.eeeeeeee, + options={ + "forkforkfork": 1, + "borkborkbork": 2, + "corkcorkcork": 3, + "horkhorkhork": 4, + "porkporkpork": 5, + }) + """) + expected_formatted_code = textwrap.dedent("""\ + class Foo(object): + + def bar(self): + self.aaaaaaaa = xxxxxxxxxxxxxxxxxxx.yyyyyyyyyyyyy( + self.cccccc.ddddddddd.eeeeeeee, + options={ + "forkforkfork": 1, + "borkborkbork": 2, + "corkcorkcork": 3, + "horkhorkhork": 4, + "porkporkpork": 5, + }) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testLineWrapInForExpression(self): + code = textwrap.dedent("""\ + class A: + + def x(self, node, name, n=1): + for i, child in enumerate( + itertools.ifilter(lambda c: pytree_utils.NodeName(c) == name, + node.pre_order())): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testFunctionCallContinuationLine(self): + code = textwrap.dedent("""\ + class foo: + + def bar(self, node, name, n=1): + if True: + if True: + return [(aaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb( + cccc, ddddddddddddddddddddddddddddddddddddd))] + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testI18nNonFormatting(self): + code = textwrap.dedent("""\ + class F(object): + + def __init__(self, fieldname, + #. Error message indicating an invalid e-mail address. + message=N_('Please check your email address.'), **kwargs): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testNoSpaceBetweenUnaryOpAndOpeningParen(self): + code = textwrap.dedent("""\ + if ~(a or b): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testCommentBeforeFuncDef(self): + code = textwrap.dedent("""\ + class Foo(object): + + a = 42 + + # This is a comment. + def __init__(self, + xxxxxxx, + yyyyy=0, + zzzzzzz=None, + aaaaaaaaaaaaaaaaaa=False, + bbbbbbbbbbbbbbb=False): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testExcessLineCountWithDefaultKeywords(self): + unformatted_code = textwrap.dedent("""\ + class Fnord(object): + def Moo(self): + aaaaaaaaaaaaaaaa = self._bbbbbbbbbbbbbbbbbbbbbbb( + ccccccccccccc=ccccccccccccc, ddddddd=ddddddd, eeee=eeee, + fffff=fffff, ggggggg=ggggggg, hhhhhhhhhhhhh=hhhhhhhhhhhhh, + iiiiiii=iiiiiiiiiiiiii) + """) + expected_formatted_code = textwrap.dedent("""\ + class Fnord(object): + + def Moo(self): + aaaaaaaaaaaaaaaa = self._bbbbbbbbbbbbbbbbbbbbbbb( + ccccccccccccc=ccccccccccccc, + ddddddd=ddddddd, + eeee=eeee, + fffff=fffff, + ggggggg=ggggggg, + hhhhhhhhhhhhh=hhhhhhhhhhhhh, + iiiiiii=iiiiiiiiiiiiii) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSpaceAfterNotOperator(self): + code = textwrap.dedent("""\ + if not (this and that): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testNoPenaltySplitting(self): + code = textwrap.dedent("""\ + def f(): + if True: + if True: + python_files.extend( + os.path.join(filename, f) for f in os.listdir(filename) + if IsPythonFile(os.path.join(filename, f))) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testExpressionPenalties(self): + code = textwrap.dedent("""\ + def f(): + if ((left.value == '(' and right.value == ')') or + (left.value == '[' and right.value == ']') or + (left.value == '{' and right.value == '}')): + return False + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testLineDepthOfSingleLineStatement(self): + unformatted_code = textwrap.dedent("""\ + while True: continue + for x in range(3): continue + try: a = 42 + except: b = 42 + with open(a) as fd: a = fd.read() + """) + expected_formatted_code = textwrap.dedent("""\ + while True: + continue + for x in range(3): + continue + try: + a = 42 + except: + b = 42 + with open(a) as fd: + a = fd.read() + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSplitListWithTerminatingComma(self): + unformatted_code = textwrap.dedent("""\ + FOO = ['bar', 'baz', 'mux', 'qux', 'quux', 'quuux', 'quuuux', + 'quuuuux', 'quuuuuux', 'quuuuuuux', lambda a, b: 37,] + """) + expected_formatted_code = textwrap.dedent("""\ + FOO = [ + 'bar', + 'baz', + 'mux', + 'qux', + 'quux', + 'quuux', + 'quuuux', + 'quuuuux', + 'quuuuuux', + 'quuuuuuux', + lambda a, b: 37, + ] + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSplitListWithInterspersedComments(self): + code = textwrap.dedent("""\ + FOO = [ + 'bar', # bar + 'baz', # baz + 'mux', # mux + 'qux', # qux + 'quux', # quux + 'quuux', # quuux + 'quuuux', # quuuux + 'quuuuux', # quuuuux + 'quuuuuux', # quuuuuux + 'quuuuuuux', # quuuuuuux + lambda a, b: 37 # lambda + ] + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testRelativeImportStatements(self): + code = textwrap.dedent("""\ + from ... import bork + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testSingleLineList(self): + # A list on a single line should prefer to remain contiguous. + unformatted_code = textwrap.dedent("""\ + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = aaaaaaaaaaa( + ("...", "."), "..", + ".............................................." + ) + """) + expected_formatted_code = textwrap.dedent("""\ + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = aaaaaaaaaaa( + ("...", "."), "..", "..............................................") + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testBlankLinesBeforeFunctionsNotInColumnZero(self): + unformatted_code = textwrap.dedent("""\ + import signal + + + try: + signal.SIGALRM + # .................................................................. + # ............................................................... + + + def timeout(seconds=1): + pass + except: + pass + """) + expected_formatted_code = textwrap.dedent("""\ + import signal + + try: + signal.SIGALRM + + # .................................................................. + # ............................................................... + + + def timeout(seconds=1): + pass + except: + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testNoKeywordArgumentBreakage(self): + code = textwrap.dedent("""\ + class A(object): + + def b(self): + if self.aaaaaaaaaaaaaaaaaaaa not in self.bbbbbbbbbb( + cccccccccccccccccccc=True): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testTrailerOnSingleLine(self): + code = textwrap.dedent("""\ + urlpatterns = patterns('', + url(r'^$', 'homepage_view'), + url(r'^/login/$', 'login_view'), + url(r'^/login/$', 'logout_view'), + url(r'^/user/(?P\\w+)/$', 'profile_view')) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testIfConditionalParens(self): + code = textwrap.dedent("""\ + class Foo: + + def bar(): + if True: + if (child.type == grammar_token.NAME and + child.value in substatement_names): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testContinuationMarkers(self): + code = textwrap.dedent("""\ + text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. "\\ + "Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur "\\ + "ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis "\\ + "sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. "\\ + "Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet" + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + code = textwrap.dedent("""\ + from __future__ import nested_scopes, generators, division, absolute_import, with_statement, \\ + print_function, unicode_literals + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + code = textwrap.dedent("""\ + if aaaaaaaaa == 42 and bbbbbbbbbbbbbb == 42 and \\ + cccccccc == 42: + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testCommentsWithContinuationMarkers(self): + code = textwrap.dedent("""\ + def fn(arg): + v = fn2(key1=True, + #c1 + key2=arg)\\ + .fn3() + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testEmptyContainers(self): + code = textwrap.dedent("""\ + flags.DEFINE_list( + 'output_dirs', [], + 'Lorem ipsum dolor sit amet, consetetur adipiscing elit. Donec a diam lectus. ' + 'Sed sit amet ipsum mauris. Maecenas congue.') + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testSplitStringsIfSurroundedByParens(self): + unformatted_code = textwrap.dedent("""\ + a = foo.bar({'xxxxxxxxxxxxxxxxxxxxxxx' 'yyyyyyyyyyyyyyyyyyyyyyyyyy': baz[42]} + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbb' 'cccccccccccccccccccccccccccccccc' 'ddddddddddddddddddddddddddddd') + """) + expected_formatted_code = textwrap.dedent("""\ + a = foo.bar({ + 'xxxxxxxxxxxxxxxxxxxxxxx' + 'yyyyyyyyyyyyyyyyyyyyyyyyyy': baz[42] + } + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + 'bbbbbbbbbbbbbbbbbbbbbbbbbb' + 'cccccccccccccccccccccccccccccccc' + 'ddddddddddddddddddddddddddddd') + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + code = textwrap.dedent("""\ + a = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' \ +'bbbbbbbbbbbbbbbbbbbbbbbbbb' 'cccccccccccccccccccccccccccccccc' \ +'ddddddddddddddddddddddddddddd' + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testMultilineShebang(self): + code = textwrap.dedent("""\ + #!/bin/sh + if "true" : '''\' + then + + export FOO=123 + exec /usr/bin/env python "$0" "$@" + + exit 127 + fi + ''' + + import os + + assert os.environ['FOO'] == '123' + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testNoSplittingAroundTermOperators(self): + code = textwrap.dedent("""\ + a_very_long_function_call_yada_yada_etc_etc_etc(long_arg1, + long_arg2 / long_arg3) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testNoSplittingWithinSubscriptList(self): + code = textwrap.dedent("""\ + somequitelongvariablename.somemember[(a, b)] = { + 'somelongkey': 1, + 'someotherlongkey': 2 + } + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testExcessCharacters(self): + code = textwrap.dedent("""\ + class foo: + + def bar(self): + self.write(s=[ + '%s%s %s' % ('many of really', 'long strings', '+ just makes up 81') + ]) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testDictSetGenerator(self): + code = textwrap.dedent("""\ + foo = { + variable: 'hello world. How are you today?' + for variable in fnord if variable != 37 + } + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testUnaryOpInDictionaryValue(self): + code = textwrap.dedent("""\ + beta = "123" + + test = {'alpha': beta[-1]} + + print(beta[-1]) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testUnaryNotOperator(self): + code = textwrap.dedent("""\ + if True: + if True: + if True: + if True: + remote_checksum = self.get_checksum(conn, tmp, dest, inject, + not directory_prepended, source) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testRelaxArraySubscriptAffinity(self): + code = textwrap.dedent("""\ + class A(object): + + def f(self, aaaaaaaaa, bbbbbbbbbbbbb, row): + if True: + if True: + if True: + if True: + if row[4] is None or row[5] is None: + bbbbbbbbbbbbb['..............'] = row[5] if row[ + 5] is not None else 5 + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testFunctionCallInDict(self): + code = "a = {'a': b(c=d, **e)}\n" + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testFunctionCallInNestedDict(self): + code = "a = {'a': {'a': {'a': b(c=d, **e)}}}\n" + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testUnbreakableNot(self): + code = textwrap.dedent("""\ + def test(): + if not "Foooooooooooooooooooooooooooooo" or "Foooooooooooooooooooooooooooooo" == "Foooooooooooooooooooooooooooooo": + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testSplitListWithComment(self): + code = textwrap.dedent("""\ + a = [ + 'a', + 'b', + 'c' # hello world + ] + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testOverColumnLimit(self): + unformatted_code = textwrap.dedent("""\ + class Test: + + def testSomething(self): + expected = { + ('aaaaaaaaaaaaa', 'bbbb'): 'ccccccccccccccccccccccccccccccccccccccccccc', + ('aaaaaaaaaaaaa', 'bbbb'): 'ccccccccccccccccccccccccccccccccccccccccccc', + ('aaaaaaaaaaaaa', 'bbbb'): 'ccccccccccccccccccccccccccccccccccccccccccc', + } + """) + expected_formatted_code = textwrap.dedent("""\ + class Test: + + def testSomething(self): + expected = { + ('aaaaaaaaaaaaa', 'bbbb'): + 'ccccccccccccccccccccccccccccccccccccccccccc', + ('aaaaaaaaaaaaa', 'bbbb'): + 'ccccccccccccccccccccccccccccccccccccccccccc', + ('aaaaaaaaaaaaa', 'bbbb'): + 'ccccccccccccccccccccccccccccccccccccccccccc', + } + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testEndingComment(self): + code = textwrap.dedent("""\ + a = f( + a="something", + b="something requiring comment which is quite long", # comment about b (pushes line over 79) + c="something else, about which comment doesn't make sense") + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testContinuationSpaceRetention(self): + code = textwrap.dedent("""\ + def fn(): + return module \\ + .method(Object(data, + fn2(arg) + )) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testIfExpressionWithFunctionCall(self): + code = textwrap.dedent("""\ + if x or z.y(a, + c, + aaaaaaaaaaaaaaaaaaaaa=aaaaaaaaaaaaaaaaaa, + bbbbbbbbbbbbbbbbbbbbb=bbbbbbbbbbbbbbbbbb): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testUnformattedAfterMultilineString(self): + code = textwrap.dedent("""\ + def foo(): + com_text = \\ + ''' + TEST + ''' % (input_fname, output_fname) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testNoSpacesAroundKeywordDefaultValues(self): + code = textwrap.dedent("""\ + sources = { + 'json': request.get_json(silent=True) or {}, + 'json2': request.get_json(silent=True), + } + json = request.get_json(silent=True) or {} + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testNoSplittingBeforeEndingSubscriptBracket(self): + unformatted_code = textwrap.dedent("""\ + if True: + if True: + status = cf.describe_stacks(StackName=stackname)[u'Stacks'][0][u'StackStatus'] + """) + expected_formatted_code = textwrap.dedent("""\ + if True: + if True: + status = cf.describe_stacks( + StackName=stackname)[u'Stacks'][0][u'StackStatus'] + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testNoSplittingOnSingleArgument(self): + unformatted_code = textwrap.dedent("""\ + xxxxxxxxxxxxxx = (re.search(r'(\\d+\\.\\d+\\.\\d+\\.)\\d+', + aaaaaaa.bbbbbbbbbbbb).group(1) + + re.search(r'\\d+\\.\\d+\\.\\d+\\.(\\d+)', + ccccccc).group(1)) + xxxxxxxxxxxxxx = (re.search(r'(\\d+\\.\\d+\\.\\d+\\.)\\d+', + aaaaaaa.bbbbbbbbbbbb).group(a.b) + + re.search(r'\\d+\\.\\d+\\.\\d+\\.(\\d+)', + ccccccc).group(c.d)) + """) + expected_formatted_code = textwrap.dedent("""\ + xxxxxxxxxxxxxx = ( + re.search(r'(\\d+\\.\\d+\\.\\d+\\.)\\d+', aaaaaaa.bbbbbbbbbbbb).group(1) + + re.search(r'\\d+\\.\\d+\\.\\d+\\.(\\d+)', ccccccc).group(1)) + xxxxxxxxxxxxxx = ( + re.search(r'(\\d+\\.\\d+\\.\\d+\\.)\\d+', aaaaaaa.bbbbbbbbbbbb).group(a.b) + + re.search(r'\\d+\\.\\d+\\.\\d+\\.(\\d+)', ccccccc).group(c.d)) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSplittingArraysSensibly(self): + unformatted_code = textwrap.dedent("""\ + while True: + while True: + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list['bbbbbbbbbbbbbbbbbbbbbbbbb'].split(',') + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list('bbbbbbbbbbbbbbbbbbbbbbbbb').split(',') + """) + expected_formatted_code = textwrap.dedent("""\ + while True: + while True: + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list[ + 'bbbbbbbbbbbbbbbbbbbbbbbbb'].split(',') + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list( + 'bbbbbbbbbbbbbbbbbbbbbbbbb').split(',') + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testComprehensionForAndIf(self): + unformatted_code = textwrap.dedent("""\ + class f: + + def __repr__(self): + tokens_repr = ','.join(['{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens]) + """) + expected_formatted_code = textwrap.dedent("""\ + class f: + + def __repr__(self): + tokens_repr = ','.join( + ['{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens]) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testFunctionCallArguments(self): + unformatted_code = textwrap.dedent("""\ + def f(): + if True: + pytree_utils.InsertNodesBefore(_CreateCommentsFromPrefix( + comment_prefix, comment_lineno, comment_column, + standalone=True), ancestor_at_indent) + pytree_utils.InsertNodesBefore(_CreateCommentsFromPrefix( + comment_prefix, comment_lineno, comment_column, + standalone=True)) + """) + expected_formatted_code = textwrap.dedent("""\ + def f(): + if True: + pytree_utils.InsertNodesBefore( + _CreateCommentsFromPrefix( + comment_prefix, comment_lineno, comment_column, standalone=True), + ancestor_at_indent) + pytree_utils.InsertNodesBefore( + _CreateCommentsFromPrefix( + comment_prefix, comment_lineno, comment_column, standalone=True)) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testBinaryOperators(self): + unformatted_code = textwrap.dedent("""\ + a = b ** 37 + c = (20 ** -3) / (_GRID_ROWS ** (code_length - 10)) + """) + expected_formatted_code = textwrap.dedent("""\ + a = b**37 + c = (20**-3) / (_GRID_ROWS**(code_length - 10)) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + code = textwrap.dedent("""\ + def f(): + if True: + if (self.stack[-1].split_before_closing_bracket and + # FIXME(morbo): Use the 'matching_bracket' instead of this. + # FIXME(morbo): Don't forget about tuples! + current.value in ']}'): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testContiguousList(self): + code = textwrap.dedent("""\ + [retval1, retval2] = a_very_long_function(argument_1, argument2, argument_3, + argument_4) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testArgsAndKwargsFormatting(self): + code = textwrap.dedent("""\ + a(a=aaaaaaaaaaaaaaaaaaaaa, + b=aaaaaaaaaaaaaaaaaaaaaaaa, + c=aaaaaaaaaaaaaaaaaa, + *d, + **e) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testCommentColumnLimitOverflow(self): + code = textwrap.dedent("""\ + def f(): + if True: + TaskManager.get_tags = MagicMock( + name='get_tags_mock', + return_value=[157031694470475], + # side_effect=[(157031694470475), (157031694470475),], + ) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testMultilineLambdas(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: chromium, allow_multiline_lambdas: true}')) + unformatted_code = textwrap.dedent("""\ + class SomeClass(object): + do_something = True + + def succeeded(self, dddddddddddddd): + d = defer.succeed(None) + + if self.do_something: + d.addCallback(lambda _: self.aaaaaa.bbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccccccc(dddddddddddddd)) + return d + """) + expected_formatted_code = textwrap.dedent("""\ + class SomeClass(object): + do_something = True + + def succeeded(self, dddddddddddddd): + d = defer.succeed(None) + + if self.do_something: + d.addCallback(lambda _: self.aaaaaa.bbbbbbbbbbbbbbbb. + cccccccccccccccccccccccccccccccc(dddddddddddddd)) + return d + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + + def testStableDictionaryFormatting(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: pep8, indent_width: 2, ' + 'continuation_indent_width: 4, indent_dictionary_value: True}')) + code = textwrap.dedent("""\ + class A(object): + def method(self): + filters = { + 'expressions': [{ + 'field': { + 'search_field': { + 'user_field': 'latest_party__number_of_guests' + }, + } + }] + } + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + reformatted_code = reformatter.Reformat(uwlines) + self.assertCodeEqual(code, reformatted_code) + + uwlines = reformatter_test.ParseAndUnwrap(reformatted_code) + reformatted_code = reformatter.Reformat(uwlines) + self.assertCodeEqual(code, reformatted_code) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + + def testDontSplitKeywordValueArguments(self): + code = textwrap.dedent("""\ + def mark_game_scored(gid): + _connect.execute(_games.update().where(_games.c.gid == gid).values( + scored=True)) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testDontAddBlankLineAfterMultilineString(self): + code = textwrap.dedent("""\ + query = '''SELECT id + FROM table + WHERE day in {}''' + days = ",".join(days) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testFormattingListComprehensions(self): + code = textwrap.dedent("""\ + def a(): + if True: + if True: + if True: + columns = [ + x for x, y in self._heap_this_is_very_long if x.route[0] == choice + ] + self._heap = [x for x in self._heap if x.route and x.route[0] == choice] + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testNoSplittingWhenBinPacking(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: pep8, indent_width: 2, ' + 'continuation_indent_width: 4, indent_dictionary_value: True, ' + 'dedent_closing_brackets: True, ' + 'split_before_named_assigns: False}')) + code = textwrap.dedent("""\ + a_very_long_function_name( + long_argument_name_1=1, + long_argument_name_2=2, + long_argument_name_3=3, + long_argument_name_4=4, + ) + + a_very_long_function_name( + long_argument_name_1=1, long_argument_name_2=2, long_argument_name_3=3, + long_argument_name_4=4 + ) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + reformatted_code = reformatter.Reformat(uwlines) + self.assertCodeEqual(code, reformatted_code) + + uwlines = reformatter_test.ParseAndUnwrap(reformatted_code) + reformatted_code = reformatter.Reformat(uwlines) + self.assertCodeEqual(code, reformatted_code) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + + def testNotSplittingAfterSubscript(self): + unformatted_code = textwrap.dedent("""\ + if not aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.b(c == d[ + 'eeeeee']).ffffff(): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + if not aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.b( + c == d['eeeeee']).ffffff(): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSplittingOneArgumentList(self): + unformatted_code = textwrap.dedent("""\ + def _(): + if True: + if True: + if True: + if True: + if True: + boxes[id_] = np.concatenate((points.min(axis=0), qoints.max(axis=0))) + """) + expected_formatted_code = textwrap.dedent("""\ + def _(): + if True: + if True: + if True: + if True: + if True: + boxes[id_] = np.concatenate( + (points.min(axis=0), qoints.max(axis=0))) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSplittingBeforeFirstElementListArgument(self): + unformatted_code = textwrap.dedent("""\ + class _(): + @classmethod + def _pack_results_for_constraint_or(cls, combination, constraints): + if True: + if True: + if True: + return cls._create_investigation_result( + ( + clue for clue in combination if not clue == Verifier.UNMATCHED + ), constraints, InvestigationResult.OR + ) + """) + expected_formatted_code = textwrap.dedent("""\ + class _(): + + @classmethod + def _pack_results_for_constraint_or(cls, combination, constraints): + if True: + if True: + if True: + return cls._create_investigation_result( + (clue for clue in combination if not clue == Verifier.UNMATCHED), + constraints, InvestigationResult.OR) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSplittingArgumentsTerminatedByComma(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: chromium, ' + 'split_arguments_when_comma_terminated: True}')) + unformatted_code = textwrap.dedent("""\ + function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3) + + function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3,) + + a_very_long_function_name(long_argument_name_1=1, long_argument_name_2=2, long_argument_name_3=3, long_argument_name_4=4) + + a_very_long_function_name(long_argument_name_1, long_argument_name_2, long_argument_name_3, long_argument_name_4,) + + r =f0 (1, 2,3,) + """) + expected_formatted_code = textwrap.dedent("""\ + function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3) + + function_name( + argument_name_1=1, + argument_name_2=2, + argument_name_3=3, + ) + + a_very_long_function_name( + long_argument_name_1=1, + long_argument_name_2=2, + long_argument_name_3=3, + long_argument_name_4=4) + + a_very_long_function_name( + long_argument_name_1, + long_argument_name_2, + long_argument_name_3, + long_argument_name_4, + ) + + r = f0( + 1, + 2, + 3, + ) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + reformatted_code = reformatter.Reformat(uwlines) + self.assertCodeEqual(expected_formatted_code, reformatted_code) + + uwlines = reformatter_test.ParseAndUnwrap(reformatted_code) + reformatted_code = reformatter.Reformat(uwlines) + self.assertCodeEqual(expected_formatted_code, reformatted_code) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + + def testImportAsList(self): + code = textwrap.dedent("""\ + from toto import titi, tata, tutu # noqa + from toto import titi, tata, tutu + from toto import (titi, tata, tutu) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testDictionaryValuesOnOwnLines(self): + unformatted_code = textwrap.dedent("""\ + a = { + 'aaaaaaaaaaaaaaaaaaaaaaaa': + Check('ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ', '=', True), + 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb': + Check('YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY', '=', True), + 'ccccccccccccccc': + Check('XXXXXXXXXXXXXXXXXXX', '!=', 'SUSPENDED'), + 'dddddddddddddddddddddddddddddd': + Check('WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW', '=', False), + 'eeeeeeeeeeeeeeeeeeeeeeeeeeeee': + Check('VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV', '=', False), + 'ffffffffffffffffffffffffff': + Check('UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU', '=', True), + 'ggggggggggggggggg': + Check('TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT', '=', True), + 'hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh': + Check('SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS', '=', True), + 'iiiiiiiiiiiiiiiiiiiiiiii': + Check('RRRRRRRRRRRRRRRRRRRRRRRRRRR', '=', True), + 'jjjjjjjjjjjjjjjjjjjjjjjjjj': + Check('QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ', '=', False), + } + """) + expected_formatted_code = textwrap.dedent("""\ + a = { + 'aaaaaaaaaaaaaaaaaaaaaaaa': + Check('ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ', '=', True), + 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb': + Check('YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY', '=', True), + 'ccccccccccccccc': + Check('XXXXXXXXXXXXXXXXXXX', '!=', 'SUSPENDED'), + 'dddddddddddddddddddddddddddddd': + Check('WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW', '=', False), + 'eeeeeeeeeeeeeeeeeeeeeeeeeeeee': + Check('VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV', '=', False), + 'ffffffffffffffffffffffffff': + Check('UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU', '=', True), + 'ggggggggggggggggg': + Check('TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT', '=', True), + 'hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh': + Check('SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS', '=', True), + 'iiiiiiiiiiiiiiiiiiiiiiii': + Check('RRRRRRRRRRRRRRRRRRRRRRRRRRR', '=', True), + 'jjjjjjjjjjjjjjjjjjjjjjjjjj': + Check('QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ', '=', False), + } + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testDictionaryOnOwnLine(self): + unformatted_code = textwrap.dedent("""\ + doc = test_utils.CreateTestDocumentViaController( + content={ 'a': 'b' }, + branch_key=branch.key, + collection_key=collection.key) + """) + expected_formatted_code = textwrap.dedent("""\ + doc = test_utils.CreateTestDocumentViaController( + content={'a': 'b'}, branch_key=branch.key, collection_key=collection.key) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + unformatted_code = textwrap.dedent("""\ + doc = test_utils.CreateTestDocumentViaController( + content={ 'a': 'b' }, + branch_key=branch.key, + collection_key=collection.key, + collection_key2=collection.key2) + """) + expected_formatted_code = textwrap.dedent("""\ + doc = test_utils.CreateTestDocumentViaController( + content={'a': 'b'}, + branch_key=branch.key, + collection_key=collection.key, + collection_key2=collection.key2) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testNestedListsInDictionary(self): + unformatted_code = textwrap.dedent("""\ + _A = { + 'cccccccccc': ('^^1',), + 'rrrrrrrrrrrrrrrrrrrrrrrrr': ('^7913', # AAAAAAAAAAAAAA. + ), + 'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee': ('^6242', # BBBBBBBBBBBBBBB. + ), + 'vvvvvvvvvvvvvvvvvvv': ('^27959', # CCCCCCCCCCCCCCCCCC. + '^19746', # DDDDDDDDDDDDDDDDDDDDDDD. + '^22907', # EEEEEEEEEEEEEEEEEEEEEEEE. + '^21098', # FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF. + '^22826', # GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG. + '^22769', # HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH. + '^22935', # IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII. + '^3982', # JJJJJJJJJJJJJ. + ), + 'uuuuuuuuuuuu': ('^19745', # LLLLLLLLLLLLLLLLLLLLLLLLLL. + '^21324', # MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM. + '^22831', # NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN. + '^17081', # OOOOOOOOOOOOOOOOOOOOO. + ), + 'eeeeeeeeeeeeee': ( + '^9416', # Reporter email. Not necessarily the reporter. + '^^3', # This appears to be the raw email field. + ), + 'cccccccccc': ('^21109', # PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP. + ), + } + """) + expected_formatted_code = textwrap.dedent("""\ + _A = { + 'cccccccccc': ('^^1',), + 'rrrrrrrrrrrrrrrrrrrrrrrrr': ( + '^7913', # AAAAAAAAAAAAAA. + ), + 'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee': ( + '^6242', # BBBBBBBBBBBBBBB. + ), + 'vvvvvvvvvvvvvvvvvvv': ( + '^27959', # CCCCCCCCCCCCCCCCCC. + '^19746', # DDDDDDDDDDDDDDDDDDDDDDD. + '^22907', # EEEEEEEEEEEEEEEEEEEEEEEE. + '^21098', # FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF. + '^22826', # GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG. + '^22769', # HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH. + '^22935', # IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII. + '^3982', # JJJJJJJJJJJJJ. + ), + 'uuuuuuuuuuuu': ( + '^19745', # LLLLLLLLLLLLLLLLLLLLLLLLLL. + '^21324', # MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM. + '^22831', # NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN. + '^17081', # OOOOOOOOOOOOOOOOOOOOO. + ), + 'eeeeeeeeeeeeee': ( + '^9416', # Reporter email. Not necessarily the reporter. + '^^3', # This appears to be the raw email field. + ), + 'cccccccccc': ( + '^21109', # PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP. + ), + } + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testNestedDictionary(self): + unformatted_code = textwrap.dedent("""\ + class _(): + def _(): + breadcrumbs = [{'name': 'Admin', + 'url': url_for(".home")}, + {'title': title},] + breadcrumbs = [{'name': 'Admin', + 'url': url_for(".home")}, + {'title': title}] + """) + expected_formatted_code = textwrap.dedent("""\ + class _(): + def _(): + breadcrumbs = [ + { + 'name': 'Admin', + 'url': url_for(".home") + }, + { + 'title': title + }, + ] + breadcrumbs = [{ + 'name': 'Admin', + 'url': url_for(".home") + }, { + 'title': title + }] + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testDictionaryElementsOnOneLine(self): + code = textwrap.dedent("""\ + class _(): + + @mock.patch.dict( + os.environ, + {'HTTP_' + xsrf._XSRF_TOKEN_HEADER.replace('-', '_'): 'atoken'}) + def _(): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testNotInParams(self): + unformatted_code = textwrap.dedent("""\ + list("a long line to break the line. a long line to break the brk a long lin", not True) + """) + expected_code = textwrap.dedent("""\ + list("a long line to break the line. a long line to break the brk a long lin", + not True) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + + +if __name__ == '__main__': + unittest.main() diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py new file mode 100644 index 000000000..52968c245 --- /dev/null +++ b/yapftests/reformatter_buganizer_test.py @@ -0,0 +1,1215 @@ +# Copyright 2015-2016 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Buganizer tests for yapf.reformatter.""" + +import textwrap +import unittest + +from yapf.yapflib import reformatter +from yapf.yapflib import style + +from yapftests import reformatter_test + + +class BuganizerFixes(reformatter_test.ReformatterTest): + + @classmethod + def setUpClass(cls): + style.SetGlobalStyle(style.CreateChromiumStyle()) + + def testB31937033(self): + code = textwrap.dedent("""\ + class _(): + + def __init__(self, metric, fields_cb=None): + self._fields_cb = fields_cb or (lambda *unused_args, **unused_kwargs: {}) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB31911533(self): + code = textwrap.dedent("""\ + class _(): + + @parameterized.NamedParameters( + ('IncludingModInfoWithHeaderList', AAAA, aaaa), + ('IncludingModInfoWithoutHeaderList', BBBB, bbbbb), + ('ExcludingModInfoWithHeaderList', CCCCC, cccc), + ('ExcludingModInfoWithoutHeaderList', DDDDD, ddddd),) + def _(): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB31847238(self): + unformatted_code = textwrap.dedent("""\ + class _(): + + def aaaaa(self, bbbbb, cccccccccccccc=None): # pylint: disable=unused-argument + return 1 + + def xxxxx(self, yyyyy, zzzzzzzzzzzzzz=None): # A normal comment that runs over the column limit. + return 1 + """) + expected_formatted_code = textwrap.dedent("""\ + class _(): + + def aaaaa(self, bbbbb, cccccccccccccc=None): # pylint: disable=unused-argument + return 1 + + def xxxxx( + self, yyyyy, + zzzzzzzzzzzzzz=None): # A normal comment that runs over the column limit. + return 1 + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB30760569(self): + unformatted_code = textwrap.dedent("""\ + {'1234567890123456789012345678901234567890123456789012345678901234567890': + '1234567890123456789012345678901234567890'} + """) + expected_formatted_code = textwrap.dedent("""\ + { + '1234567890123456789012345678901234567890123456789012345678901234567890': + '1234567890123456789012345678901234567890' + } + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB26034238(self): + unformatted_code = textwrap.dedent("""\ + class Thing: + + def Function(self): + thing.Scrape('/aaaaaaaaa/bbbbbbbbbb/ccccc/dddd/eeeeeeeeeeeeee/ffffffffffffff').AndReturn(42) + """) + expected_formatted_code = textwrap.dedent("""\ + class Thing: + + def Function(self): + thing.Scrape( + '/aaaaaaaaa/bbbbbbbbbb/ccccc/dddd/eeeeeeeeeeeeee/ffffffffffffff' + ).AndReturn(42) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB30536435(self): + unformatted_code = textwrap.dedent("""\ + def main(unused_argv): + if True: + if True: + aaaaaaaaaaa.comment('import-from[{}] {} {}'.format( + bbbbbbbbb.usage, + ccccccccc.within, + imports.ddddddddddddddddddd(name_item.ffffffffffffffff))) + """) + expected_formatted_code = textwrap.dedent("""\ + def main(unused_argv): + if True: + if True: + aaaaaaaaaaa.comment('import-from[{}] {} {}'.format( + bbbbbbbbb.usage, ccccccccc.within, + imports.ddddddddddddddddddd(name_item.ffffffffffffffff))) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB30442148(self): + unformatted_code = textwrap.dedent("""\ + def lulz(): + return (some_long_module_name.SomeLongClassName. + some_long_attribute_name.some_long_method_name()) + """) + expected_formatted_code = textwrap.dedent("""\ + def lulz(): + return (some_long_module_name.SomeLongClassName.some_long_attribute_name. + some_long_method_name()) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB26868213(self): + unformatted_code = textwrap.dedent("""\ + def _(): + xxxxxxxxxxxxxxxxxxx = { + 'ssssss': {'ddddd': 'qqqqq', + 'p90': aaaaaaaaaaaaaaaaa, + 'p99': bbbbbbbbbbbbbbbbb, + 'lllllllllllll': yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy(),}, + 'bbbbbbbbbbbbbbbbbbbbbbbbbbbb': { + 'ddddd': 'bork bork bork bo', + 'p90': wwwwwwwwwwwwwwwww, + 'p99': wwwwwwwwwwwwwwwww, + 'lllllllllllll': None, # use the default + } + } + """) + expected_formatted_code = textwrap.dedent("""\ + def _(): + xxxxxxxxxxxxxxxxxxx = { + 'ssssss': { + 'ddddd': 'qqqqq', + 'p90': aaaaaaaaaaaaaaaaa, + 'p99': bbbbbbbbbbbbbbbbb, + 'lllllllllllll': yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy(), + }, + 'bbbbbbbbbbbbbbbbbbbbbbbbbbbb': { + 'ddddd': 'bork bork bork bo', + 'p90': wwwwwwwwwwwwwwwww, + 'p99': wwwwwwwwwwwwwwwww, + 'lllllllllllll': None, # use the default + } + } + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB30173198(self): + code = textwrap.dedent("""\ + class _(): + + def _(): + self.assertFalse( + evaluation_runner.get_larps_in_eval_set('these_arent_the_larps')) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB29908765(self): + code = textwrap.dedent("""\ + class _(): + + def __repr__(self): + return '' % (self._id, + self._stub._stub.rpc_channel().target()) # pylint:disable=protected-access + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB30087362(self): + code = textwrap.dedent("""\ + def _(): + for s in sorted(env['foo']): + bar() + # This is a comment + + # This is another comment + foo() + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB29093579(self): + unformatted_code = textwrap.dedent("""\ + def _(): + _xxxxxxxxxxxxxxx(aaaaaaaa, bbbbbbbbbbbbbb.cccccccccc[ + dddddddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffff]) + """) + expected_formatted_code = textwrap.dedent("""\ + def _(): + _xxxxxxxxxxxxxxx( + aaaaaaaa, + bbbbbbbbbbbbbb.cccccccccc[dddddddddddddddddddddddddddd. + eeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffff]) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB26382315(self): + code = textwrap.dedent("""\ + @hello_world + # This is a first comment + + # Comment + def foo(): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB27616132(self): + unformatted_code = textwrap.dedent("""\ + if True: + query.fetch_page.assert_has_calls([ + mock.call(100, + start_cursor=None), + mock.call(100, + start_cursor=cursor_1), + mock.call(100, + start_cursor=cursor_2), + ]) + """) + expected_formatted_code = textwrap.dedent("""\ + if True: + query.fetch_page.assert_has_calls([ + mock.call( + 100, start_cursor=None), + mock.call( + 100, start_cursor=cursor_1), + mock.call( + 100, start_cursor=cursor_2), + ]) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB27590179(self): + unformatted_code = textwrap.dedent("""\ + if True: + if True: + self.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = ( + { True: + self.bbb.cccccccccc(ddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee), + False: + self.bbb.cccccccccc(ddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee) + }) + """) + expected_formatted_code = textwrap.dedent("""\ + if True: + if True: + self.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = ({ + True: + self.bbb.cccccccccc(ddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee), + False: + self.bbb.cccccccccc(ddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee) + }) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB27266946(self): + unformatted_code = textwrap.dedent("""\ + def _(): + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = (self.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccccccccccc) + """) + expected_formatted_code = textwrap.dedent("""\ + def _(): + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = ( + self.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb. + cccccccccccccccccccccccccccccccccccc) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB25505359(self): + code = textwrap.dedent("""\ + _EXAMPLE = { + 'aaaaaaaaaaaaaa': [{ + 'bbbb': 'cccccccccccccccccccccc', + 'dddddddddddd': [] + }, { + 'bbbb': 'ccccccccccccccccccc', + 'dddddddddddd': [] + }] + } + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB25324261(self): + code = textwrap.dedent("""\ + aaaaaaaaa = set(bbbb.cccc + for ddd in eeeeee.fffffffffff.gggggggggggggggg + for cccc in ddd.specification) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB25136704(self): + code = textwrap.dedent("""\ + class f: + + def test(self): + self.bbbbbbb[0]['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', { + 'xxxxxx': 'yyyyyy' + }] = cccccc.ddd('1m', '10x1+1') + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB25165602(self): + code = textwrap.dedent("""\ + def f(): + ids = {u: i for u, i in zip(self.aaaaa, xrange(42, 42 + len(self.aaaaaa)))} + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB25157123(self): + code = textwrap.dedent("""\ + def ListArgs(): + FairlyLongMethodName([relatively_long_identifier_for_a_list], + another_argument_with_a_long_identifier) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB25136820(self): + unformatted_code = textwrap.dedent("""\ + def foo(): + return collections.OrderedDict({ + # Preceding comment. + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa': + '$bbbbbbbbbbbbbbbbbbbbbbbb', + }) + """) + expected_formatted_code = textwrap.dedent("""\ + def foo(): + return collections.OrderedDict({ + # Preceding comment. + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa': + '$bbbbbbbbbbbbbbbbbbbbbbbb', + }) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB25131481(self): + unformatted_code = textwrap.dedent("""\ + APPARENT_ACTIONS = ('command_type', { + 'materialize': lambda x: some_type_of_function('materialize ' + x.command_def), + '#': lambda x: x # do nothing + }) + """) + expected_formatted_code = textwrap.dedent("""\ + APPARENT_ACTIONS = ( + 'command_type', + { + 'materialize': + lambda x: some_type_of_function('materialize ' + x.command_def), + '#': + lambda x: x # do nothing + }) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB23445244(self): + unformatted_code = textwrap.dedent("""\ + def foo(): + if True: + return xxxxxxxxxxxxxxxx( + command, + extra_env={ + "OOOOOOOOOOOOOOOOOOOOO": FLAGS.zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, + "PPPPPPPPPPPPPPPPPPPPP": + FLAGS.aaaaaaaaaaaaaa + FLAGS.bbbbbbbbbbbbbbbbbbb, + }) + """) + expected_formatted_code = textwrap.dedent("""\ + def foo(): + if True: + return xxxxxxxxxxxxxxxx( + command, + extra_env={ + "OOOOOOOOOOOOOOOOOOOOO": + FLAGS.zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, + "PPPPPPPPPPPPPPPPPPPPP": + FLAGS.aaaaaaaaaaaaaa + FLAGS.bbbbbbbbbbbbbbbbbbb, + }) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB20559654(self): + unformatted_code = textwrap.dedent("""\ + class A(object): + + def foo(self): + unused_error, result = server.Query( + ['AA BBBB CCC DDD EEEEEEEE X YY ZZZZ FFF EEE AAAAAAAA'], + aaaaaaaaaaa=True, bbbbbbbb=None) + """) + expected_formatted_code = textwrap.dedent("""\ + class A(object): + + def foo(self): + unused_error, result = server.Query( + ['AA BBBB CCC DDD EEEEEEEE X YY ZZZZ FFF EEE AAAAAAAA'], + aaaaaaaaaaa=True, + bbbbbbbb=None) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB23943842(self): + unformatted_code = textwrap.dedent("""\ + class F(): + def f(): + self.assertDictEqual( + accounts, { + 'foo': + {'account': 'foo', + 'lines': 'l1\\nl2\\nl3\\n1 line(s) were elided.'}, + 'bar': {'account': 'bar', + 'lines': 'l5\\nl6\\nl7'}, + 'wiz': {'account': 'wiz', + 'lines': 'l8'} + }) + """) + expected_formatted_code = textwrap.dedent("""\ + class F(): + + def f(): + self.assertDictEqual(accounts, { + 'foo': { + 'account': 'foo', + 'lines': 'l1\\nl2\\nl3\\n1 line(s) were elided.' + }, + 'bar': { + 'account': 'bar', + 'lines': 'l5\\nl6\\nl7' + }, + 'wiz': { + 'account': 'wiz', + 'lines': 'l8' + } + }) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB20551180(self): + unformatted_code = textwrap.dedent("""\ + def foo(): + if True: + return (struct.pack('aaaa', bbbbbbbbbb, ccccccccccccccc, dddddddd) + eeeeeee) + """) + expected_formatted_code = textwrap.dedent("""\ + def foo(): + if True: + return ( + struct.pack('aaaa', bbbbbbbbbb, ccccccccccccccc, dddddddd) + eeeeeee) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB23944849(self): + unformatted_code = textwrap.dedent("""\ + class A(object): + def xxxxxxxxx(self, aaaaaaa, bbbbbbb=ccccccccccc, dddddd=300, eeeeeeeeeeeeee=None, fffffffffffffff=0): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + class A(object): + + def xxxxxxxxx(self, + aaaaaaa, + bbbbbbb=ccccccccccc, + dddddd=300, + eeeeeeeeeeeeee=None, + fffffffffffffff=0): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB23935890(self): + unformatted_code = textwrap.dedent("""\ + class F(): + def functioni(self, aaaaaaa, bbbbbbb, cccccc, dddddddddddddd, eeeeeeeeeeeeeee): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + class F(): + + def functioni(self, aaaaaaa, bbbbbbb, cccccc, dddddddddddddd, + eeeeeeeeeeeeeee): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB28414371(self): + code = textwrap.dedent("""\ + def _(): + return ( + (m.fffff( + m.rrr('mmmmmmmmmmmmmmmm', 'ssssssssssssssssssssssssss'), + ffffffffffffffff) + | m.wwwwww(m.ddddd('1h')) + | m.ggggggg(bbbbbbbbbbbbbbb) + | m.ppppp( + (1 - m.ffffffffffffffff(llllllllllllllllllllll * 1000000, m.vvv)) * + m.ddddddddddddddddd(m.vvv)), m.fffff( + m.rrr('mmmmmmmmmmmmmmmm', 'sssssssssssssssssssssss'), + dict( + ffffffffffffffff, + **{ + 'mmmmmm:ssssss': + m.rrrrrrrrrrr( + '|'.join(iiiiiiiiiiiiii), iiiiii=True) + })) + | m.wwwwww(m.rrrr('1h')) + | m.ggggggg(bbbbbbbbbbbbbbb)) + | m.jjjj() + | m.ppppp(m.vvv[0] + m.vvv[1])) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB20127686(self): + code = textwrap.dedent("""\ + def f(): + if True: + return ((m.fffff( + m.rrr('xxxxxxxxxxxxxxxx', + 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'), + mmmmmmmm) + | m.wwwwww(m.rrrr(self.tttttttttt, self.mmmmmmmmmmmmmmmmmmmmm)) + | m.ggggggg(self.gggggggg, m.sss()), m.fffff('aaaaaaaaaaaaaaaa') + | m.wwwwww(m.ddddd(self.tttttttttt, self.mmmmmmmmmmmmmmmmmmmmm)) + | m.ggggggg(self.gggggggg)) + | m.jjjj() + | m.ppppp(m.VAL[0] / m.VAL[1])) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB20016122(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: pep8, split_penalty_import_names: 35}')) + unformatted_code = textwrap.dedent("""\ + from a_very_long_or_indented_module_name_yada_yada import (long_argument_1, + long_argument_2) + """) + expected_formatted_code = textwrap.dedent("""\ + from a_very_long_or_indented_module_name_yada_yada import ( + long_argument_1, long_argument_2) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreatePEP8Style()) + + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{based_on_style: chromium, ' + 'split_before_logical_operator: True}')) + code = textwrap.dedent("""\ + class foo(): + + def __eq__(self, other): + return (isinstance(other, type(self)) + and self.xxxxxxxxxxx == other.xxxxxxxxxxx + and self.xxxxxxxx == other.xxxxxxxx + and self.aaaaaaaaaaaa == other.aaaaaaaaaaaa + and self.bbbbbbbbbbb == other.bbbbbbbbbbb + and self.ccccccccccccccccc == other.ccccccccccccccccc + and self.ddddddddddddddddddddddd == other.ddddddddddddddddddddddd + and self.eeeeeeeeeeee == other.eeeeeeeeeeee + and self.ffffffffffffff == other.time_completed + and self.gggggg == other.gggggg and self.hhh == other.hhh + and len(self.iiiiiiii) == len(other.iiiiiiii) + and all(jjjjjjj in other.iiiiiiii for jjjjjjj in self.iiiiiiii)) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + + def testB22527411(self): + unformatted_code = textwrap.dedent("""\ + def f(): + if True: + aaaaaa.bbbbbbbbbbbbbbbbbbbb[-1].cccccccccccccc.ddd().eeeeeeee(ffffffffffffff) + """) + expected_formatted_code = textwrap.dedent("""\ + def f(): + if True: + aaaaaa.bbbbbbbbbbbbbbbbbbbb[-1].cccccccccccccc.ddd().eeeeeeee( + ffffffffffffff) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB20849933(self): + code = textwrap.dedent("""\ + def main(unused_argv): + if True: + aaaaaaaa = { + 'xxx': + '%s/cccccc/ddddddddddddddddddd.jar' % (eeeeee.FFFFFFFFFFFFFFFFFF), + } + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB20813997(self): + code = textwrap.dedent("""\ + def myfunc_1(): + myarray = numpy.zeros((2, 2, 2)) + print(myarray[:, 1, :]) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB20605036(self): + code = textwrap.dedent("""\ + foo = { + 'aaaa': { + # A comment for no particular reason. + 'xxxxxxxx': + 'bbbbbbbbb', + 'yyyyyyyyyyyyyyyyyy': + 'cccccccccccccccccccccccccccccc' + 'dddddddddddddddddddddddddddddddddddddddddd', + } + } + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB20562732(self): + code = textwrap.dedent("""\ + foo = [ + # Comment about first list item + 'First item', + # Comment about second list item + 'Second item', + ] + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB20128830(self): + code = textwrap.dedent("""\ + a = { + 'xxxxxxxxxxxxxxxxxxxx': { + 'aaaa': + 'mmmmmmm', + 'bbbbb': + 'mmmmmmmmmmmmmmmmmmmmm', + 'cccccccccc': [ + 'nnnnnnnnnnn', + 'ooooooooooo', + 'ppppppppppp', + 'qqqqqqqqqqq', + ], + }, + } + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB20073838(self): + code = textwrap.dedent("""\ + class DummyModel(object): + + def do_nothing(self, class_1_count): + if True: + class_0_count = num_votes - class_1_count + return ('{class_0_name}={class_0_count}, {class_1_name}={class_1_count}' + .format( + class_0_name=self.class_0_name, + class_0_count=class_0_count, + class_1_name=self.class_1_name, + class_1_count=class_1_count)) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB19626808(self): + code = textwrap.dedent("""\ + if True: + aaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbb( + 'ccccccccccc', ddddddddd='eeeee').fffffffff([ggggggggggggggggggggg]) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB19547210(self): + code = textwrap.dedent("""\ + while True: + if True: + if True: + if True: + if xxxxxxxxxxxx.yyyyyyy(aa).zzzzzzz() not in ( + xxxxxxxxxxxx.yyyyyyyyyyyyyy.zzzzzzzz, + xxxxxxxxxxxx.yyyyyyyyyyyyyy.zzzzzzzz): + continue + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB19377034(self): + code = textwrap.dedent("""\ + def f(): + if (aaaaaaaaaaaaaaa.start >= aaaaaaaaaaaaaaa.end or + bbbbbbbbbbbbbbb.start >= bbbbbbbbbbbbbbb.end): + return False + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB19372573(self): + code = textwrap.dedent("""\ + def f(): + if a: return 42 + while True: + if b: continue + if c: break + return 0 + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + try: + style.SetGlobalStyle(style.CreatePEP8Style()) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + + def testB19353268(self): + code = textwrap.dedent("""\ + a = {1, 2, 3}[x] + b = {'foo': 42, 'bar': 37}['foo'] + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB19287512(self): + unformatted_code = textwrap.dedent("""\ + class Foo(object): + + def bar(self): + with xxxxxxxxxx.yyyyy( + 'aaaaaaa.bbbbbbbb.ccccccc.dddddddddddddddddddd.eeeeeeeeeee', + fffffffffff=(aaaaaaa.bbbbbbbb.ccccccc.dddddddddddddddddddd + .Mmmmmmmmmmmmmmmmmm(-1, 'permission error'))): + self.assertRaises(nnnnnnnnnnnnnnnn.ooooo, ppppp.qqqqqqqqqqqqqqqqq) + """) + expected_formatted_code = textwrap.dedent("""\ + class Foo(object): + + def bar(self): + with xxxxxxxxxx.yyyyy( + 'aaaaaaa.bbbbbbbb.ccccccc.dddddddddddddddddddd.eeeeeeeeeee', + fffffffffff=( + aaaaaaa.bbbbbbbb.ccccccc.dddddddddddddddddddd.Mmmmmmmmmmmmmmmmmm( + -1, 'permission error'))): + self.assertRaises(nnnnnnnnnnnnnnnn.ooooo, ppppp.qqqqqqqqqqqqqqqqq) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB19194420(self): + code = textwrap.dedent("""\ + method.Set('long argument goes here that causes the line to break', + lambda arg2=0.5: arg2) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB19073499(self): + code = textwrap.dedent("""\ + instance = ( + aaaaaaa.bbbbbbb().ccccccccccccccccc().ddddddddddd({ + 'aa': 'context!' + }).eeeeeeeeeeeeeeeeeee( + { # Inline comment about why fnord has the value 6. + 'fnord': 6 + })) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB18257115(self): + code = textwrap.dedent("""\ + if True: + if True: + self._Test(aaaa, bbbbbbb.cccccccccc, dddddddd, eeeeeeeeeee, + [ffff, ggggggggggg, hhhhhhhhhhhh, iiiiii, jjjj]) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB18256666(self): + code = textwrap.dedent("""\ + class Foo(object): + + def Bar(self): + aaaaa.bbbbbbb( + ccc='ddddddddddddddd', + eeee='ffffffffffffffffffffff-%s-%s' % (gggg, int(time.time())), + hhhhhh={ + 'iiiiiiiiiii': iiiiiiiiiii, + 'jjjj': jjjj.jjjjj(), + 'kkkkkkkkkkkk': kkkkkkkkkkkk, + }, + llllllllll=mmmmmm.nnnnnnnnnnnnnnnn) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB18256826(self): + code = textwrap.dedent("""\ + if True: + pass + # A multiline comment. + # Line two. + elif False: + pass + + if True: + pass + # A multiline comment. + # Line two. + elif False: + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB18255697(self): + code = textwrap.dedent("""\ + AAAAAAAAAAAAAAA = { + 'XXXXXXXXXXXXXX': 4242, # Inline comment + # Next comment + 'YYYYYYYYYYYYYYYY': ['zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'], + } + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB17534869(self): + unformatted_code = textwrap.dedent("""\ + if True: + self.assertLess(abs(time.time()-aaaa.bbbbbbbbbbb( + datetime.datetime.now())), 1) + """) + expected_formatted_code = textwrap.dedent("""\ + if True: + self.assertLess( + abs(time.time() - aaaa.bbbbbbbbbbb(datetime.datetime.now())), 1) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB17489866(self): + unformatted_code = textwrap.dedent("""\ + def f(): + if True: + if True: + return aaaa.bbbbbbbbb(ccccccc=dddddddddddddd({('eeee', \ +'ffffffff'): str(j)})) + """) + expected_formatted_code = textwrap.dedent("""\ + def f(): + if True: + if True: + return aaaa.bbbbbbbbb(ccccccc=dddddddddddddd({ + ('eeee', 'ffffffff'): str(j) + })) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB17133019(self): + unformatted_code = textwrap.dedent("""\ + class aaaaaaaaaaaaaa(object): + + def bbbbbbbbbb(self): + with io.open("/dev/null", "rb"): + with io.open(os.path.join(aaaaa.bbbbb.ccccccccccc, + DDDDDDDDDDDDDDD, + "eeeeeeeee ffffffffff" + ), "rb") as gggggggggggggggggggg: + print(gggggggggggggggggggg) + """) + expected_formatted_code = textwrap.dedent("""\ + class aaaaaaaaaaaaaa(object): + + def bbbbbbbbbb(self): + with io.open("/dev/null", "rb"): + with io.open( + os.path.join(aaaaa.bbbbb.ccccccccccc, DDDDDDDDDDDDDDD, + "eeeeeeeee ffffffffff"), "rb") as gggggggggggggggggggg: + print(gggggggggggggggggggg) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB17011869(self): + unformatted_code = textwrap.dedent("""\ + '''blah......''' + + class SomeClass(object): + '''blah.''' + + AAAAAAAAAAAA = { # Comment. + 'BBB': 1.0, + 'DDDDDDDD': 0.4811 + } + """) + expected_formatted_code = textwrap.dedent("""\ + '''blah......''' + + + class SomeClass(object): + '''blah.''' + + AAAAAAAAAAAA = { # Comment. + 'BBB': 1.0, + 'DDDDDDDD': 0.4811 + } + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB16783631(self): + unformatted_code = textwrap.dedent("""\ + if True: + with aaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccc(ddddddddddddd, + eeeeeeeee=self.fffffffffffff + )as gggg: + pass + """) + expected_formatted_code = textwrap.dedent("""\ + if True: + with aaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccc( + ddddddddddddd, eeeeeeeee=self.fffffffffffff) as gggg: + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB16572361(self): + unformatted_code = textwrap.dedent("""\ + def foo(self): + def bar(my_dict_name): + self.my_dict_name['foo-bar-baz-biz-boo-baa-baa'].IncrementBy.assert_called_once_with('foo_bar_baz_boo') + """) + expected_formatted_code = textwrap.dedent("""\ + def foo(self): + + def bar(my_dict_name): + self.my_dict_name[ + 'foo-bar-baz-biz-boo-baa-baa'].IncrementBy.assert_called_once_with( + 'foo_bar_baz_boo') + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB15884241(self): + unformatted_code = textwrap.dedent("""\ + if 1: + if 1: + for row in AAAA: + self.create(aaaaaaaa="/aaa/bbbb/cccc/dddddd/eeeeeeeeeeeeeeeeeeeeeeeeee/%s" % row [0].replace(".foo", ".bar"), aaaaa=bbb[1], ccccc=bbb[2], dddd=bbb[3], eeeeeeeeeee=[s.strip() for s in bbb[4].split(",")], ffffffff=[s.strip() for s in bbb[5].split(",")], gggggg=bbb[6]) + """) + expected_formatted_code = textwrap.dedent("""\ + if 1: + if 1: + for row in AAAA: + self.create( + aaaaaaaa="/aaa/bbbb/cccc/dddddd/eeeeeeeeeeeeeeeeeeeeeeeeee/%s" % + row[0].replace(".foo", ".bar"), + aaaaa=bbb[1], + ccccc=bbb[2], + dddd=bbb[3], + eeeeeeeeeee=[s.strip() for s in bbb[4].split(",")], + ffffffff=[s.strip() for s in bbb[5].split(",")], + gggggg=bbb[6]) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB15697268(self): + unformatted_code = textwrap.dedent("""\ + def main(unused_argv): + ARBITRARY_CONSTANT_A = 10 + an_array_with_an_exceedingly_long_name = range(ARBITRARY_CONSTANT_A + 1) + ok = an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A] + bad_slice = map(math.sqrt, an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A]) + a_long_name_slicing = an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A] + bad_slice = ("I am a crazy, no good, string whats too long, etc." + " no really ")[:ARBITRARY_CONSTANT_A] + """) + expected_formatted_code = textwrap.dedent("""\ + def main(unused_argv): + ARBITRARY_CONSTANT_A = 10 + an_array_with_an_exceedingly_long_name = range(ARBITRARY_CONSTANT_A + 1) + ok = an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A] + bad_slice = map(math.sqrt, + an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A]) + a_long_name_slicing = an_array_with_an_exceedingly_long_name[: + ARBITRARY_CONSTANT_A] + bad_slice = ("I am a crazy, no good, string whats too long, etc." + + " no really ")[:ARBITRARY_CONSTANT_A] + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB15597568(self): + unformatted_code = textwrap.dedent("""\ + if True: + if True: + if True: + print(("Return code was %d" + (", and the process timed out." if did_time_out else ".")) % errorcode) + """) + expected_formatted_code = textwrap.dedent("""\ + if True: + if True: + if True: + print(("Return code was %d" + (", and the process timed out." + if did_time_out else ".")) % errorcode) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB15542157(self): + unformatted_code = textwrap.dedent("""\ + aaaaaaaaaaaa = bbbb.ccccccccccccccc(dddddd.eeeeeeeeeeeeee, ffffffffffffffffff, gggggg.hhhhhhhhhhhhhhhhh) + """) + expected_formatted_code = textwrap.dedent("""\ + aaaaaaaaaaaa = bbbb.ccccccccccccccc(dddddd.eeeeeeeeeeeeee, ffffffffffffffffff, + gggggg.hhhhhhhhhhhhhhhhh) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB15438132(self): + unformatted_code = textwrap.dedent("""\ + if aaaaaaa.bbbbbbbbbb: + cccccc.dddddddddd(eeeeeeeeeee=fffffffffffff.gggggggggggggggggg) + if hhhhhh.iiiii.jjjjjjjjjjjjj: + # This is a comment in the middle of it all. + kkkkkkk.llllllllll.mmmmmmmmmmmmm = True + if (aaaaaa.bbbbb.ccccccccccccc != ddddddd.eeeeeeeeee.fffffffffffff or + eeeeee.fffff.ggggggggggggggggggggggggggg() != hhhhhhh.iiiiiiiiii.jjjjjjjjjjjj): + aaaaaaaa.bbbbbbbbbbbb( + aaaaaa.bbbbb.cc, + dddddddddddd=eeeeeeeeeeeeeeeeeee.fffffffffffffffff( + gggggg.hh, + iiiiiiiiiiiiiiiiiii.jjjjjjjjjj.kkkkkkk, + lllll.mm), + nnnnnnnnnn=ooooooo.pppppppppp) + """) + expected_formatted_code = textwrap.dedent("""\ + if aaaaaaa.bbbbbbbbbb: + cccccc.dddddddddd(eeeeeeeeeee=fffffffffffff.gggggggggggggggggg) + if hhhhhh.iiiii.jjjjjjjjjjjjj: + # This is a comment in the middle of it all. + kkkkkkk.llllllllll.mmmmmmmmmmmmm = True + if (aaaaaa.bbbbb.ccccccccccccc != ddddddd.eeeeeeeeee.fffffffffffff or + eeeeee.fffff.ggggggggggggggggggggggggggg() != + hhhhhhh.iiiiiiiiii.jjjjjjjjjjjj): + aaaaaaaa.bbbbbbbbbbbb( + aaaaaa.bbbbb.cc, + dddddddddddd=eeeeeeeeeeeeeeeeeee.fffffffffffffffff( + gggggg.hh, iiiiiiiiiiiiiiiiiii.jjjjjjjjjj.kkkkkkk, lllll.mm), + nnnnnnnnnn=ooooooo.pppppppppp) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB14468247(self): + unformatted_code = textwrap.dedent("""\ + call(a=1, + b=2, + ) + """) + expected_formatted_code = textwrap.dedent("""\ + call( + a=1, + b=2,) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB14406499(self): + unformatted_code = textwrap.dedent("""\ + def foo1(parameter_1, parameter_2, parameter_3, parameter_4, \ +parameter_5, parameter_6): pass + """) + expected_formatted_code = textwrap.dedent("""\ + def foo1(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, + parameter_6): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB13900309(self): + unformatted_code = textwrap.dedent("""\ + self.aaaaaaaaaaa( # A comment in the middle of it all. + 948.0/3600, self.bbb.ccccccccccccccccccccc(dddddddddddddddd.eeee, True)) + """) + expected_formatted_code = textwrap.dedent("""\ + self.aaaaaaaaaaa( # A comment in the middle of it all. + 948.0 / 3600, self.bbb.ccccccccccccccccccccc(dddddddddddddddd.eeee, True)) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + code = textwrap.dedent("""\ + aaaaaaaaaa.bbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccccc( + DC_1, (CL - 50, CL), AAAAAAAA, BBBBBBBBBBBBBBBB, 98.0, + CCCCCCC).ddddddddd( # Look! A comment is here. + AAAAAAAA - (20 * 60 - 5)) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + unformatted_code = textwrap.dedent("""\ + aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc().dddddddddddddddddddddddddd(1, 2, 3, 4) + """) + expected_formatted_code = textwrap.dedent("""\ + aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc( + ).dddddddddddddddddddddddddd(1, 2, 3, 4) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + unformatted_code = textwrap.dedent("""\ + aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc(x).dddddddddddddddddddddddddd(1, 2, 3, 4) + """) + expected_formatted_code = textwrap.dedent("""\ + aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc( + x).dddddddddddddddddddddddddd(1, 2, 3, 4) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + unformatted_code = textwrap.dedent("""\ + aaaaaaaaaaaaaaaaaaaaaaaa(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx).dddddddddddddddddddddddddd(1, 2, 3, 4) + """) + expected_formatted_code = textwrap.dedent("""\ + aaaaaaaaaaaaaaaaaaaaaaaa( + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx).dddddddddddddddddddddddddd(1, 2, 3, 4) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + unformatted_code = textwrap.dedent("""\ + aaaaaaaaaaaaaaaaaaaaaaaa().bbbbbbbbbbbbbbbbbbbbbbbb().ccccccccccccccccccc().\ +dddddddddddddddddd().eeeeeeeeeeeeeeeeeeeee().fffffffffffffffff().gggggggggggggggggg() + """) + expected_formatted_code = textwrap.dedent("""\ + aaaaaaaaaaaaaaaaaaaaaaaa().bbbbbbbbbbbbbbbbbbbbbbbb().ccccccccccccccccccc( + ).dddddddddddddddddd().eeeeeeeeeeeeeeeeeeeee().fffffffffffffffff( + ).gggggggggggggggggg() + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + +if __name__ == '__main__': + unittest.main() diff --git a/yapftests/reformatter_facebook_test.py b/yapftests/reformatter_facebook_test.py new file mode 100644 index 000000000..c79bf0340 --- /dev/null +++ b/yapftests/reformatter_facebook_test.py @@ -0,0 +1,396 @@ +# Copyright 2015-2016 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Facebook tests for yapf.reformatter.""" + +import textwrap +import unittest + +from yapf.yapflib import reformatter +from yapf.yapflib import style +from yapf.yapflib import verifier + +from yapftests import reformatter_test + + +class TestsForFacebookStyle(reformatter_test.ReformatterTest): + + @classmethod + def setUpClass(cls): + style.SetGlobalStyle(style.CreateFacebookStyle()) + + def testNoNeedForLineBreaks(self): + unformatted_code = textwrap.dedent("""\ + def overly_long_function_name( + just_one_arg, **kwargs): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def overly_long_function_name(just_one_arg, **kwargs): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testDedentClosingBracket(self): + unformatted_code = textwrap.dedent("""\ + def overly_long_function_name( + first_argument_on_the_same_line, + second_argument_makes_the_line_too_long): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def overly_long_function_name( + first_argument_on_the_same_line, second_argument_makes_the_line_too_long + ): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testBreakAfterOpeningBracketIfContentsTooBig(self): + unformatted_code = textwrap.dedent("""\ + def overly_long_function_name(a, b, c, d, e, f, g, h, i, j, k, l, m, + n, o, p, q, r, s, t, u, v, w, x, y, z): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def overly_long_function_name( + a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, \ +v, w, x, y, z + ): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testDedentClosingBracketWithComments(self): + unformatted_code = textwrap.dedent("""\ + def overly_long_function_name( + # comment about the first argument + first_argument_with_a_very_long_name_or_so, + # comment about the second argument + second_argument_makes_the_line_too_long): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def overly_long_function_name( + # comment about the first argument + first_argument_with_a_very_long_name_or_so, + # comment about the second argument + second_argument_makes_the_line_too_long + ): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testDedentImportAsNames(self): + code = textwrap.dedent("""\ + from module import ( + internal_function as function, + SOME_CONSTANT_NUMBER1, + SOME_CONSTANT_NUMBER2, + SOME_CONSTANT_NUMBER3, + ) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testDedentTestListGexp(self): + # TODO(ambv): Arguably _DetermineMustSplitAnnotation shouldn't enforce + # breaks only on the basis of a trailing comma if the entire thing fits + # in a single line. + code = textwrap.dedent("""\ + try: + pass + except ( + IOError, OSError, LookupError, RuntimeError, OverflowError + ) as exception: + pass + + try: + pass + except ( + IOError, + OSError, + LookupError, + RuntimeError, + OverflowError, + ) as exception: + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testBrokenIdempotency(self): + # TODO(ambv): The following behaviour should be fixed. + pass0_code = textwrap.dedent("""\ + try: + pass + except (IOError, OSError, LookupError, RuntimeError, OverflowError) as exception: + pass + """) + pass1_code = textwrap.dedent("""\ + try: + pass + except ( + IOError, OSError, LookupError, RuntimeError, OverflowError + ) as exception: + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(pass0_code) + self.assertCodeEqual(pass1_code, reformatter.Reformat(uwlines)) + + pass2_code = textwrap.dedent("""\ + try: + pass + except ( + IOError, OSError, LookupError, RuntimeError, OverflowError + ) as exception: + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(pass1_code) + self.assertCodeEqual(pass2_code, reformatter.Reformat(uwlines)) + + def testIfExprHangingIndent(self): + unformatted_code = textwrap.dedent("""\ + if True: + if True: + if True: + if not self.frobbies and ( + self.foobars.counters['db.cheeses'] != 1 or + self.foobars.counters['db.marshmellow_skins'] != 1): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + if True: + if True: + if True: + if not self.frobbies and ( + self.foobars.counters['db.cheeses'] != 1 or + self.foobars.counters['db.marshmellow_skins'] != 1 + ): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSimpleDedenting(self): + unformatted_code = textwrap.dedent("""\ + if True: + self.assertEqual(result.reason_not_added, "current preflight is still running") + """) + expected_formatted_code = textwrap.dedent("""\ + if True: + self.assertEqual( + result.reason_not_added, "current preflight is still running" + ) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testDedentingWithSubscripts(self): + unformatted_code = textwrap.dedent("""\ + class Foo: + class Bar: + @classmethod + def baz(cls, clues_list, effect, constraints, constraint_manager): + if clues_lists: + return cls.single_constraint_not(clues_lists, effect, constraints[0], constraint_manager) + + """) + expected_formatted_code = textwrap.dedent("""\ + class Foo: + class Bar: + @classmethod + def baz(cls, clues_list, effect, constraints, constraint_manager): + if clues_lists: + return cls.single_constraint_not( + clues_lists, effect, constraints[0], constraint_manager + ) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testDedentingCallsWithInnerLists(self): + code = textwrap.dedent("""\ + class _(): + def _(): + cls.effect_clues = { + 'effect': Clue((cls.effect_time, 'apache_host'), effect_line, 40) + } + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testDedentingListComprehension(self): + unformatted_code = textwrap.dedent("""\ + class Foo(): + def _pack_results_for_constraint_or(): + self.param_groups = dict( + ( + key + 1, ParamGroup(groups[key], default_converter) + ) for key in six.moves.range(len(groups)) + ) + + for combination in cls._clues_combinations(clues_lists): + if all( + cls._verify_constraint(combination, effect, constraint) + for constraint in constraints + ): + pass + + guessed_dict = dict( + ( + key, guessed_pattern_matches[key] + ) for key in six.moves.range(len(guessed_pattern_matches)) + ) + + content = "".join( + itertools.chain( + (first_line_fragment, ), lines_between, (last_line_fragment, ) + ) + ) + + rule = Rule( + [self.cause1, self.cause2, self.cause1, self.cause2], self.effect, constraints1, + Rule.LINKAGE_AND + ) + + assert sorted(log_type.files_to_parse) == [ + ('localhost', os.path.join(path, 'node_1.log'), super_parser), + ('localhost', os.path.join(path, 'node_2.log'), super_parser) + ] + """) + expected_formatted_code = textwrap.dedent("""\ + class Foo(): + def _pack_results_for_constraint_or(): + self.param_groups = dict( + (key + 1, ParamGroup(groups[key], default_converter)) + for key in six.moves.range(len(groups)) + ) + + for combination in cls._clues_combinations(clues_lists): + if all( + cls._verify_constraint(combination, effect, constraint) + for constraint in constraints + ): + pass + + guessed_dict = dict( + (key, guessed_pattern_matches[key]) + for key in six.moves.range(len(guessed_pattern_matches)) + ) + + content = "".join( + itertools.chain( + (first_line_fragment, ), lines_between, (last_line_fragment, ) + ) + ) + + rule = Rule( + [self.cause1, self.cause2, self.cause1, self.cause2], self.effect, + constraints1, Rule.LINKAGE_AND + ) + + assert sorted(log_type.files_to_parse) == [ + ('localhost', os.path.join(path, 'node_1.log'), super_parser), + ('localhost', os.path.join(path, 'node_2.log'), super_parser) + ] + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testMustSplitDedenting(self): + code = textwrap.dedent("""\ + class _(): + def _(): + effect_line = FrontInput( + effect_line_offset, line_content, + LineSource( + 'localhost', xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + ) + ) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testDedentIfConditional(self): + code = textwrap.dedent("""\ + class _(): + def _(): + if True: + if not self.frobbies and ( + self.foobars.counters['db.cheeses'] != 1 or + self.foobars.counters['db.marshmellow_skins'] != 1 + ): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testDedentSet(self): + code = textwrap.dedent("""\ + class _(): + def _(): + assert set(self.constraint_links.get_links()) == set( + [ + (2, 10, 100), + (2, 10, 200), + (2, 20, 100), + (2, 20, 200), + ] + ) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testDedentingInnerScope(self): + code = textwrap.dedent("""\ + class Foo(): + @classmethod + def _pack_results_for_constraint_or(cls, combination, constraints): + return cls._create_investigation_result( + (clue for clue in combination if not clue == Verifier.UNMATCHED), + constraints, InvestigationResult.OR + ) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + reformatted_code = reformatter.Reformat(uwlines) + self.assertCodeEqual(code, reformatted_code) + + uwlines = reformatter_test.ParseAndUnwrap(reformatted_code) + reformatted_code = reformatter.Reformat(uwlines) + self.assertCodeEqual(code, reformatted_code) + + def testCommentWithNewlinesInPrefix(self): + code = textwrap.dedent("""\ + def foo(): + if 0: + return False + + #a deadly comment + elif 1: + return True + + + print(foo()) + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + reformatted_code = reformatter.Reformat(uwlines) + self.assertCodeEqual(code, reformatted_code) + + +if __name__ == '__main__': + unittest.main() diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py new file mode 100644 index 000000000..169b1d48d --- /dev/null +++ b/yapftests/reformatter_pep8_test.py @@ -0,0 +1,301 @@ +# Copyright 2015-2016 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""PEP8 tests for yapf.reformatter.""" + +import textwrap +import unittest + +from yapf.yapflib import reformatter +from yapf.yapflib import style + +from yapftests import reformatter_test + + +class TestsForPEP8Style(reformatter_test.ReformatterTest): + + @classmethod + def setUpClass(cls): + style.SetGlobalStyle(style.CreatePEP8Style()) + + def testIndent4(self): + unformatted_code = textwrap.dedent("""\ + if a+b: + pass + """) + expected_formatted_code = textwrap.dedent("""\ + if a + b: + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSingleLineIfStatements(self): + code = textwrap.dedent("""\ + if True: a = 42 + elif False: b = 42 + else: c = 42 + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testNoBlankBetweenClassAndDef(self): + unformatted_code = textwrap.dedent("""\ + class Foo: + + def joe(): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + class Foo: + def joe(): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSingleWhiteBeforeTrailingComment(self): + unformatted_code = textwrap.dedent("""\ + if a+b: # comment + pass + """) + expected_formatted_code = textwrap.dedent("""\ + if a + b: # comment + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSplittingSemicolonStatements(self): + unformatted_code = textwrap.dedent("""\ + def f(): + x = y + 42 ; z = n * 42 + if True: a += 1 ; b += 1; c += 1 + """) + expected_formatted_code = textwrap.dedent("""\ + def f(): + x = y + 42 + z = n * 42 + if True: + a += 1 + b += 1 + c += 1 + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSpaceBetweenEndingCommandAndClosingBracket(self): + unformatted_code = textwrap.dedent("""\ + a = [ + 1, + ] + """) + expected_formatted_code = textwrap.dedent("""\ + a = [1, ] + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testContinuedNonOudentedLine(self): + code = textwrap.dedent("""\ + class eld(d): + if str(geom.geom_type).upper( + ) != self.geom_type and not self.geom_type == 'GEOMETRY': + ror(code='om_type') + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testWrappingPercentExpressions(self): + unformatted_code = textwrap.dedent("""\ + def f(): + if True: + zzzzz = '%s-%s' % (xxxxxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxx.yyy + 1) + zzzzz = '%s-%s'.ww(xxxxxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxx.yyy + 1) + zzzzz = '%s-%s' % (xxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxxxxxx + 1) + zzzzz = '%s-%s'.ww(xxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxxxxxx + 1) + """) + expected_formatted_code = textwrap.dedent("""\ + def f(): + if True: + zzzzz = '%s-%s' % (xxxxxxxxxxxxxxxxxxxxxxxxxx + 1, + xxxxxxxxxxxxxxxxx.yyy + 1) + zzzzz = '%s-%s'.ww(xxxxxxxxxxxxxxxxxxxxxxxxxx + 1, + xxxxxxxxxxxxxxxxx.yyy + 1) + zzzzz = '%s-%s' % (xxxxxxxxxxxxxxxxxxxxxxx + 1, + xxxxxxxxxxxxxxxxxxxxx + 1) + zzzzz = '%s-%s'.ww(xxxxxxxxxxxxxxxxxxxxxxx + 1, + xxxxxxxxxxxxxxxxxxxxx + 1) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testAlignClosingBracketWithVisualIndentation(self): + unformatted_code = textwrap.dedent("""\ + TEST_LIST = ('foo', 'bar', # first comment + 'baz' # second comment + ) + """) + expected_formatted_code = textwrap.dedent("""\ + TEST_LIST = ( + 'foo', + 'bar', # first comment + 'baz' # second comment + ) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + unformatted_code = textwrap.dedent("""\ + def f(): + + def g(): + while (xxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz]) == 'aaaaaaaaaaa' and + xxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb' + ): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def f(): + def g(): + while (xxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz]) == 'aaaaaaaaaaa' and + xxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == + 'bbbbbbb'): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testIndentSizeChanging(self): + unformatted_code = textwrap.dedent("""\ + if True: + runtime_mins = (program_end_time - program_start_time).total_seconds() / 60.0 + """) + expected_formatted_code = textwrap.dedent("""\ + if True: + runtime_mins = ( + program_end_time - program_start_time).total_seconds() / 60.0 + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testHangingIndentCollision(self): + unformatted_code = textwrap.dedent("""\ + if (aaaaaaaaaaaaaa + bbbbbbbbbbbbbbbb == ccccccccccccccccc and xxxxxxxxxxxxx or yyyyyyyyyyyyyyyyy): + pass + elif (xxxxxxxxxxxxxxx(aaaaaaaaaaa, bbbbbbbbbbbbbb, cccccccccccc, dddddddddd=None)): + pass + + + def h(): + if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): + pass + + for connection in itertools.chain(branch.contact, branch.address, morestuff.andmore.andmore.andmore.andmore.andmore.andmore.andmore): + dosomething(connection) + """) + expected_formatted_code = textwrap.dedent("""\ + if (aaaaaaaaaaaaaa + bbbbbbbbbbbbbbbb == ccccccccccccccccc and xxxxxxxxxxxxx or + yyyyyyyyyyyyyyyyy): + pass + elif (xxxxxxxxxxxxxxx( + aaaaaaaaaaa, bbbbbbbbbbbbbb, cccccccccccc, dddddddddd=None)): + pass + + + def h(): + if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and + xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): + pass + + for connection in itertools.chain( + branch.contact, branch.address, + morestuff.andmore.andmore.andmore.andmore.andmore.andmore.andmore): + dosomething(connection) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSplittingBeforeLogicalOperator(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: pep8, split_before_logical_operator: True}')) + unformatted_code = textwrap.dedent("""\ + def foo(): + return bool(update.message.new_chat_member or update.message.left_chat_member or + update.message.new_chat_title or update.message.new_chat_photo or + update.message.delete_chat_photo or update.message.group_chat_created or + update.message.supergroup_chat_created or update.message.channel_chat_created + or update.message.migrate_to_chat_id or update.message.migrate_from_chat_id or + update.message.pinned_message) + """) + expected_formatted_code = textwrap.dedent("""\ + def foo(): + return bool( + update.message.new_chat_member or update.message.left_chat_member + or update.message.new_chat_title or update.message.new_chat_photo + or update.message.delete_chat_photo + or update.message.group_chat_created + or update.message.supergroup_chat_created + or update.message.channel_chat_created + or update.message.migrate_to_chat_id + or update.message.migrate_from_chat_id + or update.message.pinned_message) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreatePEP8Style()) + + def testContiguousListEndingWithComment(self): + unformatted_code = textwrap.dedent("""\ + if True: + if True: + keys.append(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) # may be unassigned. + """) + expected_formatted_code = textwrap.dedent("""\ + if True: + if True: + keys.append( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) # may be unassigned. + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSplittingBeforeFirstArgument(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: pep8, split_before_first_argument: True}')) + unformatted_code = textwrap.dedent("""\ + a_very_long_function_name(long_argument_name_1=1, long_argument_name_2=2, + long_argument_name_3=3, long_argument_name_4=4) + """) + expected_formatted_code = textwrap.dedent("""\ + a_very_long_function_name( + long_argument_name_1=1, + long_argument_name_2=2, + long_argument_name_3=3, + long_argument_name_4=4) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreatePEP8Style()) + + +if __name__ == '__main__': + unittest.main() diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py new file mode 100644 index 000000000..78be3d050 --- /dev/null +++ b/yapftests/reformatter_python3_test.py @@ -0,0 +1,167 @@ +# Copyright 2015-2016 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Python 3 tests for yapf.reformatter.""" + +import sys +import textwrap +import unittest + +from yapf.yapflib import py3compat +from yapf.yapflib import reformatter +from yapf.yapflib import style + +from yapftests import reformatter_test + + +@unittest.skipUnless(py3compat.PY3, 'Requires Python 3') +class TestsForPython3Code(reformatter_test.ReformatterTest): + """Test a few constructs that are new Python 3 syntax.""" + + @classmethod + def setUpClass(cls): + style.SetGlobalStyle(style.CreatePEP8Style()) + + def testTypedNames(self): + unformatted_code = textwrap.dedent("""\ + def x(aaaaaaaaaaaaaaa:int,bbbbbbbbbbbbbbbb:str,ccccccccccccccc:dict,eeeeeeeeeeeeee:set={1, 2, 3})->bool: + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def x(aaaaaaaaaaaaaaa: int, + bbbbbbbbbbbbbbbb: str, + ccccccccccccccc: dict, + eeeeeeeeeeeeee: set={1, 2, 3}) -> bool: + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testKeywordOnlyArgSpecifier(self): + unformatted_code = textwrap.dedent("""\ + def foo(a, *, kw): + return a+kw + """) + expected_formatted_code = textwrap.dedent("""\ + def foo(a, *, kw): + return a + kw + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testAnnotations(self): + unformatted_code = textwrap.dedent("""\ + def foo(a: list, b: "bar") -> dict: + return a+b + """) + expected_formatted_code = textwrap.dedent("""\ + def foo(a: list, b: "bar") -> dict: + return a + b + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testExecAsNonKeyword(self): + unformatted_code = 'methods.exec( sys.modules[name])\n' + expected_formatted_code = 'methods.exec(sys.modules[name])\n' + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testAsyncFunctions(self): + if sys.version_info[1] < 5: + return + code = textwrap.dedent("""\ + import asyncio + import time + + + @print_args + async def slow_operation(): + await asyncio.sleep(1) + # print("Slow operation {} complete".format(n)) + + + async def main(): + start = time.time() + if (await get_html()): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines, verify=False)) + + def testNoSpacesAroundPowerOparator(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: pep8, SPACES_AROUND_POWER_OPERATOR: True}')) + unformatted_code = textwrap.dedent("""\ + a**b + """) + expected_formatted_code = textwrap.dedent("""\ + a ** b + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreatePEP8Style()) + + def testSpacesAroundDefaultOrNamedAssign(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: pep8, ' + 'SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN: True}')) + unformatted_code = textwrap.dedent("""\ + f(a=5) + """) + expected_formatted_code = textwrap.dedent("""\ + f(a = 5) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreatePEP8Style()) + + def testAsyncWithPrecedingComment(self): + if sys.version_info[1] < 5: + return + unformatted_code = textwrap.dedent("""\ + import asyncio + + # Comment + async def bar(): + pass + + async def foo(): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + import asyncio + + + # Comment + async def bar(): + pass + + + async def foo(): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + +if __name__ == '__main__': + unittest.main() diff --git a/yapftests/reformatter_style_config_test.py b/yapftests/reformatter_style_config_test.py new file mode 100644 index 000000000..0186fa8db --- /dev/null +++ b/yapftests/reformatter_style_config_test.py @@ -0,0 +1,61 @@ +# Copyright 2015-2016 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Style config tests for yapf.reformatter.""" + +import textwrap +import unittest + +from yapf.yapflib import reformatter +from yapf.yapflib import style + +from yapftests import reformatter_test + + +class TestsForStyleConfig(reformatter_test.ReformatterTest): + + def setUp(self): + self.current_style = style.DEFAULT_STYLE + + def testSetGlobalStyle(self): + try: + style.SetGlobalStyle(style.CreateChromiumStyle()) + unformatted_code = textwrap.dedent(u"""\ + for i in range(5): + print('bar') + """) + expected_formatted_code = textwrap.dedent(u"""\ + for i in range(5): + print('bar') + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreatePEP8Style()) + style.DEFAULT_STYLE = self.current_style + + unformatted_code = textwrap.dedent(u"""\ + for i in range(5): + print('bar') + """) + expected_formatted_code = textwrap.dedent(u"""\ + for i in range(5): + print('bar') + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + +if __name__ == '__main__': + unittest.main() diff --git a/yapftests/reformatter_test.py b/yapftests/reformatter_test.py index bff7a4a76..37fdb6fd7 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/reformatter_test.py @@ -11,25 +11,21 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -"""Tests for yapf.reformatter.""" +"""Support module for tests for yapf.reformatter.""" import difflib import sys -import textwrap import unittest from yapf.yapflib import blank_line_calculator from yapf.yapflib import comment_splicer from yapf.yapflib import continuation_splicer -from yapf.yapflib import py3compat from yapf.yapflib import pytree_unwrapper from yapf.yapflib import pytree_utils from yapf.yapflib import pytree_visitor -from yapf.yapflib import reformatter from yapf.yapflib import split_penalty from yapf.yapflib import style from yapf.yapflib import subtype_assigner -from yapf.yapflib import verifier class ReformatterTest(unittest.TestCase): @@ -60,4021 +56,7 @@ def assertCodeEqual(self, expected_code, code): self.fail('\n'.join(msg)) -class BasicReformatterTest(ReformatterTest): - - @classmethod - def setUpClass(cls): - style.SetGlobalStyle(style.CreateChromiumStyle()) - - def testSimple(self): - unformatted_code = textwrap.dedent("""\ - if a+b: - pass - """) - expected_formatted_code = textwrap.dedent("""\ - if a + b: - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testSimpleFunctions(self): - unformatted_code = textwrap.dedent("""\ - def g(): - pass - - def f(): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - def g(): - pass - - - def f(): - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testSimpleFunctionsWithTrailingComments(self): - unformatted_code = textwrap.dedent("""\ - def g(): # Trailing comment - if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and - xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): - pass - - def f( # Intermediate comment - ): - if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and - xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - def g(): # Trailing comment - if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and - xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): - pass - - - def f( # Intermediate comment - ): - if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and - xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testBlankLinesAtEndOfFile(self): - unformatted_code = textwrap.dedent("""\ - def foobar(): # foo - pass - - - - """) - expected_formatted_code = textwrap.dedent("""\ - def foobar(): # foo - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - unformatted_code = textwrap.dedent("""\ - x = { 'a':37,'b':42, - - 'c':927} - - """) - expected_formatted_code = textwrap.dedent("""\ - x = {'a': 37, 'b': 42, 'c': 927} - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testMultipleUgliness(self): - unformatted_code = textwrap.dedent("""\ - x = { 'a':37,'b':42, - - 'c':927} - - y = 'hello ''world' - z = 'hello '+'world' - a = 'hello {}'.format('world') - class foo ( object ): - def f (self ): - return 37*-+2 - def g(self, x,y=42): - return y - def f ( a ) : - return 37+-+a[42-x : y**3] - """) - expected_formatted_code = textwrap.dedent("""\ - x = {'a': 37, 'b': 42, 'c': 927} - - y = 'hello ' 'world' - z = 'hello ' + 'world' - a = 'hello {}'.format('world') - - - class foo(object): - - def f(self): - return 37 * -+2 - - def g(self, x, y=42): - return y - - - def f(a): - return 37 + -+a[42 - x:y**3] - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testComments(self): - unformatted_code = textwrap.dedent("""\ - class Foo(object): - pass - - # Attached comment - class Bar(object): - pass - - global_assignment = 42 - - # Comment attached to class with decorator. - # Comment attached to class with decorator. - @noop - @noop - class Baz(object): - pass - - # Intermediate comment - - class Qux(object): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - class Foo(object): - pass - - - # Attached comment - class Bar(object): - pass - - - global_assignment = 42 - - - # Comment attached to class with decorator. - # Comment attached to class with decorator. - @noop - @noop - class Baz(object): - pass - - - # Intermediate comment - - - class Qux(object): - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testSingleComment(self): - code = textwrap.dedent("""\ - # Thing 1 - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testCommentsInDataLiteral(self): - code = textwrap.dedent("""\ - def f(): - return collections.OrderedDict({ - # First comment. - 'fnord': 37, - - # Second comment. - # Continuation of second comment. - 'bork': 42, - - # Ending comment. - }) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testEndingWhitespaceAfterSimpleStatement(self): - code = textwrap.dedent("""\ - import foo as bar - # Thing 1 - # Thing 2 - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testDocstrings(self): - unformatted_code = textwrap.dedent('''\ - u"""Module-level docstring.""" - import os - class Foo(object): - - """Class-level docstring.""" - # A comment for qux. - def qux(self): - - - """Function-level docstring. - - A multiline function docstring. - """ - print('hello {}'.format('world')) - return 42 - ''') - expected_formatted_code = textwrap.dedent('''\ - u"""Module-level docstring.""" - import os - - - class Foo(object): - """Class-level docstring.""" - - # A comment for qux. - def qux(self): - """Function-level docstring. - - A multiline function docstring. - """ - print('hello {}'.format('world')) - return 42 - ''') - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testDocstringAndMultilineComment(self): - unformatted_code = textwrap.dedent('''\ - """Hello world""" - # A multiline - # comment - class bar(object): - """class docstring""" - # class multiline - # comment - def foo(self): - """Another docstring.""" - # Another multiline - # comment - pass - ''') - expected_formatted_code = textwrap.dedent('''\ - """Hello world""" - - - # A multiline - # comment - class bar(object): - """class docstring""" - - # class multiline - # comment - def foo(self): - """Another docstring.""" - # Another multiline - # comment - pass - ''') - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testMultilineDocstringAndMultilineComment(self): - unformatted_code = textwrap.dedent('''\ - """Hello world - - RIP Dennis Richie. - """ - # A multiline - # comment - class bar(object): - """class docstring - - A classy class. - """ - # class multiline - # comment - def foo(self): - """Another docstring. - - A functional function. - """ - # Another multiline - # comment - pass - ''') - expected_formatted_code = textwrap.dedent('''\ - """Hello world - - RIP Dennis Richie. - """ - - - # A multiline - # comment - class bar(object): - """class docstring - - A classy class. - """ - - # class multiline - # comment - def foo(self): - """Another docstring. - - A functional function. - """ - # Another multiline - # comment - pass - ''') - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testTupleCommaBeforeLastParen(self): - unformatted_code = textwrap.dedent("""\ - a = ( 1, ) - """) - expected_formatted_code = textwrap.dedent("""\ - a = (1,) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testNoBreakOutsideOfBracket(self): - # FIXME(morbo): How this is formatted is not correct. But it's syntactically - # correct. - unformatted_code = textwrap.dedent("""\ - def f(): - assert port >= minimum, \ -'Unexpected port %d when minimum was %d.' % (port, minimum) - """) - expected_formatted_code = textwrap.dedent("""\ - def f(): - assert port >= minimum, 'Unexpected port %d when minimum was %d.' % (port, - minimum) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testBlankLinesBeforeDecorators(self): - unformatted_code = textwrap.dedent("""\ - @foo() - class A(object): - @bar() - @baz() - def x(self): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - @foo() - class A(object): - - @bar() - @baz() - def x(self): - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testCommentBetweenDecorators(self): - unformatted_code = textwrap.dedent("""\ - @foo() - # frob - @bar - def x (self): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - @foo() - # frob - @bar - def x(self): - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testListComprehension(self): - unformatted_code = textwrap.dedent("""\ - def given(y): - [k for k in () - if k in y] - """) - expected_formatted_code = textwrap.dedent("""\ - def given(y): - [k for k in () if k in y] - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testOpeningAndClosingBrackets(self): - unformatted_code = textwrap.dedent("""\ - foo( ( 1, 2, 3, ) ) - """) - expected_formatted_code = textwrap.dedent("""\ - foo(( - 1, - 2, - 3,)) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testSingleLineFunctions(self): - unformatted_code = textwrap.dedent("""\ - def foo(): return 42 - """) - expected_formatted_code = textwrap.dedent("""\ - def foo(): - return 42 - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testNoQueueSeletionInMiddleOfLine(self): - # If the queue isn't properly consttructed, then a token in the middle of - # the line may be selected as the one with least penalty. The tokens after - # that one are then splatted at the end of the line with no formatting. - # FIXME(morbo): The formatting here isn't ideal. - unformatted_code = textwrap.dedent("""\ - find_symbol(node.type) + "< " + " ".join(find_pattern(n) for n in \ -node.child) + " >" - """) - expected_formatted_code = textwrap.dedent("""\ - find_symbol(node.type) + "< " + " ".join(find_pattern(n) - for n in node.child) + " >" - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testNoSpacesBetweenSubscriptsAndCalls(self): - unformatted_code = textwrap.dedent("""\ - aaaaaaaaaa = bbbbbbbb.ccccccccc() [42] (a, 2) - """) - expected_formatted_code = textwrap.dedent("""\ - aaaaaaaaaa = bbbbbbbb.ccccccccc()[42](a, 2) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testNoSpacesBetweenOpeningBracketAndStartingOperator(self): - # Unary operator. - unformatted_code = textwrap.dedent("""\ - aaaaaaaaaa = bbbbbbbb.ccccccccc[ -1 ]( -42 ) - """) - expected_formatted_code = textwrap.dedent("""\ - aaaaaaaaaa = bbbbbbbb.ccccccccc[-1](-42) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - # Varargs and kwargs. - unformatted_code = textwrap.dedent("""\ - aaaaaaaaaa = bbbbbbbb.ccccccccc( *varargs ) - aaaaaaaaaa = bbbbbbbb.ccccccccc( **kwargs ) - """) - expected_formatted_code = textwrap.dedent("""\ - aaaaaaaaaa = bbbbbbbb.ccccccccc(*varargs) - aaaaaaaaaa = bbbbbbbb.ccccccccc(**kwargs) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testMultilineCommentReformatted(self): - unformatted_code = textwrap.dedent("""\ - if True: - # This is a multiline - # comment. - pass - """) - expected_formatted_code = textwrap.dedent("""\ - if True: - # This is a multiline - # comment. - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testDictionaryMakerFormatting(self): - unformatted_code = textwrap.dedent("""\ - _PYTHON_STATEMENTS = frozenset({ - lambda x, y: 'simple_stmt': 'small_stmt', 'expr_stmt': 'print_stmt', 'del_stmt': - 'pass_stmt', lambda: 'break_stmt': 'continue_stmt', 'return_stmt': 'raise_stmt', - 'yield_stmt': 'import_stmt', lambda: 'global_stmt': 'exec_stmt', 'assert_stmt': - 'if_stmt', 'while_stmt': 'for_stmt', - }) - """) - expected_formatted_code = textwrap.dedent("""\ - _PYTHON_STATEMENTS = frozenset({ - lambda x, y: 'simple_stmt': 'small_stmt', - 'expr_stmt': 'print_stmt', - 'del_stmt': 'pass_stmt', - lambda: 'break_stmt': 'continue_stmt', - 'return_stmt': 'raise_stmt', - 'yield_stmt': 'import_stmt', - lambda: 'global_stmt': 'exec_stmt', - 'assert_stmt': 'if_stmt', - 'while_stmt': 'for_stmt', - }) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testSimpleMultilineCode(self): - unformatted_code = textwrap.dedent("""\ - if True: - aaaaaaaaaaaaaa.bbbbbbbbbbbbbb.ccccccc(zzzzzzzzzzzz, \ -xxxxxxxxxxx, yyyyyyyyyyyy, vvvvvvvvv) - aaaaaaaaaaaaaa.bbbbbbbbbbbbbb.ccccccc(zzzzzzzzzzzz, \ -xxxxxxxxxxx, yyyyyyyyyyyy, vvvvvvvvv) - """) - expected_formatted_code = textwrap.dedent("""\ - if True: - aaaaaaaaaaaaaa.bbbbbbbbbbbbbb.ccccccc(zzzzzzzzzzzz, xxxxxxxxxxx, yyyyyyyyyyyy, - vvvvvvvvv) - aaaaaaaaaaaaaa.bbbbbbbbbbbbbb.ccccccc(zzzzzzzzzzzz, xxxxxxxxxxx, yyyyyyyyyyyy, - vvvvvvvvv) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testMultilineComment(self): - code = textwrap.dedent("""\ - if Foo: - # Hello world - # Yo man. - # Yo man. - # Yo man. - # Yo man. - a = 42 - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testMultilineString(self): - code = textwrap.dedent("""\ - code = textwrap.dedent('''\ - if Foo: - # Hello world - # Yo man. - # Yo man. - # Yo man. - # Yo man. - a = 42 - ''') - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - unformatted_code = textwrap.dedent('''\ - def f(): - email_text += """This is a really long docstring that goes over the column limit and is multi-line.

- Czar: """+despot["Nicholas"]+"""
- Minion: """+serf["Dmitri"]+"""
- Residence: """+palace["Winter"]+"""
- - """ - ''') - expected_formatted_code = textwrap.dedent('''\ - def f(): - email_text += """This is a really long docstring that goes over the column limit and is multi-line.

- Czar: """ + despot["Nicholas"] + """
- Minion: """ + serf["Dmitri"] + """
- Residence: """ + palace["Winter"] + """
- - """ - ''') - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testSimpleMultilineWithComments(self): - code = textwrap.dedent("""\ - if ( # This is the first comment - a and # This is the second comment - # This is the third comment - b): # A trailing comment - # Whoa! A normal comment!! - pass # Another trailing comment - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testMatchingParenSplittingMatching(self): - unformatted_code = textwrap.dedent("""\ - def f(): - raise RuntimeError('unable to find insertion point for target node', - (target,)) - """) - expected_formatted_code = textwrap.dedent("""\ - def f(): - raise RuntimeError('unable to find insertion point for target node', - (target,)) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testContinuationIndent(self): - unformatted_code = textwrap.dedent('''\ - class F: - def _ProcessArgLists(self, node): - """Common method for processing argument lists.""" - for child in node.children: - if isinstance(child, pytree.Leaf): - self._SetTokenSubtype( - child, subtype=_ARGLIST_TOKEN_TO_SUBTYPE.get( - child.value, format_token.Subtype.NONE)) - ''') - expected_formatted_code = textwrap.dedent('''\ - class F: - - def _ProcessArgLists(self, node): - """Common method for processing argument lists.""" - for child in node.children: - if isinstance(child, pytree.Leaf): - self._SetTokenSubtype( - child, - subtype=_ARGLIST_TOKEN_TO_SUBTYPE.get(child.value, - format_token.Subtype.NONE)) - ''') - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testTrailingCommaAndBracket(self): - unformatted_code = textwrap.dedent('''\ - a = { 42, } - b = ( 42, ) - c = [ 42, ] - ''') - expected_formatted_code = textwrap.dedent('''\ - a = {42,} - b = (42,) - c = [42,] - ''') - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testI18n(self): - code = textwrap.dedent("""\ - N_('Some years ago - never mind how long precisely - having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world.') # A comment is here. - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - code = textwrap.dedent("""\ - foo('Fake function call') #. Some years ago - never mind how long precisely - having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testI18nCommentsInDataLiteral(self): - code = textwrap.dedent("""\ - def f(): - return collections.OrderedDict({ - #. First i18n comment. - 'bork': 'foo', - - #. Second i18n comment. - 'snork': 'bar#.*=\\\\0', - }) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testClosingBracketIndent(self): - code = textwrap.dedent('''\ - def f(): - - def g(): - while ( - xxxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz]) == 'aaaaaaaaaaa' and - xxxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): - pass - ''') - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testClosingBracketsInlinedInCall(self): - unformatted_code = textwrap.dedent("""\ - class Foo(object): - - def bar(self): - self.aaaaaaaa = xxxxxxxxxxxxxxxxxxx.yyyyyyyyyyyyy( - self.cccccc.ddddddddd.eeeeeeee, - options={ - "forkforkfork": 1, - "borkborkbork": 2, - "corkcorkcork": 3, - "horkhorkhork": 4, - "porkporkpork": 5, - }) - """) - expected_formatted_code = textwrap.dedent("""\ - class Foo(object): - - def bar(self): - self.aaaaaaaa = xxxxxxxxxxxxxxxxxxx.yyyyyyyyyyyyy( - self.cccccc.ddddddddd.eeeeeeee, - options={ - "forkforkfork": 1, - "borkborkbork": 2, - "corkcorkcork": 3, - "horkhorkhork": 4, - "porkporkpork": 5, - }) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testLineWrapInForExpression(self): - code = textwrap.dedent("""\ - class A: - - def x(self, node, name, n=1): - for i, child in enumerate( - itertools.ifilter(lambda c: pytree_utils.NodeName(c) == name, - node.pre_order())): - pass - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testFunctionCallContinuationLine(self): - code = textwrap.dedent("""\ - class foo: - - def bar(self, node, name, n=1): - if True: - if True: - return [(aaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb( - cccc, ddddddddddddddddddddddddddddddddddddd))] - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testI18nNonFormatting(self): - code = textwrap.dedent("""\ - class F(object): - - def __init__(self, fieldname, - #. Error message indicating an invalid e-mail address. - message=N_('Please check your email address.'), **kwargs): - pass - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testNoSpaceBetweenUnaryOpAndOpeningParen(self): - code = textwrap.dedent("""\ - if ~(a or b): - pass - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testCommentBeforeFuncDef(self): - code = textwrap.dedent("""\ - class Foo(object): - - a = 42 - - # This is a comment. - def __init__(self, - xxxxxxx, - yyyyy=0, - zzzzzzz=None, - aaaaaaaaaaaaaaaaaa=False, - bbbbbbbbbbbbbbb=False): - pass - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testExcessLineCountWithDefaultKeywords(self): - unformatted_code = textwrap.dedent("""\ - class Fnord(object): - def Moo(self): - aaaaaaaaaaaaaaaa = self._bbbbbbbbbbbbbbbbbbbbbbb( - ccccccccccccc=ccccccccccccc, ddddddd=ddddddd, eeee=eeee, - fffff=fffff, ggggggg=ggggggg, hhhhhhhhhhhhh=hhhhhhhhhhhhh, - iiiiiii=iiiiiiiiiiiiii) - """) - expected_formatted_code = textwrap.dedent("""\ - class Fnord(object): - - def Moo(self): - aaaaaaaaaaaaaaaa = self._bbbbbbbbbbbbbbbbbbbbbbb( - ccccccccccccc=ccccccccccccc, - ddddddd=ddddddd, - eeee=eeee, - fffff=fffff, - ggggggg=ggggggg, - hhhhhhhhhhhhh=hhhhhhhhhhhhh, - iiiiiii=iiiiiiiiiiiiii) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testSpaceAfterNotOperator(self): - code = textwrap.dedent("""\ - if not (this and that): - pass - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testNoPenaltySplitting(self): - code = textwrap.dedent("""\ - def f(): - if True: - if True: - python_files.extend( - os.path.join(filename, f) for f in os.listdir(filename) - if IsPythonFile(os.path.join(filename, f))) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testExpressionPenalties(self): - code = textwrap.dedent("""\ - def f(): - if ((left.value == '(' and right.value == ')') or - (left.value == '[' and right.value == ']') or - (left.value == '{' and right.value == '}')): - return False - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testLineDepthOfSingleLineStatement(self): - unformatted_code = textwrap.dedent("""\ - while True: continue - for x in range(3): continue - try: a = 42 - except: b = 42 - with open(a) as fd: a = fd.read() - """) - expected_formatted_code = textwrap.dedent("""\ - while True: - continue - for x in range(3): - continue - try: - a = 42 - except: - b = 42 - with open(a) as fd: - a = fd.read() - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testSplitListWithTerminatingComma(self): - unformatted_code = textwrap.dedent("""\ - FOO = ['bar', 'baz', 'mux', 'qux', 'quux', 'quuux', 'quuuux', - 'quuuuux', 'quuuuuux', 'quuuuuuux', lambda a, b: 37,] - """) - expected_formatted_code = textwrap.dedent("""\ - FOO = [ - 'bar', - 'baz', - 'mux', - 'qux', - 'quux', - 'quuux', - 'quuuux', - 'quuuuux', - 'quuuuuux', - 'quuuuuuux', - lambda a, b: 37, - ] - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testSplitListWithInterspersedComments(self): - code = textwrap.dedent("""\ - FOO = [ - 'bar', # bar - 'baz', # baz - 'mux', # mux - 'qux', # qux - 'quux', # quux - 'quuux', # quuux - 'quuuux', # quuuux - 'quuuuux', # quuuuux - 'quuuuuux', # quuuuuux - 'quuuuuuux', # quuuuuuux - lambda a, b: 37 # lambda - ] - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testRelativeImportStatements(self): - code = textwrap.dedent("""\ - from ... import bork - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testSingleLineList(self): - # A list on a single line should prefer to remain contiguous. - unformatted_code = textwrap.dedent("""\ - bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = aaaaaaaaaaa( - ("...", "."), "..", - ".............................................." - ) - """) - expected_formatted_code = textwrap.dedent("""\ - bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = aaaaaaaaaaa( - ("...", "."), "..", "..............................................") - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testBlankLinesBeforeFunctionsNotInColumnZero(self): - unformatted_code = textwrap.dedent("""\ - import signal - - - try: - signal.SIGALRM - # .................................................................. - # ............................................................... - - - def timeout(seconds=1): - pass - except: - pass - """) - expected_formatted_code = textwrap.dedent("""\ - import signal - - try: - signal.SIGALRM - - # .................................................................. - # ............................................................... - - - def timeout(seconds=1): - pass - except: - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testNoKeywordArgumentBreakage(self): - code = textwrap.dedent("""\ - class A(object): - - def b(self): - if self.aaaaaaaaaaaaaaaaaaaa not in self.bbbbbbbbbb( - cccccccccccccccccccc=True): - pass - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testTrailerOnSingleLine(self): - code = textwrap.dedent("""\ - urlpatterns = patterns('', - url(r'^$', 'homepage_view'), - url(r'^/login/$', 'login_view'), - url(r'^/login/$', 'logout_view'), - url(r'^/user/(?P\\w+)/$', 'profile_view')) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testIfConditionalParens(self): - code = textwrap.dedent("""\ - class Foo: - - def bar(): - if True: - if (child.type == grammar_token.NAME and - child.value in substatement_names): - pass - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testContinuationMarkers(self): - code = textwrap.dedent("""\ - text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. "\\ - "Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur "\\ - "ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis "\\ - "sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. "\\ - "Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet" - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - code = textwrap.dedent("""\ - from __future__ import nested_scopes, generators, division, absolute_import, with_statement, \\ - print_function, unicode_literals - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - code = textwrap.dedent("""\ - if aaaaaaaaa == 42 and bbbbbbbbbbbbbb == 42 and \\ - cccccccc == 42: - pass - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testCommentsWithContinuationMarkers(self): - code = textwrap.dedent("""\ - def fn(arg): - v = fn2(key1=True, - #c1 - key2=arg)\\ - .fn3() - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testEmptyContainers(self): - code = textwrap.dedent("""\ - flags.DEFINE_list( - 'output_dirs', [], - 'Lorem ipsum dolor sit amet, consetetur adipiscing elit. Donec a diam lectus. ' - 'Sed sit amet ipsum mauris. Maecenas congue.') - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testSplitStringsIfSurroundedByParens(self): - unformatted_code = textwrap.dedent("""\ - a = foo.bar({'xxxxxxxxxxxxxxxxxxxxxxx' 'yyyyyyyyyyyyyyyyyyyyyyyyyy': baz[42]} + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbb' 'cccccccccccccccccccccccccccccccc' 'ddddddddddddddddddddddddddddd') - """) - expected_formatted_code = textwrap.dedent("""\ - a = foo.bar({ - 'xxxxxxxxxxxxxxxxxxxxxxx' - 'yyyyyyyyyyyyyyyyyyyyyyyyyy': baz[42] - } + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' - 'bbbbbbbbbbbbbbbbbbbbbbbbbb' - 'cccccccccccccccccccccccccccccccc' - 'ddddddddddddddddddddddddddddd') - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - code = textwrap.dedent("""\ - a = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' \ -'bbbbbbbbbbbbbbbbbbbbbbbbbb' 'cccccccccccccccccccccccccccccccc' \ -'ddddddddddddddddddddddddddddd' - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testMultilineShebang(self): - code = textwrap.dedent("""\ - #!/bin/sh - if "true" : '''\' - then - - export FOO=123 - exec /usr/bin/env python "$0" "$@" - - exit 127 - fi - ''' - - import os - - assert os.environ['FOO'] == '123' - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testNoSplittingAroundTermOperators(self): - code = textwrap.dedent("""\ - a_very_long_function_call_yada_yada_etc_etc_etc(long_arg1, - long_arg2 / long_arg3) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testNoSplittingWithinSubscriptList(self): - code = textwrap.dedent("""\ - somequitelongvariablename.somemember[(a, b)] = { - 'somelongkey': 1, - 'someotherlongkey': 2 - } - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testExcessCharacters(self): - code = textwrap.dedent("""\ - class foo: - - def bar(self): - self.write(s=[ - '%s%s %s' % ('many of really', 'long strings', '+ just makes up 81') - ]) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testDictSetGenerator(self): - code = textwrap.dedent("""\ - foo = { - variable: 'hello world. How are you today?' - for variable in fnord if variable != 37 - } - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testUnaryOpInDictionaryValue(self): - code = textwrap.dedent("""\ - beta = "123" - - test = {'alpha': beta[-1]} - - print(beta[-1]) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testUnaryNotOperator(self): - code = textwrap.dedent("""\ - if True: - if True: - if True: - if True: - remote_checksum = self.get_checksum(conn, tmp, dest, inject, - not directory_prepended, source) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testRelaxArraySubscriptAffinity(self): - code = textwrap.dedent("""\ - class A(object): - - def f(self, aaaaaaaaa, bbbbbbbbbbbbb, row): - if True: - if True: - if True: - if True: - if row[4] is None or row[5] is None: - bbbbbbbbbbbbb['..............'] = row[5] if row[ - 5] is not None else 5 - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testFunctionCallInDict(self): - code = "a = {'a': b(c=d, **e)}\n" - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testFunctionCallInNestedDict(self): - code = "a = {'a': {'a': {'a': b(c=d, **e)}}}\n" - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testUnbreakableNot(self): - code = textwrap.dedent("""\ - def test(): - if not "Foooooooooooooooooooooooooooooo" or "Foooooooooooooooooooooooooooooo" == "Foooooooooooooooooooooooooooooo": - pass - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testSplitListWithComment(self): - code = textwrap.dedent("""\ - a = [ - 'a', - 'b', - 'c' # hello world - ] - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testOverColumnLimit(self): - unformatted_code = textwrap.dedent("""\ - class Test: - - def testSomething(self): - expected = { - ('aaaaaaaaaaaaa', 'bbbb'): 'ccccccccccccccccccccccccccccccccccccccccccc', - ('aaaaaaaaaaaaa', 'bbbb'): 'ccccccccccccccccccccccccccccccccccccccccccc', - ('aaaaaaaaaaaaa', 'bbbb'): 'ccccccccccccccccccccccccccccccccccccccccccc', - } - """) - expected_formatted_code = textwrap.dedent("""\ - class Test: - - def testSomething(self): - expected = { - ('aaaaaaaaaaaaa', 'bbbb'): - 'ccccccccccccccccccccccccccccccccccccccccccc', - ('aaaaaaaaaaaaa', 'bbbb'): - 'ccccccccccccccccccccccccccccccccccccccccccc', - ('aaaaaaaaaaaaa', 'bbbb'): - 'ccccccccccccccccccccccccccccccccccccccccccc', - } - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testEndingComment(self): - code = textwrap.dedent("""\ - a = f( - a="something", - b="something requiring comment which is quite long", # comment about b (pushes line over 79) - c="something else, about which comment doesn't make sense") - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testContinuationSpaceRetention(self): - code = textwrap.dedent("""\ - def fn(): - return module \\ - .method(Object(data, - fn2(arg) - )) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testIfExpressionWithFunctionCall(self): - code = textwrap.dedent("""\ - if x or z.y(a, - c, - aaaaaaaaaaaaaaaaaaaaa=aaaaaaaaaaaaaaaaaa, - bbbbbbbbbbbbbbbbbbbbb=bbbbbbbbbbbbbbbbbb): - pass - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testUnformattedAfterMultilineString(self): - code = textwrap.dedent("""\ - def foo(): - com_text = \\ - ''' - TEST - ''' % (input_fname, output_fname) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testNoSpacesAroundKeywordDefaultValues(self): - code = textwrap.dedent("""\ - sources = { - 'json': request.get_json(silent=True) or {}, - 'json2': request.get_json(silent=True), - } - json = request.get_json(silent=True) or {} - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testNoSplittingBeforeEndingSubscriptBracket(self): - unformatted_code = textwrap.dedent("""\ - if True: - if True: - status = cf.describe_stacks(StackName=stackname)[u'Stacks'][0][u'StackStatus'] - """) - expected_formatted_code = textwrap.dedent("""\ - if True: - if True: - status = cf.describe_stacks( - StackName=stackname)[u'Stacks'][0][u'StackStatus'] - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testNoSplittingOnSingleArgument(self): - unformatted_code = textwrap.dedent("""\ - xxxxxxxxxxxxxx = (re.search(r'(\\d+\\.\\d+\\.\\d+\\.)\\d+', - aaaaaaa.bbbbbbbbbbbb).group(1) + - re.search(r'\\d+\\.\\d+\\.\\d+\\.(\\d+)', - ccccccc).group(1)) - xxxxxxxxxxxxxx = (re.search(r'(\\d+\\.\\d+\\.\\d+\\.)\\d+', - aaaaaaa.bbbbbbbbbbbb).group(a.b) + - re.search(r'\\d+\\.\\d+\\.\\d+\\.(\\d+)', - ccccccc).group(c.d)) - """) - expected_formatted_code = textwrap.dedent("""\ - xxxxxxxxxxxxxx = ( - re.search(r'(\\d+\\.\\d+\\.\\d+\\.)\\d+', aaaaaaa.bbbbbbbbbbbb).group(1) + - re.search(r'\\d+\\.\\d+\\.\\d+\\.(\\d+)', ccccccc).group(1)) - xxxxxxxxxxxxxx = ( - re.search(r'(\\d+\\.\\d+\\.\\d+\\.)\\d+', aaaaaaa.bbbbbbbbbbbb).group(a.b) + - re.search(r'\\d+\\.\\d+\\.\\d+\\.(\\d+)', ccccccc).group(c.d)) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testSplittingArraysSensibly(self): - unformatted_code = textwrap.dedent("""\ - while True: - while True: - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list['bbbbbbbbbbbbbbbbbbbbbbbbb'].split(',') - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list('bbbbbbbbbbbbbbbbbbbbbbbbb').split(',') - """) - expected_formatted_code = textwrap.dedent("""\ - while True: - while True: - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list[ - 'bbbbbbbbbbbbbbbbbbbbbbbbb'].split(',') - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list( - 'bbbbbbbbbbbbbbbbbbbbbbbbb').split(',') - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testComprehensionForAndIf(self): - unformatted_code = textwrap.dedent("""\ - class f: - - def __repr__(self): - tokens_repr = ','.join(['{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens]) - """) - expected_formatted_code = textwrap.dedent("""\ - class f: - - def __repr__(self): - tokens_repr = ','.join( - ['{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens]) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testFunctionCallArguments(self): - unformatted_code = textwrap.dedent("""\ - def f(): - if True: - pytree_utils.InsertNodesBefore(_CreateCommentsFromPrefix( - comment_prefix, comment_lineno, comment_column, - standalone=True), ancestor_at_indent) - pytree_utils.InsertNodesBefore(_CreateCommentsFromPrefix( - comment_prefix, comment_lineno, comment_column, - standalone=True)) - """) - expected_formatted_code = textwrap.dedent("""\ - def f(): - if True: - pytree_utils.InsertNodesBefore( - _CreateCommentsFromPrefix( - comment_prefix, comment_lineno, comment_column, standalone=True), - ancestor_at_indent) - pytree_utils.InsertNodesBefore( - _CreateCommentsFromPrefix( - comment_prefix, comment_lineno, comment_column, standalone=True)) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testBinaryOperators(self): - unformatted_code = textwrap.dedent("""\ - a = b ** 37 - c = (20 ** -3) / (_GRID_ROWS ** (code_length - 10)) - """) - expected_formatted_code = textwrap.dedent("""\ - a = b**37 - c = (20**-3) / (_GRID_ROWS**(code_length - 10)) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - code = textwrap.dedent("""\ - def f(): - if True: - if (self.stack[-1].split_before_closing_bracket and - # FIXME(morbo): Use the 'matching_bracket' instead of this. - # FIXME(morbo): Don't forget about tuples! - current.value in ']}'): - pass - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testContiguousList(self): - code = textwrap.dedent("""\ - [retval1, retval2] = a_very_long_function(argument_1, argument2, argument_3, - argument_4) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testArgsAndKwargsFormatting(self): - code = textwrap.dedent("""\ - a(a=aaaaaaaaaaaaaaaaaaaaa, - b=aaaaaaaaaaaaaaaaaaaaaaaa, - c=aaaaaaaaaaaaaaaaaa, - *d, - **e) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testCommentColumnLimitOverflow(self): - code = textwrap.dedent("""\ - def f(): - if True: - TaskManager.get_tags = MagicMock( - name='get_tags_mock', - return_value=[157031694470475], - # side_effect=[(157031694470475), (157031694470475),], - ) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testMultilineLambdas(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: chromium, allow_multiline_lambdas: true}')) - unformatted_code = textwrap.dedent("""\ - class SomeClass(object): - do_something = True - - def succeeded(self, dddddddddddddd): - d = defer.succeed(None) - - if self.do_something: - d.addCallback(lambda _: self.aaaaaa.bbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccccccc(dddddddddddddd)) - return d - """) - expected_formatted_code = textwrap.dedent("""\ - class SomeClass(object): - do_something = True - - def succeeded(self, dddddddddddddd): - d = defer.succeed(None) - - if self.do_something: - d.addCallback(lambda _: self.aaaaaa.bbbbbbbbbbbbbbbb. - cccccccccccccccccccccccccccccccc(dddddddddddddd)) - return d - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) - finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) - - def testStableDictionaryFormatting(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: pep8, indent_width: 2, ' - 'continuation_indent_width: 4, indent_dictionary_value: True}')) - code = textwrap.dedent("""\ - class A(object): - def method(self): - filters = { - 'expressions': [{ - 'field': { - 'search_field': { - 'user_field': 'latest_party__number_of_guests' - }, - } - }] - } - """) - uwlines = _ParseAndUnwrap(code) - reformatted_code = reformatter.Reformat(uwlines) - self.assertCodeEqual(code, reformatted_code) - - uwlines = _ParseAndUnwrap(reformatted_code) - reformatted_code = reformatter.Reformat(uwlines) - self.assertCodeEqual(code, reformatted_code) - finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) - - def testDontSplitKeywordValueArguments(self): - code = textwrap.dedent("""\ - def mark_game_scored(gid): - _connect.execute(_games.update().where(_games.c.gid == gid).values( - scored=True)) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testDontAddBlankLineAfterMultilineString(self): - code = textwrap.dedent("""\ - query = '''SELECT id - FROM table - WHERE day in {}''' - days = ",".join(days) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testFormattingListComprehensions(self): - code = textwrap.dedent("""\ - def a(): - if True: - if True: - if True: - columns = [ - x for x, y in self._heap_this_is_very_long if x.route[0] == choice - ] - self._heap = [x for x in self._heap if x.route and x.route[0] == choice] - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testNoSplittingWhenBinPacking(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: pep8, indent_width: 2, ' - 'continuation_indent_width: 4, indent_dictionary_value: True, ' - 'dedent_closing_brackets: True, ' - 'split_before_named_assigns: False}')) - code = textwrap.dedent("""\ - a_very_long_function_name( - long_argument_name_1=1, - long_argument_name_2=2, - long_argument_name_3=3, - long_argument_name_4=4, - ) - - a_very_long_function_name( - long_argument_name_1=1, long_argument_name_2=2, long_argument_name_3=3, - long_argument_name_4=4 - ) - """) - uwlines = _ParseAndUnwrap(code) - reformatted_code = reformatter.Reformat(uwlines) - self.assertCodeEqual(code, reformatted_code) - - uwlines = _ParseAndUnwrap(reformatted_code) - reformatted_code = reformatter.Reformat(uwlines) - self.assertCodeEqual(code, reformatted_code) - finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) - - def testNotSplittingAfterSubscript(self): - unformatted_code = textwrap.dedent("""\ - if not aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.b(c == d[ - 'eeeeee']).ffffff(): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - if not aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.b( - c == d['eeeeee']).ffffff(): - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testSplittingOneArgumentList(self): - unformatted_code = textwrap.dedent("""\ - def _(): - if True: - if True: - if True: - if True: - if True: - boxes[id_] = np.concatenate((points.min(axis=0), qoints.max(axis=0))) - """) - expected_formatted_code = textwrap.dedent("""\ - def _(): - if True: - if True: - if True: - if True: - if True: - boxes[id_] = np.concatenate( - (points.min(axis=0), qoints.max(axis=0))) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testSplittingBeforeFirstElementListArgument(self): - unformatted_code = textwrap.dedent("""\ - class _(): - @classmethod - def _pack_results_for_constraint_or(cls, combination, constraints): - if True: - if True: - if True: - return cls._create_investigation_result( - ( - clue for clue in combination if not clue == Verifier.UNMATCHED - ), constraints, InvestigationResult.OR - ) - """) - expected_formatted_code = textwrap.dedent("""\ - class _(): - - @classmethod - def _pack_results_for_constraint_or(cls, combination, constraints): - if True: - if True: - if True: - return cls._create_investigation_result( - (clue for clue in combination if not clue == Verifier.UNMATCHED), - constraints, InvestigationResult.OR) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testSplittingArgumentsTerminatedByComma(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: chromium, ' - 'split_arguments_when_comma_terminated: True}')) - unformatted_code = textwrap.dedent("""\ - function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3) - - function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3,) - - a_very_long_function_name(long_argument_name_1=1, long_argument_name_2=2, long_argument_name_3=3, long_argument_name_4=4) - - a_very_long_function_name(long_argument_name_1, long_argument_name_2, long_argument_name_3, long_argument_name_4,) - - r =f0 (1, 2,3,) - """) - expected_formatted_code = textwrap.dedent("""\ - function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3) - - function_name( - argument_name_1=1, - argument_name_2=2, - argument_name_3=3, - ) - - a_very_long_function_name( - long_argument_name_1=1, - long_argument_name_2=2, - long_argument_name_3=3, - long_argument_name_4=4) - - a_very_long_function_name( - long_argument_name_1, - long_argument_name_2, - long_argument_name_3, - long_argument_name_4, - ) - - r = f0( - 1, - 2, - 3, - ) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - reformatted_code = reformatter.Reformat(uwlines) - self.assertCodeEqual(expected_formatted_code, reformatted_code) - - uwlines = _ParseAndUnwrap(reformatted_code) - reformatted_code = reformatter.Reformat(uwlines) - self.assertCodeEqual(expected_formatted_code, reformatted_code) - finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) - - def testImportAsList(self): - code = textwrap.dedent("""\ - from toto import titi, tata, tutu # noqa - from toto import titi, tata, tutu - from toto import (titi, tata, tutu) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testDictionaryValuesOnOwnLines(self): - unformatted_code = textwrap.dedent("""\ - a = { - 'aaaaaaaaaaaaaaaaaaaaaaaa': - Check('ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ', '=', True), - 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb': - Check('YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY', '=', True), - 'ccccccccccccccc': - Check('XXXXXXXXXXXXXXXXXXX', '!=', 'SUSPENDED'), - 'dddddddddddddddddddddddddddddd': - Check('WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW', '=', False), - 'eeeeeeeeeeeeeeeeeeeeeeeeeeeee': - Check('VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV', '=', False), - 'ffffffffffffffffffffffffff': - Check('UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU', '=', True), - 'ggggggggggggggggg': - Check('TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT', '=', True), - 'hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh': - Check('SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS', '=', True), - 'iiiiiiiiiiiiiiiiiiiiiiii': - Check('RRRRRRRRRRRRRRRRRRRRRRRRRRR', '=', True), - 'jjjjjjjjjjjjjjjjjjjjjjjjjj': - Check('QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ', '=', False), - } - """) - expected_formatted_code = textwrap.dedent("""\ - a = { - 'aaaaaaaaaaaaaaaaaaaaaaaa': - Check('ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ', '=', True), - 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb': - Check('YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY', '=', True), - 'ccccccccccccccc': - Check('XXXXXXXXXXXXXXXXXXX', '!=', 'SUSPENDED'), - 'dddddddddddddddddddddddddddddd': - Check('WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW', '=', False), - 'eeeeeeeeeeeeeeeeeeeeeeeeeeeee': - Check('VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV', '=', False), - 'ffffffffffffffffffffffffff': - Check('UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU', '=', True), - 'ggggggggggggggggg': - Check('TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT', '=', True), - 'hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh': - Check('SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS', '=', True), - 'iiiiiiiiiiiiiiiiiiiiiiii': - Check('RRRRRRRRRRRRRRRRRRRRRRRRRRR', '=', True), - 'jjjjjjjjjjjjjjjjjjjjjjjjjj': - Check('QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ', '=', False), - } - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testDictionaryOnOwnLine(self): - unformatted_code = textwrap.dedent("""\ - doc = test_utils.CreateTestDocumentViaController( - content={ 'a': 'b' }, - branch_key=branch.key, - collection_key=collection.key) - """) - expected_formatted_code = textwrap.dedent("""\ - doc = test_utils.CreateTestDocumentViaController( - content={'a': 'b'}, branch_key=branch.key, collection_key=collection.key) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - unformatted_code = textwrap.dedent("""\ - doc = test_utils.CreateTestDocumentViaController( - content={ 'a': 'b' }, - branch_key=branch.key, - collection_key=collection.key, - collection_key2=collection.key2) - """) - expected_formatted_code = textwrap.dedent("""\ - doc = test_utils.CreateTestDocumentViaController( - content={'a': 'b'}, - branch_key=branch.key, - collection_key=collection.key, - collection_key2=collection.key2) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testNestedListsInDictionary(self): - unformatted_code = textwrap.dedent("""\ - _A = { - 'cccccccccc': ('^^1',), - 'rrrrrrrrrrrrrrrrrrrrrrrrr': ('^7913', # AAAAAAAAAAAAAA. - ), - 'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee': ('^6242', # BBBBBBBBBBBBBBB. - ), - 'vvvvvvvvvvvvvvvvvvv': ('^27959', # CCCCCCCCCCCCCCCCCC. - '^19746', # DDDDDDDDDDDDDDDDDDDDDDD. - '^22907', # EEEEEEEEEEEEEEEEEEEEEEEE. - '^21098', # FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF. - '^22826', # GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG. - '^22769', # HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH. - '^22935', # IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII. - '^3982', # JJJJJJJJJJJJJ. - ), - 'uuuuuuuuuuuu': ('^19745', # LLLLLLLLLLLLLLLLLLLLLLLLLL. - '^21324', # MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM. - '^22831', # NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN. - '^17081', # OOOOOOOOOOOOOOOOOOOOO. - ), - 'eeeeeeeeeeeeee': ( - '^9416', # Reporter email. Not necessarily the reporter. - '^^3', # This appears to be the raw email field. - ), - 'cccccccccc': ('^21109', # PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP. - ), - } - """) - expected_formatted_code = textwrap.dedent("""\ - _A = { - 'cccccccccc': ('^^1',), - 'rrrrrrrrrrrrrrrrrrrrrrrrr': ( - '^7913', # AAAAAAAAAAAAAA. - ), - 'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee': ( - '^6242', # BBBBBBBBBBBBBBB. - ), - 'vvvvvvvvvvvvvvvvvvv': ( - '^27959', # CCCCCCCCCCCCCCCCCC. - '^19746', # DDDDDDDDDDDDDDDDDDDDDDD. - '^22907', # EEEEEEEEEEEEEEEEEEEEEEEE. - '^21098', # FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF. - '^22826', # GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG. - '^22769', # HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH. - '^22935', # IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII. - '^3982', # JJJJJJJJJJJJJ. - ), - 'uuuuuuuuuuuu': ( - '^19745', # LLLLLLLLLLLLLLLLLLLLLLLLLL. - '^21324', # MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM. - '^22831', # NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN. - '^17081', # OOOOOOOOOOOOOOOOOOOOO. - ), - 'eeeeeeeeeeeeee': ( - '^9416', # Reporter email. Not necessarily the reporter. - '^^3', # This appears to be the raw email field. - ), - 'cccccccccc': ( - '^21109', # PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP. - ), - } - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testNestedDictionary(self): - unformatted_code = textwrap.dedent("""\ - class _(): - def _(): - breadcrumbs = [{'name': 'Admin', - 'url': url_for(".home")}, - {'title': title},] - breadcrumbs = [{'name': 'Admin', - 'url': url_for(".home")}, - {'title': title}] - """) - expected_formatted_code = textwrap.dedent("""\ - class _(): - def _(): - breadcrumbs = [ - { - 'name': 'Admin', - 'url': url_for(".home") - }, - { - 'title': title - }, - ] - breadcrumbs = [{ - 'name': 'Admin', - 'url': url_for(".home") - }, { - 'title': title - }] - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testDictionaryElementsOnOneLine(self): - code = textwrap.dedent("""\ - class _(): - - @mock.patch.dict( - os.environ, - {'HTTP_' + xsrf._XSRF_TOKEN_HEADER.replace('-', '_'): 'atoken'}) - def _(): - pass - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - -class BuganizerFixes(ReformatterTest): - - @classmethod - def setUpClass(cls): - style.SetGlobalStyle(style.CreateChromiumStyle()) - - def testB31937033(self): - code = textwrap.dedent("""\ - class _(): - - def __init__(self, metric, fields_cb=None): - self._fields_cb = fields_cb or (lambda *unused_args, **unused_kwargs: {}) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB31911533(self): - code = textwrap.dedent("""\ - class _(): - - @parameterized.NamedParameters( - ('IncludingModInfoWithHeaderList', AAAA, aaaa), - ('IncludingModInfoWithoutHeaderList', BBBB, bbbbb), - ('ExcludingModInfoWithHeaderList', CCCCC, cccc), - ('ExcludingModInfoWithoutHeaderList', DDDDD, ddddd),) - def _(): - pass - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB31847238(self): - unformatted_code = textwrap.dedent("""\ - class _(): - - def aaaaa(self, bbbbb, cccccccccccccc=None): # pylint: disable=unused-argument - return 1 - - def xxxxx(self, yyyyy, zzzzzzzzzzzzzz=None): # A normal comment that runs over the column limit. - return 1 - """) - expected_formatted_code = textwrap.dedent("""\ - class _(): - - def aaaaa(self, bbbbb, cccccccccccccc=None): # pylint: disable=unused-argument - return 1 - - def xxxxx( - self, yyyyy, - zzzzzzzzzzzzzz=None): # A normal comment that runs over the column limit. - return 1 - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB30760569(self): - unformatted_code = textwrap.dedent("""\ - {'1234567890123456789012345678901234567890123456789012345678901234567890': - '1234567890123456789012345678901234567890'} - """) - expected_formatted_code = textwrap.dedent("""\ - { - '1234567890123456789012345678901234567890123456789012345678901234567890': - '1234567890123456789012345678901234567890' - } - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB26034238(self): - unformatted_code = textwrap.dedent("""\ - class Thing: - - def Function(self): - thing.Scrape('/aaaaaaaaa/bbbbbbbbbb/ccccc/dddd/eeeeeeeeeeeeee/ffffffffffffff').AndReturn(42) - """) - expected_formatted_code = textwrap.dedent("""\ - class Thing: - - def Function(self): - thing.Scrape( - '/aaaaaaaaa/bbbbbbbbbb/ccccc/dddd/eeeeeeeeeeeeee/ffffffffffffff' - ).AndReturn(42) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB30536435(self): - unformatted_code = textwrap.dedent("""\ - def main(unused_argv): - if True: - if True: - aaaaaaaaaaa.comment('import-from[{}] {} {}'.format( - bbbbbbbbb.usage, - ccccccccc.within, - imports.ddddddddddddddddddd(name_item.ffffffffffffffff))) - """) - expected_formatted_code = textwrap.dedent("""\ - def main(unused_argv): - if True: - if True: - aaaaaaaaaaa.comment('import-from[{}] {} {}'.format( - bbbbbbbbb.usage, ccccccccc.within, - imports.ddddddddddddddddddd(name_item.ffffffffffffffff))) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB30442148(self): - unformatted_code = textwrap.dedent("""\ - def lulz(): - return (some_long_module_name.SomeLongClassName. - some_long_attribute_name.some_long_method_name()) - """) - expected_formatted_code = textwrap.dedent("""\ - def lulz(): - return (some_long_module_name.SomeLongClassName.some_long_attribute_name. - some_long_method_name()) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB26868213(self): - unformatted_code = textwrap.dedent("""\ - def _(): - xxxxxxxxxxxxxxxxxxx = { - 'ssssss': {'ddddd': 'qqqqq', - 'p90': aaaaaaaaaaaaaaaaa, - 'p99': bbbbbbbbbbbbbbbbb, - 'lllllllllllll': yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy(),}, - 'bbbbbbbbbbbbbbbbbbbbbbbbbbbb': { - 'ddddd': 'bork bork bork bo', - 'p90': wwwwwwwwwwwwwwwww, - 'p99': wwwwwwwwwwwwwwwww, - 'lllllllllllll': None, # use the default - } - } - """) - expected_formatted_code = textwrap.dedent("""\ - def _(): - xxxxxxxxxxxxxxxxxxx = { - 'ssssss': { - 'ddddd': 'qqqqq', - 'p90': aaaaaaaaaaaaaaaaa, - 'p99': bbbbbbbbbbbbbbbbb, - 'lllllllllllll': yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy(), - }, - 'bbbbbbbbbbbbbbbbbbbbbbbbbbbb': { - 'ddddd': 'bork bork bork bo', - 'p90': wwwwwwwwwwwwwwwww, - 'p99': wwwwwwwwwwwwwwwww, - 'lllllllllllll': None, # use the default - } - } - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB30173198(self): - code = textwrap.dedent("""\ - class _(): - - def _(): - self.assertFalse( - evaluation_runner.get_larps_in_eval_set('these_arent_the_larps')) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB29908765(self): - code = textwrap.dedent("""\ - class _(): - - def __repr__(self): - return '' % (self._id, - self._stub._stub.rpc_channel().target()) # pylint:disable=protected-access - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB30087362(self): - code = textwrap.dedent("""\ - def _(): - for s in sorted(env['foo']): - bar() - # This is a comment - - # This is another comment - foo() - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB29093579(self): - unformatted_code = textwrap.dedent("""\ - def _(): - _xxxxxxxxxxxxxxx(aaaaaaaa, bbbbbbbbbbbbbb.cccccccccc[ - dddddddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffff]) - """) - expected_formatted_code = textwrap.dedent("""\ - def _(): - _xxxxxxxxxxxxxxx( - aaaaaaaa, - bbbbbbbbbbbbbb.cccccccccc[dddddddddddddddddddddddddddd. - eeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffff]) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB26382315(self): - code = textwrap.dedent("""\ - @hello_world - # This is a first comment - - # Comment - def foo(): - pass - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB27616132(self): - unformatted_code = textwrap.dedent("""\ - if True: - query.fetch_page.assert_has_calls([ - mock.call(100, - start_cursor=None), - mock.call(100, - start_cursor=cursor_1), - mock.call(100, - start_cursor=cursor_2), - ]) - """) - expected_formatted_code = textwrap.dedent("""\ - if True: - query.fetch_page.assert_has_calls([ - mock.call( - 100, start_cursor=None), - mock.call( - 100, start_cursor=cursor_1), - mock.call( - 100, start_cursor=cursor_2), - ]) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB27590179(self): - unformatted_code = textwrap.dedent("""\ - if True: - if True: - self.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = ( - { True: - self.bbb.cccccccccc(ddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee), - False: - self.bbb.cccccccccc(ddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee) - }) - """) - expected_formatted_code = textwrap.dedent("""\ - if True: - if True: - self.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = ({ - True: - self.bbb.cccccccccc(ddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee), - False: - self.bbb.cccccccccc(ddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee) - }) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB27266946(self): - unformatted_code = textwrap.dedent("""\ - def _(): - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = (self.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccccccccccc) - """) - expected_formatted_code = textwrap.dedent("""\ - def _(): - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = ( - self.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb. - cccccccccccccccccccccccccccccccccccc) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB25505359(self): - code = textwrap.dedent("""\ - _EXAMPLE = { - 'aaaaaaaaaaaaaa': [{ - 'bbbb': 'cccccccccccccccccccccc', - 'dddddddddddd': [] - }, { - 'bbbb': 'ccccccccccccccccccc', - 'dddddddddddd': [] - }] - } - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB25324261(self): - code = textwrap.dedent("""\ - aaaaaaaaa = set(bbbb.cccc - for ddd in eeeeee.fffffffffff.gggggggggggggggg - for cccc in ddd.specification) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB25136704(self): - code = textwrap.dedent("""\ - class f: - - def test(self): - self.bbbbbbb[0]['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', { - 'xxxxxx': 'yyyyyy' - }] = cccccc.ddd('1m', '10x1+1') - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB25165602(self): - code = textwrap.dedent("""\ - def f(): - ids = {u: i for u, i in zip(self.aaaaa, xrange(42, 42 + len(self.aaaaaa)))} - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB25157123(self): - code = textwrap.dedent("""\ - def ListArgs(): - FairlyLongMethodName([relatively_long_identifier_for_a_list], - another_argument_with_a_long_identifier) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB25136820(self): - unformatted_code = textwrap.dedent("""\ - def foo(): - return collections.OrderedDict({ - # Preceding comment. - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa': - '$bbbbbbbbbbbbbbbbbbbbbbbb', - }) - """) - expected_formatted_code = textwrap.dedent("""\ - def foo(): - return collections.OrderedDict({ - # Preceding comment. - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa': - '$bbbbbbbbbbbbbbbbbbbbbbbb', - }) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB25131481(self): - unformatted_code = textwrap.dedent("""\ - APPARENT_ACTIONS = ('command_type', { - 'materialize': lambda x: some_type_of_function('materialize ' + x.command_def), - '#': lambda x: x # do nothing - }) - """) - expected_formatted_code = textwrap.dedent("""\ - APPARENT_ACTIONS = ( - 'command_type', - { - 'materialize': - lambda x: some_type_of_function('materialize ' + x.command_def), - '#': - lambda x: x # do nothing - }) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB23445244(self): - unformatted_code = textwrap.dedent("""\ - def foo(): - if True: - return xxxxxxxxxxxxxxxx( - command, - extra_env={ - "OOOOOOOOOOOOOOOOOOOOO": FLAGS.zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, - "PPPPPPPPPPPPPPPPPPPPP": - FLAGS.aaaaaaaaaaaaaa + FLAGS.bbbbbbbbbbbbbbbbbbb, - }) - """) - expected_formatted_code = textwrap.dedent("""\ - def foo(): - if True: - return xxxxxxxxxxxxxxxx( - command, - extra_env={ - "OOOOOOOOOOOOOOOOOOOOO": - FLAGS.zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, - "PPPPPPPPPPPPPPPPPPPPP": - FLAGS.aaaaaaaaaaaaaa + FLAGS.bbbbbbbbbbbbbbbbbbb, - }) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB20559654(self): - unformatted_code = textwrap.dedent("""\ - class A(object): - - def foo(self): - unused_error, result = server.Query( - ['AA BBBB CCC DDD EEEEEEEE X YY ZZZZ FFF EEE AAAAAAAA'], - aaaaaaaaaaa=True, bbbbbbbb=None) - """) - expected_formatted_code = textwrap.dedent("""\ - class A(object): - - def foo(self): - unused_error, result = server.Query( - ['AA BBBB CCC DDD EEEEEEEE X YY ZZZZ FFF EEE AAAAAAAA'], - aaaaaaaaaaa=True, - bbbbbbbb=None) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB23943842(self): - unformatted_code = textwrap.dedent("""\ - class F(): - def f(): - self.assertDictEqual( - accounts, { - 'foo': - {'account': 'foo', - 'lines': 'l1\\nl2\\nl3\\n1 line(s) were elided.'}, - 'bar': {'account': 'bar', - 'lines': 'l5\\nl6\\nl7'}, - 'wiz': {'account': 'wiz', - 'lines': 'l8'} - }) - """) - expected_formatted_code = textwrap.dedent("""\ - class F(): - - def f(): - self.assertDictEqual(accounts, { - 'foo': { - 'account': 'foo', - 'lines': 'l1\\nl2\\nl3\\n1 line(s) were elided.' - }, - 'bar': { - 'account': 'bar', - 'lines': 'l5\\nl6\\nl7' - }, - 'wiz': { - 'account': 'wiz', - 'lines': 'l8' - } - }) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB20551180(self): - unformatted_code = textwrap.dedent("""\ - def foo(): - if True: - return (struct.pack('aaaa', bbbbbbbbbb, ccccccccccccccc, dddddddd) + eeeeeee) - """) - expected_formatted_code = textwrap.dedent("""\ - def foo(): - if True: - return ( - struct.pack('aaaa', bbbbbbbbbb, ccccccccccccccc, dddddddd) + eeeeeee) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB23944849(self): - unformatted_code = textwrap.dedent("""\ - class A(object): - def xxxxxxxxx(self, aaaaaaa, bbbbbbb=ccccccccccc, dddddd=300, eeeeeeeeeeeeee=None, fffffffffffffff=0): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - class A(object): - - def xxxxxxxxx(self, - aaaaaaa, - bbbbbbb=ccccccccccc, - dddddd=300, - eeeeeeeeeeeeee=None, - fffffffffffffff=0): - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB23935890(self): - unformatted_code = textwrap.dedent("""\ - class F(): - def functioni(self, aaaaaaa, bbbbbbb, cccccc, dddddddddddddd, eeeeeeeeeeeeeee): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - class F(): - - def functioni(self, aaaaaaa, bbbbbbb, cccccc, dddddddddddddd, - eeeeeeeeeeeeeee): - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB28414371(self): - code = textwrap.dedent("""\ - def _(): - return ( - (m.fffff( - m.rrr('mmmmmmmmmmmmmmmm', 'ssssssssssssssssssssssssss'), - ffffffffffffffff) - | m.wwwwww(m.ddddd('1h')) - | m.ggggggg(bbbbbbbbbbbbbbb) - | m.ppppp( - (1 - m.ffffffffffffffff(llllllllllllllllllllll * 1000000, m.vvv)) * - m.ddddddddddddddddd(m.vvv)), m.fffff( - m.rrr('mmmmmmmmmmmmmmmm', 'sssssssssssssssssssssss'), - dict( - ffffffffffffffff, - **{ - 'mmmmmm:ssssss': - m.rrrrrrrrrrr( - '|'.join(iiiiiiiiiiiiii), iiiiii=True) - })) - | m.wwwwww(m.rrrr('1h')) - | m.ggggggg(bbbbbbbbbbbbbbb)) - | m.jjjj() - | m.ppppp(m.vvv[0] + m.vvv[1])) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB20127686(self): - code = textwrap.dedent("""\ - def f(): - if True: - return ((m.fffff( - m.rrr('xxxxxxxxxxxxxxxx', - 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'), - mmmmmmmm) - | m.wwwwww(m.rrrr(self.tttttttttt, self.mmmmmmmmmmmmmmmmmmmmm)) - | m.ggggggg(self.gggggggg, m.sss()), m.fffff('aaaaaaaaaaaaaaaa') - | m.wwwwww(m.ddddd(self.tttttttttt, self.mmmmmmmmmmmmmmmmmmmmm)) - | m.ggggggg(self.gggggggg)) - | m.jjjj() - | m.ppppp(m.VAL[0] / m.VAL[1])) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB20016122(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: chromium, ' - 'SPLIT_BEFORE_LOGICAL_OPERATOR: True}')) - code = textwrap.dedent("""\ - class foo(): - - def __eq__(self, other): - return (isinstance(other, type(self)) - and self.xxxxxxxxxxx == other.xxxxxxxxxxx - and self.xxxxxxxx == other.xxxxxxxx - and self.aaaaaaaaaaaa == other.aaaaaaaaaaaa - and self.bbbbbbbbbbb == other.bbbbbbbbbbb - and self.ccccccccccccccccc == other.ccccccccccccccccc - and self.ddddddddddddddddddddddd == other.ddddddddddddddddddddddd - and self.eeeeeeeeeeee == other.eeeeeeeeeeee - and self.ffffffffffffff == other.time_completed - and self.gggggg == other.gggggg and self.hhh == other.hhh - and len(self.iiiiiiii) == len(other.iiiiiiii) - and all(jjjjjjj in other.iiiiiiii for jjjjjjj in self.iiiiiiii)) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) - - def testB22527411(self): - unformatted_code = textwrap.dedent("""\ - def f(): - if True: - aaaaaa.bbbbbbbbbbbbbbbbbbbb[-1].cccccccccccccc.ddd().eeeeeeee(ffffffffffffff) - """) - expected_formatted_code = textwrap.dedent("""\ - def f(): - if True: - aaaaaa.bbbbbbbbbbbbbbbbbbbb[-1].cccccccccccccc.ddd().eeeeeeee( - ffffffffffffff) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB20849933(self): - code = textwrap.dedent("""\ - def main(unused_argv): - if True: - aaaaaaaa = { - 'xxx': - '%s/cccccc/ddddddddddddddddddd.jar' % (eeeeee.FFFFFFFFFFFFFFFFFF), - } - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB20813997(self): - code = textwrap.dedent("""\ - def myfunc_1(): - myarray = numpy.zeros((2, 2, 2)) - print(myarray[:, 1, :]) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB20605036(self): - code = textwrap.dedent("""\ - foo = { - 'aaaa': { - # A comment for no particular reason. - 'xxxxxxxx': - 'bbbbbbbbb', - 'yyyyyyyyyyyyyyyyyy': - 'cccccccccccccccccccccccccccccc' - 'dddddddddddddddddddddddddddddddddddddddddd', - } - } - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB20562732(self): - code = textwrap.dedent("""\ - foo = [ - # Comment about first list item - 'First item', - # Comment about second list item - 'Second item', - ] - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB20128830(self): - code = textwrap.dedent("""\ - a = { - 'xxxxxxxxxxxxxxxxxxxx': { - 'aaaa': - 'mmmmmmm', - 'bbbbb': - 'mmmmmmmmmmmmmmmmmmmmm', - 'cccccccccc': [ - 'nnnnnnnnnnn', - 'ooooooooooo', - 'ppppppppppp', - 'qqqqqqqqqqq', - ], - }, - } - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB20073838(self): - code = textwrap.dedent("""\ - class DummyModel(object): - - def do_nothing(self, class_1_count): - if True: - class_0_count = num_votes - class_1_count - return ('{class_0_name}={class_0_count}, {class_1_name}={class_1_count}' - .format( - class_0_name=self.class_0_name, - class_0_count=class_0_count, - class_1_name=self.class_1_name, - class_1_count=class_1_count)) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB19626808(self): - code = textwrap.dedent("""\ - if True: - aaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbb( - 'ccccccccccc', ddddddddd='eeeee').fffffffff([ggggggggggggggggggggg]) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB19547210(self): - code = textwrap.dedent("""\ - while True: - if True: - if True: - if True: - if xxxxxxxxxxxx.yyyyyyy(aa).zzzzzzz() not in ( - xxxxxxxxxxxx.yyyyyyyyyyyyyy.zzzzzzzz, - xxxxxxxxxxxx.yyyyyyyyyyyyyy.zzzzzzzz): - continue - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB19377034(self): - code = textwrap.dedent("""\ - def f(): - if (aaaaaaaaaaaaaaa.start >= aaaaaaaaaaaaaaa.end or - bbbbbbbbbbbbbbb.start >= bbbbbbbbbbbbbbb.end): - return False - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB19372573(self): - code = textwrap.dedent("""\ - def f(): - if a: return 42 - while True: - if b: continue - if c: break - return 0 - """) - uwlines = _ParseAndUnwrap(code) - try: - style.SetGlobalStyle(style.CreatePEP8Style()) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) - - def testB19353268(self): - code = textwrap.dedent("""\ - a = {1, 2, 3}[x] - b = {'foo': 42, 'bar': 37}['foo'] - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB19287512(self): - unformatted_code = textwrap.dedent("""\ - class Foo(object): - - def bar(self): - with xxxxxxxxxx.yyyyy( - 'aaaaaaa.bbbbbbbb.ccccccc.dddddddddddddddddddd.eeeeeeeeeee', - fffffffffff=(aaaaaaa.bbbbbbbb.ccccccc.dddddddddddddddddddd - .Mmmmmmmmmmmmmmmmmm(-1, 'permission error'))): - self.assertRaises(nnnnnnnnnnnnnnnn.ooooo, ppppp.qqqqqqqqqqqqqqqqq) - """) - expected_formatted_code = textwrap.dedent("""\ - class Foo(object): - - def bar(self): - with xxxxxxxxxx.yyyyy( - 'aaaaaaa.bbbbbbbb.ccccccc.dddddddddddddddddddd.eeeeeeeeeee', - fffffffffff=( - aaaaaaa.bbbbbbbb.ccccccc.dddddddddddddddddddd.Mmmmmmmmmmmmmmmmmm( - -1, 'permission error'))): - self.assertRaises(nnnnnnnnnnnnnnnn.ooooo, ppppp.qqqqqqqqqqqqqqqqq) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB19194420(self): - code = textwrap.dedent("""\ - method.Set('long argument goes here that causes the line to break', - lambda arg2=0.5: arg2) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB19073499(self): - code = textwrap.dedent("""\ - instance = ( - aaaaaaa.bbbbbbb().ccccccccccccccccc().ddddddddddd({ - 'aa': 'context!' - }).eeeeeeeeeeeeeeeeeee( - { # Inline comment about why fnord has the value 6. - 'fnord': 6 - })) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB18257115(self): - code = textwrap.dedent("""\ - if True: - if True: - self._Test(aaaa, bbbbbbb.cccccccccc, dddddddd, eeeeeeeeeee, - [ffff, ggggggggggg, hhhhhhhhhhhh, iiiiii, jjjj]) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB18256666(self): - code = textwrap.dedent("""\ - class Foo(object): - - def Bar(self): - aaaaa.bbbbbbb( - ccc='ddddddddddddddd', - eeee='ffffffffffffffffffffff-%s-%s' % (gggg, int(time.time())), - hhhhhh={ - 'iiiiiiiiiii': iiiiiiiiiii, - 'jjjj': jjjj.jjjjj(), - 'kkkkkkkkkkkk': kkkkkkkkkkkk, - }, - llllllllll=mmmmmm.nnnnnnnnnnnnnnnn) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB18256826(self): - code = textwrap.dedent("""\ - if True: - pass - # A multiline comment. - # Line two. - elif False: - pass - - if True: - pass - # A multiline comment. - # Line two. - elif False: - pass - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB18255697(self): - code = textwrap.dedent("""\ - AAAAAAAAAAAAAAA = { - 'XXXXXXXXXXXXXX': 4242, # Inline comment - # Next comment - 'YYYYYYYYYYYYYYYY': ['zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'], - } - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testB17534869(self): - unformatted_code = textwrap.dedent("""\ - if True: - self.assertLess(abs(time.time()-aaaa.bbbbbbbbbbb( - datetime.datetime.now())), 1) - """) - expected_formatted_code = textwrap.dedent("""\ - if True: - self.assertLess( - abs(time.time() - aaaa.bbbbbbbbbbb(datetime.datetime.now())), 1) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB17489866(self): - unformatted_code = textwrap.dedent("""\ - def f(): - if True: - if True: - return aaaa.bbbbbbbbb(ccccccc=dddddddddddddd({('eeee', \ -'ffffffff'): str(j)})) - """) - expected_formatted_code = textwrap.dedent("""\ - def f(): - if True: - if True: - return aaaa.bbbbbbbbb(ccccccc=dddddddddddddd({ - ('eeee', 'ffffffff'): str(j) - })) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB17133019(self): - unformatted_code = textwrap.dedent("""\ - class aaaaaaaaaaaaaa(object): - - def bbbbbbbbbb(self): - with io.open("/dev/null", "rb"): - with io.open(os.path.join(aaaaa.bbbbb.ccccccccccc, - DDDDDDDDDDDDDDD, - "eeeeeeeee ffffffffff" - ), "rb") as gggggggggggggggggggg: - print(gggggggggggggggggggg) - """) - expected_formatted_code = textwrap.dedent("""\ - class aaaaaaaaaaaaaa(object): - - def bbbbbbbbbb(self): - with io.open("/dev/null", "rb"): - with io.open( - os.path.join(aaaaa.bbbbb.ccccccccccc, DDDDDDDDDDDDDDD, - "eeeeeeeee ffffffffff"), "rb") as gggggggggggggggggggg: - print(gggggggggggggggggggg) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB17011869(self): - unformatted_code = textwrap.dedent("""\ - '''blah......''' - - class SomeClass(object): - '''blah.''' - - AAAAAAAAAAAA = { # Comment. - 'BBB': 1.0, - 'DDDDDDDD': 0.4811 - } - """) - expected_formatted_code = textwrap.dedent("""\ - '''blah......''' - - - class SomeClass(object): - '''blah.''' - - AAAAAAAAAAAA = { # Comment. - 'BBB': 1.0, - 'DDDDDDDD': 0.4811 - } - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB16783631(self): - unformatted_code = textwrap.dedent("""\ - if True: - with aaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccc(ddddddddddddd, - eeeeeeeee=self.fffffffffffff - )as gggg: - pass - """) - expected_formatted_code = textwrap.dedent("""\ - if True: - with aaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccc( - ddddddddddddd, eeeeeeeee=self.fffffffffffff) as gggg: - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB16572361(self): - unformatted_code = textwrap.dedent("""\ - def foo(self): - def bar(my_dict_name): - self.my_dict_name['foo-bar-baz-biz-boo-baa-baa'].IncrementBy.assert_called_once_with('foo_bar_baz_boo') - """) - expected_formatted_code = textwrap.dedent("""\ - def foo(self): - - def bar(my_dict_name): - self.my_dict_name[ - 'foo-bar-baz-biz-boo-baa-baa'].IncrementBy.assert_called_once_with( - 'foo_bar_baz_boo') - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB15884241(self): - unformatted_code = textwrap.dedent("""\ - if 1: - if 1: - for row in AAAA: - self.create(aaaaaaaa="/aaa/bbbb/cccc/dddddd/eeeeeeeeeeeeeeeeeeeeeeeeee/%s" % row [0].replace(".foo", ".bar"), aaaaa=bbb[1], ccccc=bbb[2], dddd=bbb[3], eeeeeeeeeee=[s.strip() for s in bbb[4].split(",")], ffffffff=[s.strip() for s in bbb[5].split(",")], gggggg=bbb[6]) - """) - expected_formatted_code = textwrap.dedent("""\ - if 1: - if 1: - for row in AAAA: - self.create( - aaaaaaaa="/aaa/bbbb/cccc/dddddd/eeeeeeeeeeeeeeeeeeeeeeeeee/%s" % - row[0].replace(".foo", ".bar"), - aaaaa=bbb[1], - ccccc=bbb[2], - dddd=bbb[3], - eeeeeeeeeee=[s.strip() for s in bbb[4].split(",")], - ffffffff=[s.strip() for s in bbb[5].split(",")], - gggggg=bbb[6]) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB15697268(self): - unformatted_code = textwrap.dedent("""\ - def main(unused_argv): - ARBITRARY_CONSTANT_A = 10 - an_array_with_an_exceedingly_long_name = range(ARBITRARY_CONSTANT_A + 1) - ok = an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A] - bad_slice = map(math.sqrt, an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A]) - a_long_name_slicing = an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A] - bad_slice = ("I am a crazy, no good, string whats too long, etc." + " no really ")[:ARBITRARY_CONSTANT_A] - """) - expected_formatted_code = textwrap.dedent("""\ - def main(unused_argv): - ARBITRARY_CONSTANT_A = 10 - an_array_with_an_exceedingly_long_name = range(ARBITRARY_CONSTANT_A + 1) - ok = an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A] - bad_slice = map(math.sqrt, - an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A]) - a_long_name_slicing = an_array_with_an_exceedingly_long_name[: - ARBITRARY_CONSTANT_A] - bad_slice = ("I am a crazy, no good, string whats too long, etc." + - " no really ")[:ARBITRARY_CONSTANT_A] - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB15597568(self): - unformatted_code = textwrap.dedent("""\ - if True: - if True: - if True: - print(("Return code was %d" + (", and the process timed out." if did_time_out else ".")) % errorcode) - """) - expected_formatted_code = textwrap.dedent("""\ - if True: - if True: - if True: - print(("Return code was %d" + (", and the process timed out." - if did_time_out else ".")) % errorcode) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB15542157(self): - unformatted_code = textwrap.dedent("""\ - aaaaaaaaaaaa = bbbb.ccccccccccccccc(dddddd.eeeeeeeeeeeeee, ffffffffffffffffff, gggggg.hhhhhhhhhhhhhhhhh) - """) - expected_formatted_code = textwrap.dedent("""\ - aaaaaaaaaaaa = bbbb.ccccccccccccccc(dddddd.eeeeeeeeeeeeee, ffffffffffffffffff, - gggggg.hhhhhhhhhhhhhhhhh) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB15438132(self): - unformatted_code = textwrap.dedent("""\ - if aaaaaaa.bbbbbbbbbb: - cccccc.dddddddddd(eeeeeeeeeee=fffffffffffff.gggggggggggggggggg) - if hhhhhh.iiiii.jjjjjjjjjjjjj: - # This is a comment in the middle of it all. - kkkkkkk.llllllllll.mmmmmmmmmmmmm = True - if (aaaaaa.bbbbb.ccccccccccccc != ddddddd.eeeeeeeeee.fffffffffffff or - eeeeee.fffff.ggggggggggggggggggggggggggg() != hhhhhhh.iiiiiiiiii.jjjjjjjjjjjj): - aaaaaaaa.bbbbbbbbbbbb( - aaaaaa.bbbbb.cc, - dddddddddddd=eeeeeeeeeeeeeeeeeee.fffffffffffffffff( - gggggg.hh, - iiiiiiiiiiiiiiiiiii.jjjjjjjjjj.kkkkkkk, - lllll.mm), - nnnnnnnnnn=ooooooo.pppppppppp) - """) - expected_formatted_code = textwrap.dedent("""\ - if aaaaaaa.bbbbbbbbbb: - cccccc.dddddddddd(eeeeeeeeeee=fffffffffffff.gggggggggggggggggg) - if hhhhhh.iiiii.jjjjjjjjjjjjj: - # This is a comment in the middle of it all. - kkkkkkk.llllllllll.mmmmmmmmmmmmm = True - if (aaaaaa.bbbbb.ccccccccccccc != ddddddd.eeeeeeeeee.fffffffffffff or - eeeeee.fffff.ggggggggggggggggggggggggggg() != - hhhhhhh.iiiiiiiiii.jjjjjjjjjjjj): - aaaaaaaa.bbbbbbbbbbbb( - aaaaaa.bbbbb.cc, - dddddddddddd=eeeeeeeeeeeeeeeeeee.fffffffffffffffff( - gggggg.hh, iiiiiiiiiiiiiiiiiii.jjjjjjjjjj.kkkkkkk, lllll.mm), - nnnnnnnnnn=ooooooo.pppppppppp) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB14468247(self): - unformatted_code = textwrap.dedent("""\ - call(a=1, - b=2, - ) - """) - expected_formatted_code = textwrap.dedent("""\ - call( - a=1, - b=2,) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB14406499(self): - unformatted_code = textwrap.dedent("""\ - def foo1(parameter_1, parameter_2, parameter_3, parameter_4, \ -parameter_5, parameter_6): pass - """) - expected_formatted_code = textwrap.dedent("""\ - def foo1(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, - parameter_6): - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB13900309(self): - unformatted_code = textwrap.dedent("""\ - self.aaaaaaaaaaa( # A comment in the middle of it all. - 948.0/3600, self.bbb.ccccccccccccccccccccc(dddddddddddddddd.eeee, True)) - """) - expected_formatted_code = textwrap.dedent("""\ - self.aaaaaaaaaaa( # A comment in the middle of it all. - 948.0 / 3600, self.bbb.ccccccccccccccccccccc(dddddddddddddddd.eeee, True)) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - code = textwrap.dedent("""\ - aaaaaaaaaa.bbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccccc( - DC_1, (CL - 50, CL), AAAAAAAA, BBBBBBBBBBBBBBBB, 98.0, - CCCCCCC).ddddddddd( # Look! A comment is here. - AAAAAAAA - (20 * 60 - 5)) - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - unformatted_code = textwrap.dedent("""\ - aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc().dddddddddddddddddddddddddd(1, 2, 3, 4) - """) - expected_formatted_code = textwrap.dedent("""\ - aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc( - ).dddddddddddddddddddddddddd(1, 2, 3, 4) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - unformatted_code = textwrap.dedent("""\ - aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc(x).dddddddddddddddddddddddddd(1, 2, 3, 4) - """) - expected_formatted_code = textwrap.dedent("""\ - aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc( - x).dddddddddddddddddddddddddd(1, 2, 3, 4) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - unformatted_code = textwrap.dedent("""\ - aaaaaaaaaaaaaaaaaaaaaaaa(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx).dddddddddddddddddddddddddd(1, 2, 3, 4) - """) - expected_formatted_code = textwrap.dedent("""\ - aaaaaaaaaaaaaaaaaaaaaaaa( - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx).dddddddddddddddddddddddddd(1, 2, 3, 4) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - unformatted_code = textwrap.dedent("""\ - aaaaaaaaaaaaaaaaaaaaaaaa().bbbbbbbbbbbbbbbbbbbbbbbb().ccccccccccccccccccc().\ -dddddddddddddddddd().eeeeeeeeeeeeeeeeeeeee().fffffffffffffffff().gggggggggggggggggg() - """) - expected_formatted_code = textwrap.dedent("""\ - aaaaaaaaaaaaaaaaaaaaaaaa().bbbbbbbbbbbbbbbbbbbbbbbb().ccccccccccccccccccc( - ).dddddddddddddddddd().eeeeeeeeeeeeeeeeeeeee().fffffffffffffffff( - ).gggggggggggggggggg() - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - -class TestsForStyleConfig(ReformatterTest): - - def setUp(self): - self.current_style = style.DEFAULT_STYLE - - def testSetGlobalStyle(self): - try: - style.SetGlobalStyle(style.CreateChromiumStyle()) - unformatted_code = textwrap.dedent(u"""\ - for i in range(5): - print('bar') - """) - expected_formatted_code = textwrap.dedent(u"""\ - for i in range(5): - print('bar') - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) - finally: - style.SetGlobalStyle(style.CreatePEP8Style()) - style.DEFAULT_STYLE = self.current_style - - unformatted_code = textwrap.dedent(u"""\ - for i in range(5): - print('bar') - """) - expected_formatted_code = textwrap.dedent(u"""\ - for i in range(5): - print('bar') - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - -class TestsForPEP8Style(ReformatterTest): - - @classmethod - def setUpClass(cls): - style.SetGlobalStyle(style.CreatePEP8Style()) - - def testIndent4(self): - unformatted_code = textwrap.dedent("""\ - if a+b: - pass - """) - expected_formatted_code = textwrap.dedent("""\ - if a + b: - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testSingleLineIfStatements(self): - code = textwrap.dedent("""\ - if True: a = 42 - elif False: b = 42 - else: c = 42 - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testNoBlankBetweenClassAndDef(self): - unformatted_code = textwrap.dedent("""\ - class Foo: - - def joe(): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - class Foo: - def joe(): - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testSingleWhiteBeforeTrailingComment(self): - unformatted_code = textwrap.dedent("""\ - if a+b: # comment - pass - """) - expected_formatted_code = textwrap.dedent("""\ - if a + b: # comment - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testSplittingSemicolonStatements(self): - unformatted_code = textwrap.dedent("""\ - def f(): - x = y + 42 ; z = n * 42 - if True: a += 1 ; b += 1; c += 1 - """) - expected_formatted_code = textwrap.dedent("""\ - def f(): - x = y + 42 - z = n * 42 - if True: - a += 1 - b += 1 - c += 1 - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testSpaceBetweenEndingCommandAndClosingBracket(self): - unformatted_code = textwrap.dedent("""\ - a = [ - 1, - ] - """) - expected_formatted_code = textwrap.dedent("""\ - a = [1, ] - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testContinuedNonOudentedLine(self): - code = textwrap.dedent("""\ - class eld(d): - if str(geom.geom_type).upper( - ) != self.geom_type and not self.geom_type == 'GEOMETRY': - ror(code='om_type') - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - - def testWrappingPercentExpressions(self): - unformatted_code = textwrap.dedent("""\ - def f(): - if True: - zzzzz = '%s-%s' % (xxxxxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxx.yyy + 1) - zzzzz = '%s-%s'.ww(xxxxxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxx.yyy + 1) - zzzzz = '%s-%s' % (xxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxxxxxx + 1) - zzzzz = '%s-%s'.ww(xxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxxxxxx + 1) - """) - expected_formatted_code = textwrap.dedent("""\ - def f(): - if True: - zzzzz = '%s-%s' % (xxxxxxxxxxxxxxxxxxxxxxxxxx + 1, - xxxxxxxxxxxxxxxxx.yyy + 1) - zzzzz = '%s-%s'.ww(xxxxxxxxxxxxxxxxxxxxxxxxxx + 1, - xxxxxxxxxxxxxxxxx.yyy + 1) - zzzzz = '%s-%s' % (xxxxxxxxxxxxxxxxxxxxxxx + 1, - xxxxxxxxxxxxxxxxxxxxx + 1) - zzzzz = '%s-%s'.ww(xxxxxxxxxxxxxxxxxxxxxxx + 1, - xxxxxxxxxxxxxxxxxxxxx + 1) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testAlignClosingBracketWithVisualIndentation(self): - unformatted_code = textwrap.dedent("""\ - TEST_LIST = ('foo', 'bar', # first comment - 'baz' # second comment - ) - """) - expected_formatted_code = textwrap.dedent("""\ - TEST_LIST = ( - 'foo', - 'bar', # first comment - 'baz' # second comment - ) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - unformatted_code = textwrap.dedent("""\ - def f(): - - def g(): - while (xxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz]) == 'aaaaaaaaaaa' and - xxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb' - ): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - def f(): - def g(): - while (xxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz]) == 'aaaaaaaaaaa' and - xxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == - 'bbbbbbb'): - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testIndentSizeChanging(self): - unformatted_code = textwrap.dedent("""\ - if True: - runtime_mins = (program_end_time - program_start_time).total_seconds() / 60.0 - """) - expected_formatted_code = textwrap.dedent("""\ - if True: - runtime_mins = ( - program_end_time - program_start_time).total_seconds() / 60.0 - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testHangingIndentCollision(self): - unformatted_code = textwrap.dedent("""\ - if (aaaaaaaaaaaaaa + bbbbbbbbbbbbbbbb == ccccccccccccccccc and xxxxxxxxxxxxx or yyyyyyyyyyyyyyyyy): - pass - elif (xxxxxxxxxxxxxxx(aaaaaaaaaaa, bbbbbbbbbbbbbb, cccccccccccc, dddddddddd=None)): - pass - - - def h(): - if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): - pass - - for connection in itertools.chain(branch.contact, branch.address, morestuff.andmore.andmore.andmore.andmore.andmore.andmore.andmore): - dosomething(connection) - """) - expected_formatted_code = textwrap.dedent("""\ - if (aaaaaaaaaaaaaa + bbbbbbbbbbbbbbbb == ccccccccccccccccc and xxxxxxxxxxxxx or - yyyyyyyyyyyyyyyyy): - pass - elif (xxxxxxxxxxxxxxx( - aaaaaaaaaaa, bbbbbbbbbbbbbb, cccccccccccc, dddddddddd=None)): - pass - - - def h(): - if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and - xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): - pass - - for connection in itertools.chain( - branch.contact, branch.address, - morestuff.andmore.andmore.andmore.andmore.andmore.andmore.andmore): - dosomething(connection) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testB20016122(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: pep8, SPLIT_PENALTY_IMPORT_NAMES: 35}')) - unformatted_code = textwrap.dedent("""\ - from a_very_long_or_indented_module_name_yada_yada import (long_argument_1, - long_argument_2) - """) - expected_formatted_code = textwrap.dedent("""\ - from a_very_long_or_indented_module_name_yada_yada import ( - long_argument_1, long_argument_2) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) - finally: - style.SetGlobalStyle(style.CreatePEP8Style()) - - def testSplittingBeforeLogicalOperator(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: pep8, split_before_logical_operator: True}')) - unformatted_code = textwrap.dedent("""\ - def foo(): - return bool(update.message.new_chat_member or update.message.left_chat_member or - update.message.new_chat_title or update.message.new_chat_photo or - update.message.delete_chat_photo or update.message.group_chat_created or - update.message.supergroup_chat_created or update.message.channel_chat_created - or update.message.migrate_to_chat_id or update.message.migrate_from_chat_id or - update.message.pinned_message) - """) - expected_formatted_code = textwrap.dedent("""\ - def foo(): - return bool( - update.message.new_chat_member or update.message.left_chat_member - or update.message.new_chat_title or update.message.new_chat_photo - or update.message.delete_chat_photo - or update.message.group_chat_created - or update.message.supergroup_chat_created - or update.message.channel_chat_created - or update.message.migrate_to_chat_id - or update.message.migrate_from_chat_id - or update.message.pinned_message) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) - finally: - style.SetGlobalStyle(style.CreatePEP8Style()) - - def testContiguousListEndingWithComment(self): - unformatted_code = textwrap.dedent("""\ - if True: - if True: - keys.append(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) # may be unassigned. - """) - expected_formatted_code = textwrap.dedent("""\ - if True: - if True: - keys.append( - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) # may be unassigned. - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testSplittingBeforeFirstArgument(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: pep8, split_before_first_argument: True}')) - unformatted_code = textwrap.dedent("""\ - a_very_long_function_name(long_argument_name_1=1, long_argument_name_2=2, - long_argument_name_3=3, long_argument_name_4=4) - """) - expected_formatted_code = textwrap.dedent("""\ - a_very_long_function_name( - long_argument_name_1=1, - long_argument_name_2=2, - long_argument_name_3=3, - long_argument_name_4=4) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) - finally: - style.SetGlobalStyle(style.CreatePEP8Style()) - - -class TestingNotInParameters(unittest.TestCase): - - def testNotInParams(self): - unformatted_code = textwrap.dedent("""\ - list("a long line to break the line. a long line to break the brk a long lin", not True) - """) - - expected_code = textwrap.dedent("""\ - list("a long line to break the line. a long line to break the brk a long lin", - not True) - """) - - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertEqual(expected_code, reformatter.Reformat(uwlines)) - - -@unittest.skipIf(py3compat.PY3, 'Requires Python 2') -class TestVerifyNoVerify(ReformatterTest): - - @classmethod - def setUpClass(cls): - style.SetGlobalStyle(style.CreatePEP8Style()) - - def testVerifyException(self): - unformatted_code = textwrap.dedent("""\ - class ABC(metaclass=type): - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - with self.assertRaises(verifier.InternalError): - reformatter.Reformat(uwlines, verify=True) - reformatter.Reformat(uwlines) # verify should be False by default. - - def testNoVerify(self): - unformatted_code = textwrap.dedent("""\ - class ABC(metaclass=type): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - class ABC(metaclass=type): - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat( - uwlines, verify=False)) - - def testVerifyFutureImport(self): - unformatted_code = textwrap.dedent("""\ - from __future__ import print_function - - def call_my_function(the_function): - the_function("hi") - - if __name__ == "__main__": - call_my_function(print) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - with self.assertRaises(verifier.InternalError): - reformatter.Reformat(uwlines, verify=True) - - expected_formatted_code = textwrap.dedent("""\ - from __future__ import print_function - - - def call_my_function(the_function): - the_function("hi") - - - if __name__ == "__main__": - call_my_function(print) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat( - uwlines, verify=False)) - - def testContinuationLineShouldBeDistinguished(self): - unformatted_code = textwrap.dedent("""\ - class Foo(object): - - def bar(self): - if self.solo_generator_that_is_long is None and len( - self.generators + self.next_batch) == 1: - pass - """) - expected_formatted_code = textwrap.dedent("""\ - class Foo(object): - def bar(self): - if self.solo_generator_that_is_long is None and len( - self.generators + self.next_batch) == 1: - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat( - uwlines, verify=False)) - - -@unittest.skipUnless(py3compat.PY3, 'Requires Python 3') -class TestsForPython3Code(ReformatterTest): - """Test a few constructs that are new Python 3 syntax.""" - - @classmethod - def setUpClass(cls): - style.SetGlobalStyle(style.CreatePEP8Style()) - - def testTypedNames(self): - unformatted_code = textwrap.dedent("""\ - def x(aaaaaaaaaaaaaaa:int,bbbbbbbbbbbbbbbb:str,ccccccccccccccc:dict,eeeeeeeeeeeeee:set={1, 2, 3})->bool: - pass - """) - expected_formatted_code = textwrap.dedent("""\ - def x(aaaaaaaaaaaaaaa: int, - bbbbbbbbbbbbbbbb: str, - ccccccccccccccc: dict, - eeeeeeeeeeeeee: set={1, 2, 3}) -> bool: - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testKeywordOnlyArgSpecifier(self): - unformatted_code = textwrap.dedent("""\ - def foo(a, *, kw): - return a+kw - """) - expected_formatted_code = textwrap.dedent("""\ - def foo(a, *, kw): - return a + kw - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testAnnotations(self): - unformatted_code = textwrap.dedent("""\ - def foo(a: list, b: "bar") -> dict: - return a+b - """) - expected_formatted_code = textwrap.dedent("""\ - def foo(a: list, b: "bar") -> dict: - return a + b - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testExecAsNonKeyword(self): - unformatted_code = 'methods.exec( sys.modules[name])\n' - expected_formatted_code = 'methods.exec(sys.modules[name])\n' - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testAsyncFunctions(self): - if sys.version_info[1] < 5: - return - code = textwrap.dedent("""\ - import asyncio - import time - - - @print_args - async def slow_operation(): - await asyncio.sleep(1) - # print("Slow operation {} complete".format(n)) - - - async def main(): - start = time.time() - if (await get_html()): - pass - """) - uwlines = _ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines, verify=False)) - - def testNoSpacesAroundPowerOparator(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: pep8, SPACES_AROUND_POWER_OPERATOR: True}')) - unformatted_code = textwrap.dedent("""\ - a**b - """) - expected_formatted_code = textwrap.dedent("""\ - a ** b - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) - finally: - style.SetGlobalStyle(style.CreatePEP8Style()) - - def testSpacesAroundDefaultOrNamedAssign(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: pep8, ' - 'SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN: True}')) - unformatted_code = textwrap.dedent("""\ - f(a=5) - """) - expected_formatted_code = textwrap.dedent("""\ - f(a = 5) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) - finally: - style.SetGlobalStyle(style.CreatePEP8Style()) - - def testAsyncWithPrecedingComment(self): - if sys.version_info[1] < 5: - return - unformatted_code = textwrap.dedent("""\ - import asyncio - - # Comment - async def bar(): - pass - - async def foo(): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - import asyncio - - - # Comment - async def bar(): - pass - - - async def foo(): - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - -class TestsForFBStyle(ReformatterTest): - - @classmethod - def setUpClass(cls): - style.SetGlobalStyle(style.CreateFacebookStyle()) - - def testNoNeedForLineBreaks(self): - unformatted_code = textwrap.dedent("""\ - def overly_long_function_name( - just_one_arg, **kwargs): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - def overly_long_function_name(just_one_arg, **kwargs): - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testDedentClosingBracket(self): - unformatted_code = textwrap.dedent("""\ - def overly_long_function_name( - first_argument_on_the_same_line, - second_argument_makes_the_line_too_long): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - def overly_long_function_name( - first_argument_on_the_same_line, second_argument_makes_the_line_too_long - ): - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testBreakAfterOpeningBracketIfContentsTooBig(self): - unformatted_code = textwrap.dedent("""\ - def overly_long_function_name(a, b, c, d, e, f, g, h, i, j, k, l, m, - n, o, p, q, r, s, t, u, v, w, x, y, z): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - def overly_long_function_name( - a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, \ -v, w, x, y, z - ): - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testDedentClosingBracketWithComments(self): - unformatted_code = textwrap.dedent("""\ - def overly_long_function_name( - # comment about the first argument - first_argument_with_a_very_long_name_or_so, - # comment about the second argument - second_argument_makes_the_line_too_long): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - def overly_long_function_name( - # comment about the first argument - first_argument_with_a_very_long_name_or_so, - # comment about the second argument - second_argument_makes_the_line_too_long - ): - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testDedentImportAsNames(self): - unformatted_code = textwrap.dedent("""\ - from module import ( - internal_function as function, - SOME_CONSTANT_NUMBER1, - SOME_CONSTANT_NUMBER2, - SOME_CONSTANT_NUMBER3, - ) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(unformatted_code, reformatter.Reformat(uwlines)) - - def testDedentTestListGexp(self): - # TODO(ambv): Arguably _DetermineMustSplitAnnotation shouldn't enforce - # breaks only on the basis of a trailing comma if the entire thing fits - # in a single line. - unformatted_code = textwrap.dedent("""\ - try: - pass - except ( - IOError, OSError, LookupError, RuntimeError, OverflowError - ) as exception: - pass - - try: - pass - except ( - IOError, - OSError, - LookupError, - RuntimeError, - OverflowError, - ) as exception: - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(unformatted_code, reformatter.Reformat(uwlines)) - - def testBrokenIdempotency(self): - # TODO(ambv): The following behaviour should be fixed. - pass0_code = textwrap.dedent("""\ - try: - pass - except (IOError, OSError, LookupError, RuntimeError, OverflowError) as exception: - pass - """) - pass1_code = textwrap.dedent("""\ - try: - pass - except ( - IOError, OSError, LookupError, RuntimeError, OverflowError - ) as exception: - pass - """) - uwlines = _ParseAndUnwrap(pass0_code) - self.assertCodeEqual(pass1_code, reformatter.Reformat(uwlines)) - - pass2_code = textwrap.dedent("""\ - try: - pass - except ( - IOError, OSError, LookupError, RuntimeError, OverflowError - ) as exception: - pass - """) - uwlines = _ParseAndUnwrap(pass1_code) - self.assertCodeEqual(pass2_code, reformatter.Reformat(uwlines)) - - def testIfExprHangingIndent(self): - unformatted_code = textwrap.dedent("""\ - if True: - if True: - if True: - if not self.frobbies and ( - self.foobars.counters['db.cheeses'] != 1 or - self.foobars.counters['db.marshmellow_skins'] != 1): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - if True: - if True: - if True: - if not self.frobbies and ( - self.foobars.counters['db.cheeses'] != 1 or - self.foobars.counters['db.marshmellow_skins'] != 1 - ): - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testSimpleDedenting(self): - unformatted_code = textwrap.dedent("""\ - if True: - self.assertEqual(result.reason_not_added, "current preflight is still running") - """) - expected_formatted_code = textwrap.dedent("""\ - if True: - self.assertEqual( - result.reason_not_added, "current preflight is still running" - ) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testDedentingWithSubscripts(self): - unformatted_code = textwrap.dedent("""\ - class Foo: - class Bar: - @classmethod - def baz(cls, clues_list, effect, constraints, constraint_manager): - if clues_lists: - return cls.single_constraint_not(clues_lists, effect, constraints[0], constraint_manager) - - """) - expected_formatted_code = textwrap.dedent("""\ - class Foo: - class Bar: - @classmethod - def baz(cls, clues_list, effect, constraints, constraint_manager): - if clues_lists: - return cls.single_constraint_not( - clues_lists, effect, constraints[0], constraint_manager - ) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testDedentingCallsWithInnerLists(self): - unformatted_code = textwrap.dedent("""\ - class _(): - def _(): - cls.effect_clues = { - 'effect': Clue((cls.effect_time, 'apache_host'), effect_line, 40) - } - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(unformatted_code, reformatter.Reformat(uwlines)) - - def testDedentingListComprehension(self): - unformatted_code = textwrap.dedent("""\ - class Foo(): - def _pack_results_for_constraint_or(): - self.param_groups = dict( - ( - key + 1, ParamGroup(groups[key], default_converter) - ) for key in six.moves.range(len(groups)) - ) - - for combination in cls._clues_combinations(clues_lists): - if all( - cls._verify_constraint(combination, effect, constraint) - for constraint in constraints - ): - pass - - guessed_dict = dict( - ( - key, guessed_pattern_matches[key] - ) for key in six.moves.range(len(guessed_pattern_matches)) - ) - - content = "".join( - itertools.chain( - (first_line_fragment, ), lines_between, (last_line_fragment, ) - ) - ) - - rule = Rule( - [self.cause1, self.cause2, self.cause1, self.cause2], self.effect, constraints1, - Rule.LINKAGE_AND - ) - - assert sorted(log_type.files_to_parse) == [ - ('localhost', os.path.join(path, 'node_1.log'), super_parser), - ('localhost', os.path.join(path, 'node_2.log'), super_parser) - ] - """) - expected_formatted_code = textwrap.dedent("""\ - class Foo(): - def _pack_results_for_constraint_or(): - self.param_groups = dict( - (key + 1, ParamGroup(groups[key], default_converter)) - for key in six.moves.range(len(groups)) - ) - - for combination in cls._clues_combinations(clues_lists): - if all( - cls._verify_constraint(combination, effect, constraint) - for constraint in constraints - ): - pass - - guessed_dict = dict( - (key, guessed_pattern_matches[key]) - for key in six.moves.range(len(guessed_pattern_matches)) - ) - - content = "".join( - itertools.chain( - (first_line_fragment, ), lines_between, (last_line_fragment, ) - ) - ) - - rule = Rule( - [self.cause1, self.cause2, self.cause1, self.cause2], self.effect, - constraints1, Rule.LINKAGE_AND - ) - - assert sorted(log_type.files_to_parse) == [ - ('localhost', os.path.join(path, 'node_1.log'), super_parser), - ('localhost', os.path.join(path, 'node_2.log'), super_parser) - ] - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testMustSplitDedenting(self): - unformatted_code = textwrap.dedent("""\ - class _(): - def _(): - effect_line = FrontInput( - effect_line_offset, line_content, - LineSource( - 'localhost', xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - ) - ) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(unformatted_code, reformatter.Reformat(uwlines)) - - def testDedentIfConditional(self): - unformatted_code = textwrap.dedent("""\ - class _(): - def _(): - if True: - if not self.frobbies and ( - self.foobars.counters['db.cheeses'] != 1 or - self.foobars.counters['db.marshmellow_skins'] != 1 - ): - pass - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(unformatted_code, reformatter.Reformat(uwlines)) - - def testDedentSet(self): - unformatted_code = textwrap.dedent("""\ - class _(): - def _(): - assert set(self.constraint_links.get_links()) == set( - [ - (2, 10, 100), - (2, 10, 200), - (2, 20, 100), - (2, 20, 200), - ] - ) - """) - uwlines = _ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(unformatted_code, reformatter.Reformat(uwlines)) - - def testDedentingInnerScope(self): - code = textwrap.dedent("""\ - class Foo(): - @classmethod - def _pack_results_for_constraint_or(cls, combination, constraints): - return cls._create_investigation_result( - (clue for clue in combination if not clue == Verifier.UNMATCHED), - constraints, InvestigationResult.OR - ) - """) - uwlines = _ParseAndUnwrap(code) - reformatted_code = reformatter.Reformat(uwlines) - self.assertCodeEqual(code, reformatted_code) - - uwlines = _ParseAndUnwrap(reformatted_code) - reformatted_code = reformatter.Reformat(uwlines) - self.assertCodeEqual(code, reformatted_code) - - def testCommentWithNewlinesInPrefix(self): - code = textwrap.dedent("""\ - def foo(): - if 0: - return False - - #a deadly comment - elif 1: - return True - - - print(foo()) - """) - uwlines = _ParseAndUnwrap(code) - reformatted_code = reformatter.Reformat(uwlines) - self.assertCodeEqual(code, reformatted_code) - - -def _ParseAndUnwrap(code, dumptree=False): +def ParseAndUnwrap(code, dumptree=False): """Produces unwrapped lines from the given code. Parses the code into a tree, performs comment splicing and runs the @@ -4103,7 +85,3 @@ def _ParseAndUnwrap(code, dumptree=False): uwl.CalculateFormattingInformation() return uwlines - - -if __name__ == '__main__': - unittest.main() diff --git a/yapftests/reformatter_verify_test.py b/yapftests/reformatter_verify_test.py new file mode 100644 index 000000000..861bcab3c --- /dev/null +++ b/yapftests/reformatter_verify_test.py @@ -0,0 +1,111 @@ +# Copyright 2015-2016 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Tests for yapf.reformatter.""" + +import textwrap +import unittest + +from yapf.yapflib import py3compat +from yapf.yapflib import reformatter +from yapf.yapflib import style +from yapf.yapflib import verifier + +from yapftests import reformatter_test + + +@unittest.skipIf(py3compat.PY3, 'Requires Python 2') +class TestVerifyNoVerify(reformatter_test.ReformatterTest): + + @classmethod + def setUpClass(cls): + style.SetGlobalStyle(style.CreatePEP8Style()) + + def testVerifyException(self): + unformatted_code = textwrap.dedent("""\ + class ABC(metaclass=type): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + with self.assertRaises(verifier.InternalError): + reformatter.Reformat(uwlines, verify=True) + reformatter.Reformat(uwlines) # verify should be False by default. + + def testNoVerify(self): + unformatted_code = textwrap.dedent("""\ + class ABC(metaclass=type): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + class ABC(metaclass=type): + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat( + uwlines, verify=False)) + + def testVerifyFutureImport(self): + unformatted_code = textwrap.dedent("""\ + from __future__ import print_function + + def call_my_function(the_function): + the_function("hi") + + if __name__ == "__main__": + call_my_function(print) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + with self.assertRaises(verifier.InternalError): + reformatter.Reformat(uwlines, verify=True) + + expected_formatted_code = textwrap.dedent("""\ + from __future__ import print_function + + + def call_my_function(the_function): + the_function("hi") + + + if __name__ == "__main__": + call_my_function(print) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat( + uwlines, verify=False)) + + def testContinuationLineShouldBeDistinguished(self): + unformatted_code = textwrap.dedent("""\ + class Foo(object): + + def bar(self): + if self.solo_generator_that_is_long is None and len( + self.generators + self.next_batch) == 1: + pass + """) + expected_formatted_code = textwrap.dedent("""\ + class Foo(object): + def bar(self): + if self.solo_generator_that_is_long is None and len( + self.generators + self.next_batch) == 1: + pass + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat( + uwlines, verify=False)) + + +if __name__ == '__main__': + unittest.main() From 254b2d032593a9985c50edd7c20a9d57100ca63c Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 23 Oct 2016 02:20:12 -0700 Subject: [PATCH 057/719] Use lower case for the style help --- yapf/__init__.py | 2 +- yapftests/main_test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 5f0dce13a..22a5ceea8 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -127,7 +127,7 @@ def main(argv): for option, docstring in sorted(style.Help().items()): for line in docstring.splitlines(): print('#', line) - print(option, '=', style.Get(option), sep='') + print(option.lower(), '=', style.Get(option), sep='') print() return 0 diff --git a/yapftests/main_test.py b/yapftests/main_test.py index abdf28310..4293b19d6 100644 --- a/yapftests/main_test.py +++ b/yapftests/main_test.py @@ -138,7 +138,7 @@ def testHelp(self): ret = yapf.main(['-', '--style-help', '--style=pep8']) self.assertEqual(ret, 0) help_message = out.getvalue() - self.assertIn("INDENT_WIDTH=4", help_message) + self.assertIn("indent_width=4", help_message) self.assertIn("The number of spaces required before a trailing comment.", help_message) From c32f5aa7456edfce2e3eacb95ef50e6d25875918 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 23 Oct 2016 02:40:21 -0700 Subject: [PATCH 058/719] Look for last newline to calculate prefix --- yapf/yapflib/comment_splicer.py | 2 +- yapftests/reformatter_facebook_test.py | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index 1759bf787..4cf70be63 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -62,7 +62,7 @@ def _VisitNodeRec(node): child_prefix = child.prefix.lstrip('\n') prefix_indent = child_prefix[:child_prefix.find('#')] if '\n' in prefix_indent: - prefix_indent = prefix_indent[prefix_indent.find('\n') + 1:] + prefix_indent = prefix_indent[prefix_indent.rfind('\n') + 1:] child.prefix = '' if child.type == token.NEWLINE: diff --git a/yapftests/reformatter_facebook_test.py b/yapftests/reformatter_facebook_test.py index c79bf0340..5955c84b1 100644 --- a/yapftests/reformatter_facebook_test.py +++ b/yapftests/reformatter_facebook_test.py @@ -375,11 +375,12 @@ def _pack_results_for_constraint_or(cls, combination, constraints): self.assertCodeEqual(code, reformatted_code) def testCommentWithNewlinesInPrefix(self): - code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ def foo(): if 0: return False + #a deadly comment elif 1: return True @@ -387,9 +388,20 @@ def foo(): print(foo()) """) - uwlines = reformatter_test.ParseAndUnwrap(code) - reformatted_code = reformatter.Reformat(uwlines) - self.assertCodeEqual(code, reformatted_code) + expected_formatted_code = textwrap.dedent("""\ + def foo(): + if 0: + return False + + #a deadly comment + elif 1: + return True + + + print(foo()) + """) + uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) if __name__ == '__main__': From 8583a2543982654eb27c8689e0600cace4b3d9a1 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 23 Oct 2016 16:09:06 -0700 Subject: [PATCH 059/719] Refactor the parsing and checking test code --- yapftests/blank_line_calculator_test.py | 100 ++------ yapftests/format_decision_state_test.py | 58 ++--- yapftests/format_token_test.py | 1 + yapftests/line_joiner_test.py | 27 +- yapftests/pytree_unwrapper_test.py | 89 ++----- yapftests/pytree_visitor_test.py | 8 +- yapftests/reformatter_basic_test.py | 230 +++++++++--------- yapftests/reformatter_buganizer_test.py | 146 +++++------ yapftests/reformatter_facebook_test.py | 42 ++-- yapftests/reformatter_pep8_test.py | 34 +-- yapftests/reformatter_python3_test.py | 20 +- yapftests/reformatter_style_config_test.py | 8 +- yapftests/reformatter_verify_test.py | 14 +- ...eformatter_test.py => yapf_test_helper.py} | 4 +- 14 files changed, 320 insertions(+), 461 deletions(-) rename yapftests/{reformatter_test.py => yapf_test_helper.py} (96%) diff --git a/yapftests/blank_line_calculator_test.py b/yapftests/blank_line_calculator_test.py index d3f6af274..f8fee8778 100644 --- a/yapftests/blank_line_calculator_test.py +++ b/yapftests/blank_line_calculator_test.py @@ -13,51 +13,20 @@ # limitations under the License. """Tests for yapf.blank_line_calculator.""" -import difflib -import sys import textwrap import unittest -from yapf.yapflib import blank_line_calculator -from yapf.yapflib import comment_splicer -from yapf.yapflib import pytree_unwrapper -from yapf.yapflib import pytree_utils -from yapf.yapflib import pytree_visitor from yapf.yapflib import reformatter -from yapf.yapflib import split_penalty from yapf.yapflib import style -from yapf.yapflib import subtype_assigner - - -class BlankLineCalculatorTest(unittest.TestCase): - - def assertCodeEqual(self, expected_code, code): - if code != expected_code: - msg = ['Code format mismatch:', 'Expected:'] - linelen = style.Get('COLUMN_LIMIT') - for l in expected_code.splitlines(): - if len(l) > linelen: - msg.append('!> %s' % l) - else: - msg.append(' > %s' % l) - msg.append('Actual:') - for l in code.splitlines(): - if len(l) > linelen: - msg.append('!> %s' % l) - else: - msg.append(' > %s' % l) - msg.append('Diff:') - msg.extend( - difflib.unified_diff( - code.splitlines(), - expected_code.splitlines(), - fromfile='actual', - tofile='expected', - lineterm='')) - self.fail('\n'.join(msg)) - - -class BasicBlankLineCalculatorTest(BlankLineCalculatorTest): + +from yapftests import yapf_test_helper + + +class BasicBlankLineCalculatorTest(yapf_test_helper.YAPFTest): + + @classmethod + def setUpClass(cls): + style.SetGlobalStyle(style.CreateChromiumStyle()) def testDecorators(self): unformatted_code = textwrap.dedent("""\ @@ -71,7 +40,7 @@ def foo(): def foo(): pass """) - uwlines = _ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testComplexDecorators(self): @@ -107,7 +76,7 @@ class moo(object): def method(self): pass """) - uwlines = _ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testCodeAfterFunctionsAndClasses(self): @@ -152,7 +121,7 @@ def method_2(self): except Error as error: pass """) - uwlines = _ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testCommentSpacing(self): @@ -218,7 +187,7 @@ def foo(self): # comment pass """) - uwlines = _ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testCommentBeforeMethod(self): @@ -229,7 +198,7 @@ class foo(object): def f(self): pass """) - uwlines = _ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testCommentsBeforeClassDefs(self): @@ -242,7 +211,7 @@ def testCommentsBeforeClassDefs(self): class Foo(object): pass ''') - uwlines = _ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testCommentsBeforeDecorator(self): @@ -252,7 +221,7 @@ def testCommentsBeforeDecorator(self): def a(): pass """) - uwlines = _ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) code = textwrap.dedent("""\ @@ -263,7 +232,7 @@ def a(): def a(): pass """) - uwlines = _ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testCommentsAfterDecorator(self): @@ -280,7 +249,7 @@ def _(): def test_unicode_filename_in_sdist(self, sdist_unicode, tmpdir, monkeypatch): pass """) - uwlines = _ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testInnerClasses(self): @@ -304,40 +273,9 @@ class TaskValidationError(Error): class DeployAPIHTTPError(Error): pass """) - uwlines = _ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) -def _ParseAndUnwrap(code, dumptree=False): - """Produces unwrapped lines from the given code. - - Parses the code into a tree, performs comment splicing and runs the - unwrapper. - - Arguments: - code: code to parse as a string - dumptree: if True, the parsed pytree (after comment splicing) is dumped - to stderr. Useful for debugging. - - Returns: - List of unwrapped lines. - """ - style.SetGlobalStyle(style.CreateChromiumStyle()) - tree = pytree_utils.ParseCodeToTree(code) - comment_splicer.SpliceComments(tree) - subtype_assigner.AssignSubtypes(tree) - split_penalty.ComputeSplitPenalties(tree) - blank_line_calculator.CalculateBlankLines(tree) - - if dumptree: - pytree_visitor.DumpPyTree(tree, target_stream=sys.stderr) - - uwlines = pytree_unwrapper.UnwrapPyTree(tree) - for uwl in uwlines: - uwl.CalculateFormattingInformation() - - return uwlines - - if __name__ == '__main__': unittest.main() diff --git a/yapftests/format_decision_state_test.py b/yapftests/format_decision_state_test.py index 755207a31..c4b1ce868 100644 --- a/yapftests/format_decision_state_test.py +++ b/yapftests/format_decision_state_test.py @@ -13,60 +13,30 @@ # limitations under the License. """Tests for yapf.format_decision_state.""" -import sys import textwrap import unittest -from yapf.yapflib import comment_splicer from yapf.yapflib import format_decision_state -from yapf.yapflib import pytree_unwrapper from yapf.yapflib import pytree_utils -from yapf.yapflib import pytree_visitor -from yapf.yapflib import split_penalty -from yapf.yapflib import subtype_assigner +from yapf.yapflib import style from yapf.yapflib import unwrapped_line +from yapftests import yapf_test_helper -class FormatDecisionStateTest(unittest.TestCase): - def _ParseAndUnwrap(self, code, dumptree=False): - """Produces unwrapped lines from the given code. +class FormatDecisionStateTest(yapf_test_helper.YAPFTest): - Parses the code into a tree, performs comment splicing and runs the - unwrapper. - - Arguments: - code: code to parse as a string - dumptree: if True, the parsed pytree (after comment splicing) is dumped - to stderr. Useful for debugging. - - Returns: - List of unwrapped lines. - """ - tree = pytree_utils.ParseCodeToTree(code) - comment_splicer.SpliceComments(tree) - subtype_assigner.AssignSubtypes(tree) - split_penalty.ComputeSplitPenalties(tree) - - if dumptree: - pytree_visitor.DumpPyTree(tree, target_stream=sys.stderr) - - return pytree_unwrapper.UnwrapPyTree(tree) - - def _FilterLine(self, uwline): - """Filter out nonsemantic tokens from the UnwrappedLines.""" - return [ - ft for ft in uwline.tokens - if ft.name not in pytree_utils.NONSEMANTIC_TOKENS - ] + @classmethod + def setUpClass(cls): + style.SetGlobalStyle(style.CreateChromiumStyle()) def testSimpleFunctionDefWithNoSplitting(self): code = textwrap.dedent(r""" def f(a, b): pass """) - uwlines = self._ParseAndUnwrap(code) - uwline = unwrapped_line.UnwrappedLine(0, self._FilterLine(uwlines[0])) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + uwline = unwrapped_line.UnwrappedLine(0, _FilterLine(uwlines[0])) uwline.CalculateFormattingInformation() # Add: 'f' @@ -118,8 +88,8 @@ def testSimpleFunctionDefWithSplitting(self): def f(a, b): pass """) - uwlines = self._ParseAndUnwrap(code) - uwline = unwrapped_line.UnwrappedLine(0, self._FilterLine(uwlines[0])) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + uwline = unwrapped_line.UnwrappedLine(0, _FilterLine(uwlines[0])) uwline.CalculateFormattingInformation() # Add: 'f' @@ -161,5 +131,13 @@ def f(a, b): self.assertEqual(repr(state), repr(clone)) +def _FilterLine(uwline): + """Filter out nonsemantic tokens from the UnwrappedLines.""" + return [ + ft for ft in uwline.tokens + if ft.name not in pytree_utils.NONSEMANTIC_TOKENS + ] + + if __name__ == '__main__': unittest.main() diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index b8078c733..7f5368f6f 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -17,6 +17,7 @@ from lib2to3 import pytree from lib2to3.pgen2 import token + from yapf.yapflib import format_token diff --git a/yapftests/line_joiner_test.py b/yapftests/line_joiner_test.py index 842f87f10..a29e94640 100644 --- a/yapftests/line_joiner_test.py +++ b/yapftests/line_joiner_test.py @@ -22,32 +22,15 @@ from yapf.yapflib import pytree_utils from yapf.yapflib import style +from yapftests import yapf_test_helper -class LineJoinerTest(unittest.TestCase): + +class LineJoinerTest(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): style.SetGlobalStyle(style.CreatePEP8Style()) - def _ParseAndUnwrap(self, code): - """Produces unwrapped lines from the given code. - - Parses the code into a tree, performs comment splicing and runs the - unwrapper. - - Arguments: - code: code to parse as a string - - Returns: - List of unwrapped lines. - """ - tree = pytree_utils.ParseCodeToTree(code) - comment_splicer.SpliceComments(tree) - uwlines = pytree_unwrapper.UnwrapPyTree(tree) - for uwl in uwlines: - uwl.CalculateFormattingInformation() - return uwlines - def _CheckLineJoining(self, code, join_lines): """Check that the given UnwrappedLines are joined as expected. @@ -55,8 +38,8 @@ def _CheckLineJoining(self, code, join_lines): code: The code to check to see if we can join it. join_lines: True if we expect the lines to be joined. """ - uwlines = self._ParseAndUnwrap(code) - self.assertEqual(line_joiner.CanMergeMultipleLines(uwlines), join_lines) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(line_joiner.CanMergeMultipleLines(uwlines), join_lines) def testSimpleSingleLineStatement(self): code = textwrap.dedent(u"""\ diff --git a/yapftests/pytree_unwrapper_test.py b/yapftests/pytree_unwrapper_test.py index 7d9806716..ccf01cd4d 100644 --- a/yapftests/pytree_unwrapper_test.py +++ b/yapftests/pytree_unwrapper_test.py @@ -22,30 +22,10 @@ from yapf.yapflib import pytree_utils from yapf.yapflib import pytree_visitor +from yapftests import yapf_test_helper -class PytreeUnwrapperTest(unittest.TestCase): - def _ParseAndUnwrap(self, code, dumptree=False): - """Produces unwrapped lines from the given code. - - Parses the code into a tree, performs comment splicing and runs the - unwrapper. - - Arguments: - code: code to parse as a string - dumptree: if True, the parsed pytree (after comment splicing) is dumped - to stderr. Useful for debugging. - - Returns: - List of unwrapped lines. - """ - tree = pytree_utils.ParseCodeToTree(code) - comment_splicer.SpliceComments(tree) - - if dumptree: - pytree_visitor.DumpPyTree(tree, target_stream=sys.stderr) - - return pytree_unwrapper.UnwrapPyTree(tree) +class PytreeUnwrapperTest(yapf_test_helper.YAPFTest): def _CheckUnwrappedLines(self, uwlines, list_of_expected): """Check that the given UnwrappedLines match expectations. @@ -71,27 +51,27 @@ def testSimpleFileScope(self): # a comment y = 2 """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckUnwrappedLines(uwlines, [ (0, ['x', '=', '1']), (0, ['# a comment']), - (0, ['y', '=', '2'])]) # yapf: disable + (0, ['y', '=', '2'])]) def testSimpleMultilineStatement(self): code = textwrap.dedent(r""" y = (1 + x) """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckUnwrappedLines(uwlines, [ - (0, ['y', '=', '(', '1', '+', 'x', ')'])]) # yapf: disable + (0, ['y', '=', '(', '1', '+', 'x', ')'])]) def testFileScopeWithInlineComment(self): code = textwrap.dedent(r""" x = 1 # a comment y = 2 """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckUnwrappedLines(uwlines, [ (0, ['x', '=', '1', '# a comment']), (0, ['y', '=', '2'])]) # yapf: disable @@ -102,7 +82,7 @@ def testSimpleIf(self): x = 1 y = 2 """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckUnwrappedLines(uwlines, [ (0, ['if', 'foo', ':']), (1, ['x', '=', '1']), @@ -115,7 +95,7 @@ def testSimpleIfWithComments(self): x = 1 y = 2 """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckUnwrappedLines(uwlines, [ (0, ['# c1']), (0, ['if', 'foo', ':', '# c2']), @@ -130,7 +110,7 @@ def testIfWithCommentsInside(self): # c3 y = 2 """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckUnwrappedLines(uwlines, [ (0, ['if', 'foo', ':']), (1, ['# c1']), @@ -148,7 +128,7 @@ def testIfElifElse(self): # c3 z = 1 """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckUnwrappedLines(uwlines, [ (0, ['if', 'x', ':']), (1, ['x', '=', '1', '# c1']), @@ -167,7 +147,7 @@ def testNestedCompoundTwoLevel(self): j = 1 k = 1 """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckUnwrappedLines(uwlines, [ (0, ['if', 'x', ':']), (1, ['x', '=', '1', '# c1']), @@ -182,7 +162,7 @@ def testSimpleWhile(self): # c2 x = 1 """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckUnwrappedLines(uwlines, [ (0, ['while', 'x', '>', '1', ':', '# c1']), (1, ['# c2']), @@ -201,7 +181,7 @@ def testSimpleTry(self): finally: pass """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckUnwrappedLines(uwlines, [ (0, ['try', ':']), (1, ['pass']), @@ -220,7 +200,7 @@ def foo(x): # c1 # c2 return x """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckUnwrappedLines(uwlines, [ (0, ['def', 'foo', '(', 'x', ')', ':', '# c1']), (1, ['# c2']), @@ -236,7 +216,7 @@ def bar(): # c3 # c4 return x """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckUnwrappedLines(uwlines, [ (0, ['def', 'foo', '(', 'x', ')', ':', '# c1']), (1, ['# c2']), @@ -251,7 +231,7 @@ class Klass: # c1 # c2 p = 1 """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckUnwrappedLines(uwlines, [ (0, ['class', 'Klass', ':', '# c1']), (1, ['# c2']), @@ -261,7 +241,7 @@ def testSingleLineStmtInFunc(self): code = textwrap.dedent(r""" def f(): return 37 """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckUnwrappedLines(uwlines, [ (0, ['def', 'f', '(', ')', ':']), (1, ['return', '37'])]) # yapf: disable @@ -274,7 +254,7 @@ def testMultipleComments(self): def f(): pass """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckUnwrappedLines(uwlines, [ (0, ['# Comment #1']), (0, ['# Comment #2']), @@ -289,34 +269,13 @@ def testSplitListWithComment(self): 'c', # hello world ] """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckUnwrappedLines(uwlines, [ (0, ['a', '=', '[', "'a'", ',', "'b'", ',', "'c'", ',', '# hello world', ']'])]) # yapf: disable -class MatchBracketsTest(unittest.TestCase): - - def _ParseAndUnwrap(self, code, dumptree=False): - """Produces unwrapped lines from the given code. - - Parses the code into a tree, match brackets and runs the unwrapper. - - Arguments: - code: code to parse as a string - dumptree: if True, the parsed pytree (after comment splicing) is dumped to - stderr. Useful for debugging. - - Returns: - List of unwrapped lines. - """ - tree = pytree_utils.ParseCodeToTree(code) - comment_splicer.SpliceComments(tree) - - if dumptree: - pytree_visitor.DumpPyTree(tree, target_stream=sys.stderr) - - return pytree_unwrapper.UnwrapPyTree(tree) +class MatchBracketsTest(yapf_test_helper.YAPFTest): def _CheckMatchingBrackets(self, uwlines, list_of_expected): """Check that the tokens have the expected matching bracket. @@ -349,7 +308,7 @@ def testFunctionDef(self): def foo(a, b={'hello': ['w','d']}, c=[42, 37]): pass """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckMatchingBrackets(uwlines, [ [(2, 24), (7, 15), (10, 14), (19, 23)], [] @@ -361,7 +320,7 @@ def testDecorator(self): def foo(a, b, c): pass """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckMatchingBrackets(uwlines, [ [(2, 3)], [(2, 8)], @@ -373,7 +332,7 @@ def testClassDef(self): class A(B, C, D): pass """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckMatchingBrackets(uwlines, [ [(2, 8)], [] diff --git a/yapftests/pytree_visitor_test.py b/yapftests/pytree_visitor_test.py index d0ab83457..910901057 100644 --- a/yapftests/pytree_visitor_test.py +++ b/yapftests/pytree_visitor_test.py @@ -46,16 +46,16 @@ def Visit_NAME(self, leaf): self.DefaultLeafVisit(leaf) -_VISITOR_TEST_SIMPLE_CODE = r''' +_VISITOR_TEST_SIMPLE_CODE = r""" foo = bar baz = x -''' +""" -_VISITOR_TEST_NESTED_CODE = r''' +_VISITOR_TEST_NESTED_CODE = r""" if x: if y: return z -''' +""" class PytreeVisitorTest(unittest.TestCase): diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index edf9b3d8f..06048bec7 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -21,10 +21,10 @@ from yapf.yapflib import style from yapf.yapflib import verifier -from yapftests import reformatter_test +from yapftests import yapf_test_helper -class BasicReformatterTest(reformatter_test.ReformatterTest): +class BasicReformatterTest(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): @@ -39,7 +39,7 @@ def testSimple(self): if a + b: pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSimpleFunctions(self): @@ -58,7 +58,7 @@ def g(): def f(): pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSimpleFunctionsWithTrailingComments(self): @@ -87,7 +87,7 @@ def f( # Intermediate comment xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testBlankLinesAtEndOfFile(self): @@ -102,7 +102,7 @@ def foobar(): # foo def foobar(): # foo pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) unformatted_code = textwrap.dedent("""\ @@ -114,7 +114,7 @@ def foobar(): # foo expected_formatted_code = textwrap.dedent("""\ x = {'a': 37, 'b': 42, 'c': 927} """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testMultipleUgliness(self): @@ -154,7 +154,7 @@ def g(self, x, y=42): def f(a): return 37 + -+a[42 - x:y**3] """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testComments(self): @@ -207,14 +207,14 @@ class Baz(object): class Qux(object): pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSingleComment(self): code = textwrap.dedent("""\ # Thing 1 """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testCommentsInDataLiteral(self): @@ -231,7 +231,7 @@ def f(): # Ending comment. }) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testEndingWhitespaceAfterSimpleStatement(self): @@ -240,7 +240,7 @@ def testEndingWhitespaceAfterSimpleStatement(self): # Thing 1 # Thing 2 """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testDocstrings(self): @@ -278,7 +278,7 @@ def qux(self): print('hello {}'.format('world')) return 42 ''') - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testDocstringAndMultilineComment(self): @@ -313,7 +313,7 @@ def foo(self): # comment pass ''') - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testMultilineDocstringAndMultilineComment(self): @@ -366,7 +366,7 @@ def foo(self): # comment pass ''') - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testTupleCommaBeforeLastParen(self): @@ -376,7 +376,7 @@ def testTupleCommaBeforeLastParen(self): expected_formatted_code = textwrap.dedent("""\ a = (1,) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testNoBreakOutsideOfBracket(self): @@ -392,7 +392,7 @@ def f(): assert port >= minimum, 'Unexpected port %d when minimum was %d.' % (port, minimum) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testBlankLinesBeforeDecorators(self): @@ -413,7 +413,7 @@ class A(object): def x(self): pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testCommentBetweenDecorators(self): @@ -431,7 +431,7 @@ def x (self): def x(self): pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testListComprehension(self): @@ -444,7 +444,7 @@ def given(y): def given(y): [k for k in () if k in y] """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testOpeningAndClosingBrackets(self): @@ -457,7 +457,7 @@ def testOpeningAndClosingBrackets(self): 2, 3,)) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSingleLineFunctions(self): @@ -468,7 +468,7 @@ def foo(): return 42 def foo(): return 42 """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testNoQueueSeletionInMiddleOfLine(self): @@ -484,7 +484,7 @@ def testNoQueueSeletionInMiddleOfLine(self): find_symbol(node.type) + "< " + " ".join(find_pattern(n) for n in node.child) + " >" """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testNoSpacesBetweenSubscriptsAndCalls(self): @@ -494,7 +494,7 @@ def testNoSpacesBetweenSubscriptsAndCalls(self): expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaa = bbbbbbbb.ccccccccc()[42](a, 2) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testNoSpacesBetweenOpeningBracketAndStartingOperator(self): @@ -505,7 +505,7 @@ def testNoSpacesBetweenOpeningBracketAndStartingOperator(self): expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaa = bbbbbbbb.ccccccccc[-1](-42) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) # Varargs and kwargs. @@ -517,7 +517,7 @@ def testNoSpacesBetweenOpeningBracketAndStartingOperator(self): aaaaaaaaaa = bbbbbbbb.ccccccccc(*varargs) aaaaaaaaaa = bbbbbbbb.ccccccccc(**kwargs) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testMultilineCommentReformatted(self): @@ -533,7 +533,7 @@ def testMultilineCommentReformatted(self): # comment. pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testDictionaryMakerFormatting(self): @@ -558,7 +558,7 @@ def testDictionaryMakerFormatting(self): 'while_stmt': 'for_stmt', }) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSimpleMultilineCode(self): @@ -576,7 +576,7 @@ def testSimpleMultilineCode(self): aaaaaaaaaaaaaa.bbbbbbbbbbbbbb.ccccccc(zzzzzzzzzzzz, xxxxxxxxxxx, yyyyyyyyyyyy, vvvvvvvvv) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testMultilineComment(self): @@ -589,7 +589,7 @@ def testMultilineComment(self): # Yo man. a = 42 """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testMultilineString(self): @@ -604,7 +604,7 @@ def testMultilineString(self): a = 42 ''') """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) unformatted_code = textwrap.dedent('''\ @@ -625,7 +625,7 @@ def f(): """ ''') - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSimpleMultilineWithComments(self): @@ -637,7 +637,7 @@ def testSimpleMultilineWithComments(self): # Whoa! A normal comment!! pass # Another trailing comment """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testMatchingParenSplittingMatching(self): @@ -651,7 +651,7 @@ def f(): raise RuntimeError('unable to find insertion point for target node', (target,)) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testContinuationIndent(self): @@ -677,7 +677,7 @@ def _ProcessArgLists(self, node): subtype=_ARGLIST_TOKEN_TO_SUBTYPE.get(child.value, format_token.Subtype.NONE)) ''') - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testTrailingCommaAndBracket(self): @@ -691,20 +691,20 @@ def testTrailingCommaAndBracket(self): b = (42,) c = [42,] ''') - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testI18n(self): code = textwrap.dedent("""\ N_('Some years ago - never mind how long precisely - having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world.') # A comment is here. """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) code = textwrap.dedent("""\ foo('Fake function call') #. Some years ago - never mind how long precisely - having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testI18nCommentsInDataLiteral(self): @@ -718,7 +718,7 @@ def f(): 'snork': 'bar#.*=\\\\0', }) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testClosingBracketIndent(self): @@ -731,7 +731,7 @@ def g(): xxxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): pass ''') - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testClosingBracketsInlinedInCall(self): @@ -763,7 +763,7 @@ def bar(self): "porkporkpork": 5, }) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testLineWrapInForExpression(self): @@ -776,7 +776,7 @@ def x(self, node, name, n=1): node.pre_order())): pass """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testFunctionCallContinuationLine(self): @@ -789,7 +789,7 @@ def bar(self, node, name, n=1): return [(aaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb( cccc, ddddddddddddddddddddddddddddddddddddd))] """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testI18nNonFormatting(self): @@ -801,7 +801,7 @@ def __init__(self, fieldname, message=N_('Please check your email address.'), **kwargs): pass """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testNoSpaceBetweenUnaryOpAndOpeningParen(self): @@ -809,7 +809,7 @@ def testNoSpaceBetweenUnaryOpAndOpeningParen(self): if ~(a or b): pass """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testCommentBeforeFuncDef(self): @@ -827,7 +827,7 @@ def __init__(self, bbbbbbbbbbbbbbb=False): pass """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testExcessLineCountWithDefaultKeywords(self): @@ -852,7 +852,7 @@ def Moo(self): hhhhhhhhhhhhh=hhhhhhhhhhhhh, iiiiiii=iiiiiiiiiiiiii) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSpaceAfterNotOperator(self): @@ -860,7 +860,7 @@ def testSpaceAfterNotOperator(self): if not (this and that): pass """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testNoPenaltySplitting(self): @@ -872,7 +872,7 @@ def f(): os.path.join(filename, f) for f in os.listdir(filename) if IsPythonFile(os.path.join(filename, f))) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testExpressionPenalties(self): @@ -883,7 +883,7 @@ def f(): (left.value == '{' and right.value == '}')): return False """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testLineDepthOfSingleLineStatement(self): @@ -906,7 +906,7 @@ def testLineDepthOfSingleLineStatement(self): with open(a) as fd: a = fd.read() """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSplitListWithTerminatingComma(self): @@ -929,7 +929,7 @@ def testSplitListWithTerminatingComma(self): lambda a, b: 37, ] """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSplitListWithInterspersedComments(self): @@ -948,14 +948,14 @@ def testSplitListWithInterspersedComments(self): lambda a, b: 37 # lambda ] """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testRelativeImportStatements(self): code = textwrap.dedent("""\ from ... import bork """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testSingleLineList(self): @@ -970,7 +970,7 @@ def testSingleLineList(self): bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = aaaaaaaaaaa( ("...", "."), "..", "..............................................") """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testBlankLinesBeforeFunctionsNotInColumnZero(self): @@ -1004,7 +1004,7 @@ def timeout(seconds=1): except: pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testNoKeywordArgumentBreakage(self): @@ -1016,7 +1016,7 @@ def b(self): cccccccccccccccccccc=True): pass """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testTrailerOnSingleLine(self): @@ -1027,7 +1027,7 @@ def testTrailerOnSingleLine(self): url(r'^/login/$', 'logout_view'), url(r'^/user/(?P\\w+)/$', 'profile_view')) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testIfConditionalParens(self): @@ -1040,7 +1040,7 @@ def bar(): child.value in substatement_names): pass """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testContinuationMarkers(self): @@ -1051,14 +1051,14 @@ def testContinuationMarkers(self): "sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. "\\ "Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet" """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) code = textwrap.dedent("""\ from __future__ import nested_scopes, generators, division, absolute_import, with_statement, \\ print_function, unicode_literals """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) code = textwrap.dedent("""\ @@ -1066,7 +1066,7 @@ def testContinuationMarkers(self): cccccccc == 42: pass """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testCommentsWithContinuationMarkers(self): @@ -1077,7 +1077,7 @@ def fn(arg): key2=arg)\\ .fn3() """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testEmptyContainers(self): @@ -1087,7 +1087,7 @@ def testEmptyContainers(self): 'Lorem ipsum dolor sit amet, consetetur adipiscing elit. Donec a diam lectus. ' 'Sed sit amet ipsum mauris. Maecenas congue.') """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testSplitStringsIfSurroundedByParens(self): @@ -1103,7 +1103,7 @@ def testSplitStringsIfSurroundedByParens(self): 'cccccccccccccccccccccccccccccccc' 'ddddddddddddddddddddddddddddd') """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) code = textwrap.dedent("""\ @@ -1111,7 +1111,7 @@ def testSplitStringsIfSurroundedByParens(self): 'bbbbbbbbbbbbbbbbbbbbbbbbbb' 'cccccccccccccccccccccccccccccccc' \ 'ddddddddddddddddddddddddddddd' """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testMultilineShebang(self): @@ -1131,7 +1131,7 @@ def testMultilineShebang(self): assert os.environ['FOO'] == '123' """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testNoSplittingAroundTermOperators(self): @@ -1139,7 +1139,7 @@ def testNoSplittingAroundTermOperators(self): a_very_long_function_call_yada_yada_etc_etc_etc(long_arg1, long_arg2 / long_arg3) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testNoSplittingWithinSubscriptList(self): @@ -1149,7 +1149,7 @@ def testNoSplittingWithinSubscriptList(self): 'someotherlongkey': 2 } """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testExcessCharacters(self): @@ -1161,7 +1161,7 @@ def bar(self): '%s%s %s' % ('many of really', 'long strings', '+ just makes up 81') ]) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testDictSetGenerator(self): @@ -1171,7 +1171,7 @@ def testDictSetGenerator(self): for variable in fnord if variable != 37 } """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testUnaryOpInDictionaryValue(self): @@ -1182,7 +1182,7 @@ def testUnaryOpInDictionaryValue(self): print(beta[-1]) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testUnaryNotOperator(self): @@ -1194,7 +1194,7 @@ def testUnaryNotOperator(self): remote_checksum = self.get_checksum(conn, tmp, dest, inject, not directory_prepended, source) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testRelaxArraySubscriptAffinity(self): @@ -1210,17 +1210,17 @@ def f(self, aaaaaaaaa, bbbbbbbbbbbbb, row): bbbbbbbbbbbbb['..............'] = row[5] if row[ 5] is not None else 5 """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testFunctionCallInDict(self): code = "a = {'a': b(c=d, **e)}\n" - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testFunctionCallInNestedDict(self): code = "a = {'a': {'a': {'a': b(c=d, **e)}}}\n" - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testUnbreakableNot(self): @@ -1229,7 +1229,7 @@ def test(): if not "Foooooooooooooooooooooooooooooo" or "Foooooooooooooooooooooooooooooo" == "Foooooooooooooooooooooooooooooo": pass """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testSplitListWithComment(self): @@ -1240,7 +1240,7 @@ def testSplitListWithComment(self): 'c' # hello world ] """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testOverColumnLimit(self): @@ -1267,7 +1267,7 @@ def testSomething(self): 'ccccccccccccccccccccccccccccccccccccccccccc', } """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testEndingComment(self): @@ -1277,7 +1277,7 @@ def testEndingComment(self): b="something requiring comment which is quite long", # comment about b (pushes line over 79) c="something else, about which comment doesn't make sense") """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testContinuationSpaceRetention(self): @@ -1288,7 +1288,7 @@ def fn(): fn2(arg) )) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testIfExpressionWithFunctionCall(self): @@ -1299,7 +1299,7 @@ def testIfExpressionWithFunctionCall(self): bbbbbbbbbbbbbbbbbbbbb=bbbbbbbbbbbbbbbbbb): pass """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testUnformattedAfterMultilineString(self): @@ -1310,7 +1310,7 @@ def foo(): TEST ''' % (input_fname, output_fname) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testNoSpacesAroundKeywordDefaultValues(self): @@ -1321,7 +1321,7 @@ def testNoSpacesAroundKeywordDefaultValues(self): } json = request.get_json(silent=True) or {} """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testNoSplittingBeforeEndingSubscriptBracket(self): @@ -1336,7 +1336,7 @@ def testNoSplittingBeforeEndingSubscriptBracket(self): status = cf.describe_stacks( StackName=stackname)[u'Stacks'][0][u'StackStatus'] """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testNoSplittingOnSingleArgument(self): @@ -1358,7 +1358,7 @@ def testNoSplittingOnSingleArgument(self): re.search(r'(\\d+\\.\\d+\\.\\d+\\.)\\d+', aaaaaaa.bbbbbbbbbbbb).group(a.b) + re.search(r'\\d+\\.\\d+\\.\\d+\\.(\\d+)', ccccccc).group(c.d)) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSplittingArraysSensibly(self): @@ -1376,7 +1376,7 @@ def testSplittingArraysSensibly(self): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list( 'bbbbbbbbbbbbbbbbbbbbbbbbb').split(',') """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testComprehensionForAndIf(self): @@ -1393,7 +1393,7 @@ def __repr__(self): tokens_repr = ','.join( ['{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens]) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testFunctionCallArguments(self): @@ -1418,7 +1418,7 @@ def f(): _CreateCommentsFromPrefix( comment_prefix, comment_lineno, comment_column, standalone=True)) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testBinaryOperators(self): @@ -1430,7 +1430,7 @@ def testBinaryOperators(self): a = b**37 c = (20**-3) / (_GRID_ROWS**(code_length - 10)) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) code = textwrap.dedent("""\ @@ -1442,7 +1442,7 @@ def f(): current.value in ']}'): pass """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testContiguousList(self): @@ -1450,7 +1450,7 @@ def testContiguousList(self): [retval1, retval2] = a_very_long_function(argument_1, argument2, argument_3, argument_4) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testArgsAndKwargsFormatting(self): @@ -1461,7 +1461,7 @@ def testArgsAndKwargsFormatting(self): *d, **e) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testCommentColumnLimitOverflow(self): @@ -1474,7 +1474,7 @@ def f(): # side_effect=[(157031694470475), (157031694470475),], ) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testMultilineLambdas(self): @@ -1505,7 +1505,7 @@ def succeeded(self, dddddddddddddd): cccccccccccccccccccccccccccccccc(dddddddddddddd)) return d """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: @@ -1530,11 +1530,11 @@ def method(self): }] } """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) reformatted_code = reformatter.Reformat(uwlines) self.assertCodeEqual(code, reformatted_code) - uwlines = reformatter_test.ParseAndUnwrap(reformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(reformatted_code) reformatted_code = reformatter.Reformat(uwlines) self.assertCodeEqual(code, reformatted_code) finally: @@ -1546,7 +1546,7 @@ def mark_game_scored(gid): _connect.execute(_games.update().where(_games.c.gid == gid).values( scored=True)) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testDontAddBlankLineAfterMultilineString(self): @@ -1556,7 +1556,7 @@ def testDontAddBlankLineAfterMultilineString(self): WHERE day in {}''' days = ",".join(days) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testFormattingListComprehensions(self): @@ -1570,7 +1570,7 @@ def a(): ] self._heap = [x for x in self._heap if x.route and x.route[0] == choice] """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testNoSplittingWhenBinPacking(self): @@ -1594,11 +1594,11 @@ def testNoSplittingWhenBinPacking(self): long_argument_name_4=4 ) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) reformatted_code = reformatter.Reformat(uwlines) self.assertCodeEqual(code, reformatted_code) - uwlines = reformatter_test.ParseAndUnwrap(reformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(reformatted_code) reformatted_code = reformatter.Reformat(uwlines) self.assertCodeEqual(code, reformatted_code) finally: @@ -1615,7 +1615,7 @@ def testNotSplittingAfterSubscript(self): c == d['eeeeee']).ffffff(): pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSplittingOneArgumentList(self): @@ -1638,7 +1638,7 @@ def _(): boxes[id_] = np.concatenate( (points.min(axis=0), qoints.max(axis=0))) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSplittingBeforeFirstElementListArgument(self): @@ -1667,7 +1667,7 @@ def _pack_results_for_constraint_or(cls, combination, constraints): (clue for clue in combination if not clue == Verifier.UNMATCHED), constraints, InvestigationResult.OR) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSplittingArgumentsTerminatedByComma(self): @@ -1715,11 +1715,11 @@ def testSplittingArgumentsTerminatedByComma(self): 3, ) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) reformatted_code = reformatter.Reformat(uwlines) self.assertCodeEqual(expected_formatted_code, reformatted_code) - uwlines = reformatter_test.ParseAndUnwrap(reformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(reformatted_code) reformatted_code = reformatter.Reformat(uwlines) self.assertCodeEqual(expected_formatted_code, reformatted_code) finally: @@ -1731,7 +1731,7 @@ def testImportAsList(self): from toto import titi, tata, tutu from toto import (titi, tata, tutu) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testDictionaryValuesOnOwnLines(self): @@ -1783,7 +1783,7 @@ def testDictionaryValuesOnOwnLines(self): Check('QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ', '=', False), } """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testDictionaryOnOwnLine(self): @@ -1797,7 +1797,7 @@ def testDictionaryOnOwnLine(self): doc = test_utils.CreateTestDocumentViaController( content={'a': 'b'}, branch_key=branch.key, collection_key=collection.key) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) unformatted_code = textwrap.dedent("""\ @@ -1814,7 +1814,7 @@ def testDictionaryOnOwnLine(self): collection_key=collection.key, collection_key2=collection.key2) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testNestedListsInDictionary(self): @@ -1881,7 +1881,7 @@ def testNestedListsInDictionary(self): ), } """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testNestedDictionary(self): @@ -1914,7 +1914,7 @@ def _(): 'title': title }] """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testDictionaryElementsOnOneLine(self): @@ -1927,7 +1927,7 @@ class _(): def _(): pass """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testNotInParams(self): @@ -1938,7 +1938,7 @@ def testNotInParams(self): list("a long line to break the line. a long line to break the brk a long lin", not True) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertEqual(expected_code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 52968c245..3676fd510 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -19,10 +19,10 @@ from yapf.yapflib import reformatter from yapf.yapflib import style -from yapftests import reformatter_test +from yapftests import yapf_test_helper -class BuganizerFixes(reformatter_test.ReformatterTest): +class BuganizerFixes(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): @@ -35,7 +35,7 @@ class _(): def __init__(self, metric, fields_cb=None): self._fields_cb = fields_cb or (lambda *unused_args, **unused_kwargs: {}) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB31911533(self): @@ -50,7 +50,7 @@ class _(): def _(): pass """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB31847238(self): @@ -74,7 +74,7 @@ def xxxxx( zzzzzzzzzzzzzz=None): # A normal comment that runs over the column limit. return 1 """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB30760569(self): @@ -88,7 +88,7 @@ def testB30760569(self): '1234567890123456789012345678901234567890' } """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB26034238(self): @@ -106,7 +106,7 @@ def Function(self): '/aaaaaaaaa/bbbbbbbbbb/ccccc/dddd/eeeeeeeeeeeeee/ffffffffffffff' ).AndReturn(42) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB30536435(self): @@ -127,7 +127,7 @@ def main(unused_argv): bbbbbbbbb.usage, ccccccccc.within, imports.ddddddddddddddddddd(name_item.ffffffffffffffff))) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB30442148(self): @@ -141,7 +141,7 @@ def lulz(): return (some_long_module_name.SomeLongClassName.some_long_attribute_name. some_long_method_name()) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB26868213(self): @@ -177,7 +177,7 @@ def _(): } } """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB30173198(self): @@ -188,7 +188,7 @@ def _(): self.assertFalse( evaluation_runner.get_larps_in_eval_set('these_arent_the_larps')) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB29908765(self): @@ -199,7 +199,7 @@ def __repr__(self): return '' % (self._id, self._stub._stub.rpc_channel().target()) # pylint:disable=protected-access """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB30087362(self): @@ -212,7 +212,7 @@ def _(): # This is another comment foo() """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB29093579(self): @@ -228,7 +228,7 @@ def _(): bbbbbbbbbbbbbb.cccccccccc[dddddddddddddddddddddddddddd. eeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffff]) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB26382315(self): @@ -240,7 +240,7 @@ def testB26382315(self): def foo(): pass """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB27616132(self): @@ -266,7 +266,7 @@ def testB27616132(self): 100, start_cursor=cursor_2), ]) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB27590179(self): @@ -290,7 +290,7 @@ def testB27590179(self): self.bbb.cccccccccc(ddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee) }) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB27266946(self): @@ -304,7 +304,7 @@ def _(): self.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb. cccccccccccccccccccccccccccccccccccc) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB25505359(self): @@ -319,7 +319,7 @@ def testB25505359(self): }] } """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB25324261(self): @@ -328,7 +328,7 @@ def testB25324261(self): for ddd in eeeeee.fffffffffff.gggggggggggggggg for cccc in ddd.specification) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB25136704(self): @@ -340,7 +340,7 @@ def test(self): 'xxxxxx': 'yyyyyy' }] = cccccc.ddd('1m', '10x1+1') """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB25165602(self): @@ -348,7 +348,7 @@ def testB25165602(self): def f(): ids = {u: i for u, i in zip(self.aaaaa, xrange(42, 42 + len(self.aaaaaa)))} """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB25157123(self): @@ -357,7 +357,7 @@ def ListArgs(): FairlyLongMethodName([relatively_long_identifier_for_a_list], another_argument_with_a_long_identifier) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB25136820(self): @@ -377,7 +377,7 @@ def foo(): '$bbbbbbbbbbbbbbbbbbbbbbbb', }) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB25131481(self): @@ -397,7 +397,7 @@ def testB25131481(self): lambda x: x # do nothing }) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB23445244(self): @@ -424,7 +424,7 @@ def foo(): FLAGS.aaaaaaaaaaaaaa + FLAGS.bbbbbbbbbbbbbbbbbbb, }) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB20559654(self): @@ -445,7 +445,7 @@ def foo(self): aaaaaaaaaaa=True, bbbbbbbb=None) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB23943842(self): @@ -482,7 +482,7 @@ def f(): } }) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB20551180(self): @@ -497,7 +497,7 @@ def foo(): return ( struct.pack('aaaa', bbbbbbbbbb, ccccccccccccccc, dddddddd) + eeeeeee) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB23944849(self): @@ -517,7 +517,7 @@ def xxxxxxxxx(self, fffffffffffffff=0): pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB23935890(self): @@ -533,7 +533,7 @@ def functioni(self, aaaaaaa, bbbbbbb, cccccc, dddddddddddddd, eeeeeeeeeeeeeee): pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB28414371(self): @@ -561,7 +561,7 @@ def _(): | m.jjjj() | m.ppppp(m.vvv[0] + m.vvv[1])) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB20127686(self): @@ -579,7 +579,7 @@ def f(): | m.jjjj() | m.ppppp(m.VAL[0] / m.VAL[1])) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB20016122(self): @@ -595,7 +595,7 @@ def testB20016122(self): from a_very_long_or_indented_module_name_yada_yada import ( long_argument_1, long_argument_2) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: @@ -622,7 +622,7 @@ def __eq__(self, other): and len(self.iiiiiiii) == len(other.iiiiiiii) and all(jjjjjjj in other.iiiiiiii for jjjjjjj in self.iiiiiiii)) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) finally: style.SetGlobalStyle(style.CreateChromiumStyle()) @@ -639,7 +639,7 @@ def f(): aaaaaa.bbbbbbbbbbbbbbbbbbbb[-1].cccccccccccccc.ddd().eeeeeeee( ffffffffffffff) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB20849933(self): @@ -651,7 +651,7 @@ def main(unused_argv): '%s/cccccc/ddddddddddddddddddd.jar' % (eeeeee.FFFFFFFFFFFFFFFFFF), } """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB20813997(self): @@ -660,7 +660,7 @@ def myfunc_1(): myarray = numpy.zeros((2, 2, 2)) print(myarray[:, 1, :]) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB20605036(self): @@ -676,7 +676,7 @@ def testB20605036(self): } } """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB20562732(self): @@ -688,7 +688,7 @@ def testB20562732(self): 'Second item', ] """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB20128830(self): @@ -708,7 +708,7 @@ def testB20128830(self): }, } """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB20073838(self): @@ -725,7 +725,7 @@ def do_nothing(self, class_1_count): class_1_name=self.class_1_name, class_1_count=class_1_count)) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB19626808(self): @@ -734,7 +734,7 @@ def testB19626808(self): aaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbb( 'ccccccccccc', ddddddddd='eeeee').fffffffff([ggggggggggggggggggggg]) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB19547210(self): @@ -748,7 +748,7 @@ def testB19547210(self): xxxxxxxxxxxx.yyyyyyyyyyyyyy.zzzzzzzz): continue """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB19377034(self): @@ -758,7 +758,7 @@ def f(): bbbbbbbbbbbbbbb.start >= bbbbbbbbbbbbbbb.end): return False """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB19372573(self): @@ -770,7 +770,7 @@ def f(): if c: break return 0 """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) try: style.SetGlobalStyle(style.CreatePEP8Style()) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -782,7 +782,7 @@ def testB19353268(self): a = {1, 2, 3}[x] b = {'foo': 42, 'bar': 37}['foo'] """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB19287512(self): @@ -807,7 +807,7 @@ def bar(self): -1, 'permission error'))): self.assertRaises(nnnnnnnnnnnnnnnn.ooooo, ppppp.qqqqqqqqqqqqqqqqq) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB19194420(self): @@ -815,7 +815,7 @@ def testB19194420(self): method.Set('long argument goes here that causes the line to break', lambda arg2=0.5: arg2) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB19073499(self): @@ -828,7 +828,7 @@ def testB19073499(self): 'fnord': 6 })) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB18257115(self): @@ -838,7 +838,7 @@ def testB18257115(self): self._Test(aaaa, bbbbbbb.cccccccccc, dddddddd, eeeeeeeeeee, [ffff, ggggggggggg, hhhhhhhhhhhh, iiiiii, jjjj]) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB18256666(self): @@ -856,7 +856,7 @@ def Bar(self): }, llllllllll=mmmmmm.nnnnnnnnnnnnnnnn) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB18256826(self): @@ -875,7 +875,7 @@ def testB18256826(self): elif False: pass """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB18255697(self): @@ -886,7 +886,7 @@ def testB18255697(self): 'YYYYYYYYYYYYYYYY': ['zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'], } """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB17534869(self): @@ -900,7 +900,7 @@ def testB17534869(self): self.assertLess( abs(time.time() - aaaa.bbbbbbbbbbb(datetime.datetime.now())), 1) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB17489866(self): @@ -919,7 +919,7 @@ def f(): ('eeee', 'ffffffff'): str(j) })) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB17133019(self): @@ -944,7 +944,7 @@ def bbbbbbbbbb(self): "eeeeeeeee ffffffffff"), "rb") as gggggggggggggggggggg: print(gggggggggggggggggggg) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB17011869(self): @@ -971,7 +971,7 @@ class SomeClass(object): 'DDDDDDDD': 0.4811 } """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB16783631(self): @@ -988,7 +988,7 @@ def testB16783631(self): ddddddddddddd, eeeeeeeee=self.fffffffffffff) as gggg: pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB16572361(self): @@ -1005,7 +1005,7 @@ def bar(my_dict_name): 'foo-bar-baz-biz-boo-baa-baa'].IncrementBy.assert_called_once_with( 'foo_bar_baz_boo') """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB15884241(self): @@ -1029,7 +1029,7 @@ def testB15884241(self): ffffffff=[s.strip() for s in bbb[5].split(",")], gggggg=bbb[6]) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB15697268(self): @@ -1054,7 +1054,7 @@ def main(unused_argv): bad_slice = ("I am a crazy, no good, string whats too long, etc." + " no really ")[:ARBITRARY_CONSTANT_A] """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB15597568(self): @@ -1071,7 +1071,7 @@ def testB15597568(self): print(("Return code was %d" + (", and the process timed out." if did_time_out else ".")) % errorcode) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB15542157(self): @@ -1082,7 +1082,7 @@ def testB15542157(self): aaaaaaaaaaaa = bbbb.ccccccccccccccc(dddddd.eeeeeeeeeeeeee, ffffffffffffffffff, gggggg.hhhhhhhhhhhhhhhhh) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB15438132(self): @@ -1117,7 +1117,7 @@ def testB15438132(self): gggggg.hh, iiiiiiiiiiiiiiiiiii.jjjjjjjjjj.kkkkkkk, lllll.mm), nnnnnnnnnn=ooooooo.pppppppppp) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB14468247(self): @@ -1131,7 +1131,7 @@ def testB14468247(self): a=1, b=2,) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB14406499(self): @@ -1144,7 +1144,7 @@ def foo1(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6): pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB13900309(self): @@ -1156,7 +1156,7 @@ def testB13900309(self): self.aaaaaaaaaaa( # A comment in the middle of it all. 948.0 / 3600, self.bbb.ccccccccccccccccccccc(dddddddddddddddd.eeee, True)) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) code = textwrap.dedent("""\ @@ -1165,7 +1165,7 @@ def testB13900309(self): CCCCCCC).ddddddddd( # Look! A comment is here. AAAAAAAA - (20 * 60 - 5)) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) unformatted_code = textwrap.dedent("""\ @@ -1175,7 +1175,7 @@ def testB13900309(self): aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc( ).dddddddddddddddddddddddddd(1, 2, 3, 4) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) unformatted_code = textwrap.dedent("""\ @@ -1185,7 +1185,7 @@ def testB13900309(self): aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc( x).dddddddddddddddddddddddddd(1, 2, 3, 4) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) unformatted_code = textwrap.dedent("""\ @@ -1195,7 +1195,7 @@ def testB13900309(self): aaaaaaaaaaaaaaaaaaaaaaaa( xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx).dddddddddddddddddddddddddd(1, 2, 3, 4) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) unformatted_code = textwrap.dedent("""\ @@ -1207,7 +1207,7 @@ def testB13900309(self): ).dddddddddddddddddd().eeeeeeeeeeeeeeeeeeeee().fffffffffffffffff( ).gggggggggggggggggg() """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_facebook_test.py b/yapftests/reformatter_facebook_test.py index 5955c84b1..51801346f 100644 --- a/yapftests/reformatter_facebook_test.py +++ b/yapftests/reformatter_facebook_test.py @@ -20,10 +20,10 @@ from yapf.yapflib import style from yapf.yapflib import verifier -from yapftests import reformatter_test +from yapftests import yapf_test_helper -class TestsForFacebookStyle(reformatter_test.ReformatterTest): +class TestsForFacebookStyle(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): @@ -39,7 +39,7 @@ def overly_long_function_name( def overly_long_function_name(just_one_arg, **kwargs): pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testDedentClosingBracket(self): @@ -55,7 +55,7 @@ def overly_long_function_name( ): pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testBreakAfterOpeningBracketIfContentsTooBig(self): @@ -71,7 +71,7 @@ def overly_long_function_name( ): pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testDedentClosingBracketWithComments(self): @@ -92,7 +92,7 @@ def overly_long_function_name( ): pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testDedentImportAsNames(self): @@ -104,7 +104,7 @@ def testDedentImportAsNames(self): SOME_CONSTANT_NUMBER3, ) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testDedentTestListGexp(self): @@ -130,7 +130,7 @@ def testDedentTestListGexp(self): ) as exception: pass """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testBrokenIdempotency(self): @@ -149,7 +149,7 @@ def testBrokenIdempotency(self): ) as exception: pass """) - uwlines = reformatter_test.ParseAndUnwrap(pass0_code) + uwlines = yapf_test_helper.ParseAndUnwrap(pass0_code) self.assertCodeEqual(pass1_code, reformatter.Reformat(uwlines)) pass2_code = textwrap.dedent("""\ @@ -160,7 +160,7 @@ def testBrokenIdempotency(self): ) as exception: pass """) - uwlines = reformatter_test.ParseAndUnwrap(pass1_code) + uwlines = yapf_test_helper.ParseAndUnwrap(pass1_code) self.assertCodeEqual(pass2_code, reformatter.Reformat(uwlines)) def testIfExprHangingIndent(self): @@ -183,7 +183,7 @@ def testIfExprHangingIndent(self): ): pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSimpleDedenting(self): @@ -197,7 +197,7 @@ def testSimpleDedenting(self): result.reason_not_added, "current preflight is still running" ) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testDedentingWithSubscripts(self): @@ -220,7 +220,7 @@ def baz(cls, clues_list, effect, constraints, constraint_manager): clues_lists, effect, constraints[0], constraint_manager ) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testDedentingCallsWithInnerLists(self): @@ -231,7 +231,7 @@ def _(): 'effect': Clue((cls.effect_time, 'apache_host'), effect_line, 40) } """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testDedentingListComprehension(self): @@ -309,7 +309,7 @@ def _pack_results_for_constraint_or(): ('localhost', os.path.join(path, 'node_2.log'), super_parser) ] """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testMustSplitDedenting(self): @@ -323,7 +323,7 @@ def _(): ) ) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testDedentIfConditional(self): @@ -337,7 +337,7 @@ def _(): ): pass """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testDedentSet(self): @@ -353,7 +353,7 @@ def _(): ] ) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testDedentingInnerScope(self): @@ -366,11 +366,11 @@ def _pack_results_for_constraint_or(cls, combination, constraints): constraints, InvestigationResult.OR ) """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) reformatted_code = reformatter.Reformat(uwlines) self.assertCodeEqual(code, reformatted_code) - uwlines = reformatter_test.ParseAndUnwrap(reformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(reformatted_code) reformatted_code = reformatter.Reformat(uwlines) self.assertCodeEqual(code, reformatted_code) @@ -400,7 +400,7 @@ def foo(): print(foo()) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 169b1d48d..6f7f8548d 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -19,10 +19,10 @@ from yapf.yapflib import reformatter from yapf.yapflib import style -from yapftests import reformatter_test +from yapftests import yapf_test_helper -class TestsForPEP8Style(reformatter_test.ReformatterTest): +class TestsForPEP8Style(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): @@ -37,7 +37,7 @@ def testIndent4(self): if a + b: pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSingleLineIfStatements(self): @@ -46,7 +46,7 @@ def testSingleLineIfStatements(self): elif False: b = 42 else: c = 42 """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testNoBlankBetweenClassAndDef(self): @@ -61,7 +61,7 @@ class Foo: def joe(): pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSingleWhiteBeforeTrailingComment(self): @@ -73,7 +73,7 @@ def testSingleWhiteBeforeTrailingComment(self): if a + b: # comment pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSplittingSemicolonStatements(self): @@ -91,7 +91,7 @@ def f(): b += 1 c += 1 """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSpaceBetweenEndingCommandAndClosingBracket(self): @@ -103,7 +103,7 @@ def testSpaceBetweenEndingCommandAndClosingBracket(self): expected_formatted_code = textwrap.dedent("""\ a = [1, ] """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testContinuedNonOudentedLine(self): @@ -113,7 +113,7 @@ class eld(d): ) != self.geom_type and not self.geom_type == 'GEOMETRY': ror(code='om_type') """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testWrappingPercentExpressions(self): @@ -137,7 +137,7 @@ def f(): zzzzz = '%s-%s'.ww(xxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxxxxxx + 1) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testAlignClosingBracketWithVisualIndentation(self): @@ -153,7 +153,7 @@ def testAlignClosingBracketWithVisualIndentation(self): 'baz' # second comment ) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) unformatted_code = textwrap.dedent("""\ @@ -173,7 +173,7 @@ def g(): 'bbbbbbb'): pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testIndentSizeChanging(self): @@ -186,7 +186,7 @@ def testIndentSizeChanging(self): runtime_mins = ( program_end_time - program_start_time).total_seconds() / 60.0 """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testHangingIndentCollision(self): @@ -223,7 +223,7 @@ def h(): morestuff.andmore.andmore.andmore.andmore.andmore.andmore.andmore): dosomething(connection) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSplittingBeforeLogicalOperator(self): @@ -253,7 +253,7 @@ def foo(): or update.message.migrate_from_chat_id or update.message.pinned_message) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: @@ -271,7 +271,7 @@ def testContiguousListEndingWithComment(self): keys.append( aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) # may be unassigned. """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSplittingBeforeFirstArgument(self): @@ -290,7 +290,7 @@ def testSplittingBeforeFirstArgument(self): long_argument_name_3=3, long_argument_name_4=4) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index 78be3d050..4b3a19e9d 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -21,11 +21,11 @@ from yapf.yapflib import reformatter from yapf.yapflib import style -from yapftests import reformatter_test +from yapftests import yapf_test_helper @unittest.skipUnless(py3compat.PY3, 'Requires Python 3') -class TestsForPython3Code(reformatter_test.ReformatterTest): +class TestsForPython3Code(yapf_test_helper.YAPFTest): """Test a few constructs that are new Python 3 syntax.""" @classmethod @@ -44,7 +44,7 @@ def x(aaaaaaaaaaaaaaa: int, eeeeeeeeeeeeee: set={1, 2, 3}) -> bool: pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testKeywordOnlyArgSpecifier(self): @@ -56,7 +56,7 @@ def foo(a, *, kw): def foo(a, *, kw): return a + kw """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testAnnotations(self): @@ -68,13 +68,13 @@ def foo(a: list, b: "bar") -> dict: def foo(a: list, b: "bar") -> dict: return a + b """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testExecAsNonKeyword(self): unformatted_code = 'methods.exec( sys.modules[name])\n' expected_formatted_code = 'methods.exec(sys.modules[name])\n' - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testAsyncFunctions(self): @@ -96,7 +96,7 @@ async def main(): if (await get_html()): pass """) - uwlines = reformatter_test.ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines, verify=False)) def testNoSpacesAroundPowerOparator(self): @@ -110,7 +110,7 @@ def testNoSpacesAroundPowerOparator(self): expected_formatted_code = textwrap.dedent("""\ a ** b """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: @@ -128,7 +128,7 @@ def testSpacesAroundDefaultOrNamedAssign(self): expected_formatted_code = textwrap.dedent("""\ f(a = 5) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: @@ -159,7 +159,7 @@ async def bar(): async def foo(): pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_style_config_test.py b/yapftests/reformatter_style_config_test.py index 0186fa8db..c413129e8 100644 --- a/yapftests/reformatter_style_config_test.py +++ b/yapftests/reformatter_style_config_test.py @@ -19,10 +19,10 @@ from yapf.yapflib import reformatter from yapf.yapflib import style -from yapftests import reformatter_test +from yapftests import yapf_test_helper -class TestsForStyleConfig(reformatter_test.ReformatterTest): +class TestsForStyleConfig(yapf_test_helper.YAPFTest): def setUp(self): self.current_style = style.DEFAULT_STYLE @@ -38,7 +38,7 @@ def testSetGlobalStyle(self): for i in range(5): print('bar') """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: @@ -53,7 +53,7 @@ def testSetGlobalStyle(self): for i in range(5): print('bar') """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_verify_test.py b/yapftests/reformatter_verify_test.py index 861bcab3c..a32f6c7df 100644 --- a/yapftests/reformatter_verify_test.py +++ b/yapftests/reformatter_verify_test.py @@ -21,11 +21,11 @@ from yapf.yapflib import style from yapf.yapflib import verifier -from yapftests import reformatter_test +from yapftests import yapf_test_helper @unittest.skipIf(py3compat.PY3, 'Requires Python 2') -class TestVerifyNoVerify(reformatter_test.ReformatterTest): +class TestVerifyNoVerify(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): @@ -36,7 +36,7 @@ def testVerifyException(self): class ABC(metaclass=type): pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) with self.assertRaises(verifier.InternalError): reformatter.Reformat(uwlines, verify=True) reformatter.Reformat(uwlines) # verify should be False by default. @@ -50,7 +50,7 @@ class ABC(metaclass=type): class ABC(metaclass=type): pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual( expected_formatted_code, reformatter.Reformat( uwlines, verify=False)) @@ -65,7 +65,7 @@ def call_my_function(the_function): if __name__ == "__main__": call_my_function(print) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) with self.assertRaises(verifier.InternalError): reformatter.Reformat(uwlines, verify=True) @@ -80,7 +80,7 @@ def call_my_function(the_function): if __name__ == "__main__": call_my_function(print) """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual( expected_formatted_code, reformatter.Reformat( uwlines, verify=False)) @@ -101,7 +101,7 @@ def bar(self): self.generators + self.next_batch) == 1: pass """) - uwlines = reformatter_test.ParseAndUnwrap(unformatted_code) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual( expected_formatted_code, reformatter.Reformat( uwlines, verify=False)) diff --git a/yapftests/reformatter_test.py b/yapftests/yapf_test_helper.py similarity index 96% rename from yapftests/reformatter_test.py rename to yapftests/yapf_test_helper.py index 37fdb6fd7..313318048 100644 --- a/yapftests/reformatter_test.py +++ b/yapftests/yapf_test_helper.py @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -"""Support module for tests for yapf.reformatter.""" +"""Support module for tests for yapf.""" import difflib import sys @@ -28,7 +28,7 @@ from yapf.yapflib import subtype_assigner -class ReformatterTest(unittest.TestCase): +class YAPFTest(unittest.TestCase): def assertCodeEqual(self, expected_code, code): if code != expected_code: From bdf51cf2de7fffa48043d1a61a83592dff6ea69a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 23 Oct 2016 16:36:47 -0700 Subject: [PATCH 060/719] Clean up some imports and formatting --- yapftests/line_joiner_test.py | 3 -- yapftests/pytree_unwrapper_test.py | 67 +++++++++++++++++------------- yapftests/pytree_visitor_test.py | 6 ++- yapftests/split_penalty_test.py | 10 ++--- yapftests/subtype_assigner_test.py | 51 +++++++---------------- yapftests/unwrapped_line_test.py | 53 ++++++++--------------- 6 files changed, 80 insertions(+), 110 deletions(-) diff --git a/yapftests/line_joiner_test.py b/yapftests/line_joiner_test.py index a29e94640..c2bd496fc 100644 --- a/yapftests/line_joiner_test.py +++ b/yapftests/line_joiner_test.py @@ -16,10 +16,7 @@ import textwrap import unittest -from yapf.yapflib import comment_splicer from yapf.yapflib import line_joiner -from yapf.yapflib import pytree_unwrapper -from yapf.yapflib import pytree_utils from yapf.yapflib import style from yapftests import yapf_test_helper diff --git a/yapftests/pytree_unwrapper_test.py b/yapftests/pytree_unwrapper_test.py index ccf01cd4d..fa1f70bcf 100644 --- a/yapftests/pytree_unwrapper_test.py +++ b/yapftests/pytree_unwrapper_test.py @@ -13,14 +13,10 @@ # limitations under the License. """Tests for yapf.pytree_unwrapper.""" -import sys import textwrap import unittest -from yapf.yapflib import comment_splicer -from yapf.yapflib import pytree_unwrapper from yapf.yapflib import pytree_utils -from yapf.yapflib import pytree_visitor from yapftests import yapf_test_helper @@ -55,7 +51,8 @@ def testSimpleFileScope(self): self._CheckUnwrappedLines(uwlines, [ (0, ['x', '=', '1']), (0, ['# a comment']), - (0, ['y', '=', '2'])]) + (0, ['y', '=', '2']), + ]) def testSimpleMultilineStatement(self): code = textwrap.dedent(r""" @@ -64,7 +61,8 @@ def testSimpleMultilineStatement(self): """) uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckUnwrappedLines(uwlines, [ - (0, ['y', '=', '(', '1', '+', 'x', ')'])]) + (0, ['y', '=', '(', '1', '+', 'x', ')']), + ]) def testFileScopeWithInlineComment(self): code = textwrap.dedent(r""" @@ -74,7 +72,8 @@ def testFileScopeWithInlineComment(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckUnwrappedLines(uwlines, [ (0, ['x', '=', '1', '# a comment']), - (0, ['y', '=', '2'])]) # yapf: disable + (0, ['y', '=', '2']), + ]) def testSimpleIf(self): code = textwrap.dedent(r""" @@ -86,7 +85,8 @@ def testSimpleIf(self): self._CheckUnwrappedLines(uwlines, [ (0, ['if', 'foo', ':']), (1, ['x', '=', '1']), - (1, ['y', '=', '2'])]) # yapf: disable + (1, ['y', '=', '2']), + ]) def testSimpleIfWithComments(self): code = textwrap.dedent(r""" @@ -100,7 +100,8 @@ def testSimpleIfWithComments(self): (0, ['# c1']), (0, ['if', 'foo', ':', '# c2']), (1, ['x', '=', '1']), - (1, ['y', '=', '2'])]) # yapf: disable + (1, ['y', '=', '2']), + ]) def testIfWithCommentsInside(self): code = textwrap.dedent(r""" @@ -116,7 +117,8 @@ def testIfWithCommentsInside(self): (1, ['# c1']), (1, ['x', '=', '1', '# c2']), (1, ['# c3']), - (1, ['y', '=', '2'])]) # yapf: disable + (1, ['y', '=', '2']), + ]) def testIfElifElse(self): code = textwrap.dedent(r""" @@ -136,7 +138,8 @@ def testIfElifElse(self): (1, ['y', '=', '1']), (0, ['else', ':']), (1, ['# c3']), - (1, ['z', '=', '1'])]) # yapf: disable + (1, ['z', '=', '1']), + ]) def testNestedCompoundTwoLevel(self): code = textwrap.dedent(r""" @@ -154,7 +157,8 @@ def testNestedCompoundTwoLevel(self): (1, ['while', 't', ':']), (2, ['# c2']), (2, ['j', '=', '1']), - (1, ['k', '=', '1'])]) # yapf: disable + (1, ['k', '=', '1']), + ]) def testSimpleWhile(self): code = textwrap.dedent(r""" @@ -166,7 +170,8 @@ def testSimpleWhile(self): self._CheckUnwrappedLines(uwlines, [ (0, ['while', 'x', '>', '1', ':', '# c1']), (1, ['# c2']), - (1, ['x', '=', '1'])]) # yapf: disable + (1, ['x', '=', '1']), + ]) def testSimpleTry(self): code = textwrap.dedent(r""" @@ -192,7 +197,8 @@ def testSimpleTry(self): (0, ['else', ':']), (1, ['pass']), (0, ['finally', ':']), - (1, ['pass'])]) # yapf: disable + (1, ['pass']), + ]) def testSimpleFuncdef(self): code = textwrap.dedent(r""" @@ -204,7 +210,8 @@ def foo(x): # c1 self._CheckUnwrappedLines(uwlines, [ (0, ['def', 'foo', '(', 'x', ')', ':', '# c1']), (1, ['# c2']), - (1, ['return', 'x'])]) # yapf: disable + (1, ['return', 'x']), + ]) def testTwoFuncDefs(self): code = textwrap.dedent(r""" @@ -223,7 +230,8 @@ def bar(): # c3 (1, ['return', 'x']), (0, ['def', 'bar', '(', ')', ':', '# c3']), (1, ['# c4']), - (1, ['return', 'x'])]) # yapf: disable + (1, ['return', 'x']), + ]) def testSimpleClassDef(self): code = textwrap.dedent(r""" @@ -235,7 +243,8 @@ class Klass: # c1 self._CheckUnwrappedLines(uwlines, [ (0, ['class', 'Klass', ':', '# c1']), (1, ['# c2']), - (1, ['p', '=', '1'])]) # yapf: disable + (1, ['p', '=', '1']), + ]) def testSingleLineStmtInFunc(self): code = textwrap.dedent(r""" @@ -244,7 +253,8 @@ def f(): return 37 uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckUnwrappedLines(uwlines, [ (0, ['def', 'f', '(', ')', ':']), - (1, ['return', '37'])]) # yapf: disable + (1, ['return', '37']), + ]) def testMultipleComments(self): code = textwrap.dedent(r""" @@ -259,7 +269,8 @@ def f(): (0, ['# Comment #1']), (0, ['# Comment #2']), (0, ['def', 'f', '(', ')', ':']), - (1, ['pass'])]) # yapf: disable + (1, ['pass']), + ]) def testSplitListWithComment(self): code = textwrap.dedent(r""" @@ -270,9 +281,9 @@ def testSplitListWithComment(self): ] """) uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckUnwrappedLines(uwlines, [ - (0, ['a', '=', '[', "'a'", ',', "'b'", ',', - "'c'", ',', '# hello world', ']'])]) # yapf: disable + self._CheckUnwrappedLines(uwlines, [(0, [ + 'a', '=', '[', "'a'", ',', "'b'", ',', "'c'", ',', '# hello world', ']' + ])]) class MatchBracketsTest(yapf_test_helper.YAPFTest): @@ -311,8 +322,8 @@ def foo(a, b={'hello': ['w','d']}, c=[42, 37]): uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckMatchingBrackets(uwlines, [ [(2, 24), (7, 15), (10, 14), (19, 23)], - [] - ]) # yapf: disable + [], + ]) def testDecorator(self): code = textwrap.dedent("""\ @@ -324,8 +335,8 @@ def foo(a, b, c): self._CheckMatchingBrackets(uwlines, [ [(2, 3)], [(2, 8)], - [] - ]) # yapf: disable + [], + ]) def testClassDef(self): code = textwrap.dedent("""\ @@ -335,8 +346,8 @@ class A(B, C, D): uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckMatchingBrackets(uwlines, [ [(2, 8)], - [] - ]) # yapf: disable + [], + ]) if __name__ == '__main__': diff --git a/yapftests/pytree_visitor_test.py b/yapftests/pytree_visitor_test.py index 910901057..057748311 100644 --- a/yapftests/pytree_visitor_test.py +++ b/yapftests/pytree_visitor_test.py @@ -68,7 +68,8 @@ def testCollectAllNodeNamesSimpleCode(self): 'file_input', 'simple_stmt', 'expr_stmt', 'NAME', 'EQUAL', 'NAME', 'NEWLINE', 'simple_stmt', 'expr_stmt', 'NAME', 'EQUAL', 'NAME', 'NEWLINE', - 'ENDMARKER'] # yapf: disable + 'ENDMARKER', + ] # yapf: disable self.assertEqual(expected_names, collector.all_node_names) expected_name_node_values = ['foo', 'bar', 'baz', 'x'] @@ -84,7 +85,8 @@ def testCollectAllNodeNamesNestedCode(self): 'suite', 'NEWLINE', 'INDENT', 'if_stmt', 'NAME', 'NAME', 'COLON', 'suite', 'NEWLINE', 'INDENT', 'simple_stmt', 'return_stmt', 'NAME', 'NAME', 'NEWLINE', - 'DEDENT', 'DEDENT', 'ENDMARKER'] # yapf: disable + 'DEDENT', 'DEDENT', 'ENDMARKER', + ] # yapf: disable self.assertEqual(expected_names, collector.all_node_names) expected_name_node_values = ['if', 'x', 'if', 'y', 'return', 'z'] diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index 6bc80e015..7aa1b292c 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -86,7 +86,7 @@ def foo(x): (')', STRONGLY_CONNECTED), (':', UNBREAKABLE), ('pass', None), - ]) # yapf: disable + ]) # Test function definition with trailing comment. code = textwrap.dedent(r""" @@ -102,7 +102,7 @@ def foo(x): # trailing comment (')', STRONGLY_CONNECTED), (':', UNBREAKABLE), ('pass', None), - ]) # yapf: disable + ]) # Test class definitions. code = textwrap.dedent(r""" @@ -124,7 +124,7 @@ class B(A): (')', None), (':', UNBREAKABLE), ('pass', None), - ]) # yapf: disable + ]) # Test lambda definitions. code = textwrap.dedent(r""" @@ -138,7 +138,7 @@ class B(A): ('b', UNBREAKABLE), (':', UNBREAKABLE), ('None', UNBREAKABLE), - ]) # yapf: disable + ]) # Test dotted names. code = textwrap.dedent(r""" @@ -152,7 +152,7 @@ class B(A): ('b', UNBREAKABLE), ('.', UNBREAKABLE), ('c', UNBREAKABLE), - ]) # yapf: disable + ]) def testStronglyConnected(self): # Test dictionary keys. diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index 9fe5cf8e1..75c907c8e 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -13,39 +13,16 @@ # limitations under the License. """Tests for yapf.subtype_assigner.""" -import sys import textwrap import unittest from yapf.yapflib import format_token -from yapf.yapflib import pytree_unwrapper from yapf.yapflib import pytree_utils -from yapf.yapflib import pytree_visitor -from yapf.yapflib import subtype_assigner +from yapftests import yapf_test_helper -class SubtypeAssignerTest(unittest.TestCase): - def _ParseAndUnwrap(self, code, dumptree=False): - """Produces unwrapped lines from the given code. - - Parses the code into a tree, assigns subtypes and runs the unwrapper. - - Arguments: - code: code to parse as a string - dumptree: if True, the parsed pytree (after comment splicing) is dumped - to stderr. Useful for debugging. - - Returns: - List of unwrapped lines. - """ - tree = pytree_utils.ParseCodeToTree(code) - subtype_assigner.AssignSubtypes(tree) - - if dumptree: - pytree_visitor.DumpPyTree(tree, target_stream=sys.stderr) - - return pytree_unwrapper.UnwrapPyTree(tree) +class SubtypeAssignerTest(yapf_test_helper.YAPFTest): def _CheckFormatTokenSubtypes(self, uwlines, list_of_expected): """Check that the tokens in the UnwrappedLines have the expected subtypes. @@ -69,7 +46,7 @@ def testFuncDefDefaultAssign(self): def foo(a=37, *b, **c): return -x[:42] """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [('def', [format_token.Subtype.NONE]), ('foo', {format_token.Subtype.FUNC_DEF}), @@ -98,14 +75,14 @@ def foo(a=37, *b, **c): ('[', {format_token.Subtype.SUBSCRIPT_BRACKET}), (':', {format_token.Subtype.SUBSCRIPT_COLON}), ('42', [format_token.Subtype.NONE]), - (']', {format_token.Subtype.SUBSCRIPT_BRACKET})] + (']', {format_token.Subtype.SUBSCRIPT_BRACKET})], ]) # yapf: disable def testFuncCallWithDefaultAssign(self): code = textwrap.dedent(r""" foo(x, a='hello world') """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [('foo', [format_token.Subtype.NONE]), ('(', [format_token.Subtype.NONE]), @@ -116,7 +93,7 @@ def testFuncCallWithDefaultAssign(self): format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST}), ('=', {format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN}), ("'hello world'", {format_token.Subtype.NONE}), - (')', [format_token.Subtype.NONE])] + (')', [format_token.Subtype.NONE])], ]) # yapf: disable def testSetComprehension(self): @@ -124,7 +101,7 @@ def testSetComprehension(self): def foo(strs): return {s.lower() for s in strs} """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [('def', [format_token.Subtype.NONE]), ('foo', {format_token.Subtype.FUNC_DEF}), @@ -151,7 +128,7 @@ def testUnaryNotOperator(self): code = textwrap.dedent("""\ not a """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [('not', {format_token.Subtype.UNARY_OPERATOR}), ('a', [format_token.Subtype.NONE])] @@ -161,7 +138,7 @@ def testBitwiseOperators(self): code = textwrap.dedent("""\ x = ((a | (b ^ 3) & c) << 3) >> 1 """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [('x', [format_token.Subtype.NONE]), ('=', {format_token.Subtype.ASSIGN_OPERATOR}), @@ -181,14 +158,14 @@ def testBitwiseOperators(self): ('3', [format_token.Subtype.NONE]), (')', [format_token.Subtype.NONE]), ('>>', {format_token.Subtype.BINARY_OPERATOR}), - ('1', [format_token.Subtype.NONE])] + ('1', [format_token.Subtype.NONE])], ]) # yapf: disable def testSubscriptColon(self): code = textwrap.dedent("""\ x[0:42:1] """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [('x', [format_token.Subtype.NONE]), ('[', {format_token.Subtype.SUBSCRIPT_BRACKET}), @@ -197,14 +174,14 @@ def testSubscriptColon(self): ('42', [format_token.Subtype.NONE]), (':', {format_token.Subtype.SUBSCRIPT_COLON}), ('1', [format_token.Subtype.NONE]), - (']', {format_token.Subtype.SUBSCRIPT_BRACKET})] - ]) # yapf: disable + (']', {format_token.Subtype.SUBSCRIPT_BRACKET})], + ]) def testFunctionCallWithStarExpression(self): code = textwrap.dedent("""\ [a, *b] """) - uwlines = self._ParseAndUnwrap(code) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [('[', [format_token.Subtype.NONE]), ('a', [format_token.Subtype.NONE]), diff --git a/yapftests/unwrapped_line_test.py b/yapftests/unwrapped_line_test.py index c9632f8f9..03581d56e 100644 --- a/yapftests/unwrapped_line_test.py +++ b/yapftests/unwrapped_line_test.py @@ -19,24 +19,11 @@ from lib2to3 import pytree from lib2to3.pgen2 import token -from yapf.yapflib import comment_splicer from yapf.yapflib import format_token -from yapf.yapflib import pytree_unwrapper -from yapf.yapflib import pytree_utils from yapf.yapflib import split_penalty -from yapf.yapflib import subtype_assigner from yapf.yapflib import unwrapped_line - -def _MakeFormatTokenLeaf(token_type, token_value): - return format_token.FormatToken(pytree.Leaf(token_type, token_value)) - - -def _MakeFormatTokenList(token_type_values): - return [ - _MakeFormatTokenLeaf(token_type, token_value) - for token_type, token_value in token_type_values - ] +from yapftests import yapf_test_helper class UnwrappedLineBasicTest(unittest.TestCase): @@ -74,29 +61,14 @@ def testAppendNode(self): self.assertEqual(['LPAR', 'RPAR'], [tok.name for tok in uwl.tokens]) -class UnwrappedLineFormattingInformationTest(unittest.TestCase): - - def _ParseAndUnwrap(self, code): - tree = pytree_utils.ParseCodeToTree(code) - comment_splicer.SpliceComments(tree) - subtype_assigner.AssignSubtypes(tree) - split_penalty.ComputeSplitPenalties(tree) - - uwlines = pytree_unwrapper.UnwrapPyTree(tree) - for i, uwline in enumerate(uwlines): - uwlines[i] = unwrapped_line.UnwrappedLine(uwline.depth, [ - ft for ft in uwline.tokens - if ft.name not in pytree_utils.NONSEMANTIC_TOKENS - ]) - return uwlines +class UnwrappedLineFormattingInformationTest(yapf_test_helper.YAPFTest): def testFuncDef(self): - code = textwrap.dedent(r''' - def f(a, b): - pass - ''') - uwlines = self._ParseAndUnwrap(code) - uwlines[0].CalculateFormattingInformation() + code = textwrap.dedent(r""" + def f(a, b): + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) f = uwlines[0].tokens[1] self.assertFalse(f.can_break_before) @@ -109,5 +81,16 @@ def f(a, b): self.assertEqual(lparen.split_penalty, split_penalty.UNBREAKABLE) +def _MakeFormatTokenLeaf(token_type, token_value): + return format_token.FormatToken(pytree.Leaf(token_type, token_value)) + + +def _MakeFormatTokenList(token_type_values): + return [ + _MakeFormatTokenLeaf(token_type, token_value) + for token_type, token_value in token_type_values + ] + + if __name__ == '__main__': unittest.main() From 22f742239f7e84b2b2441d98bbf25ee227d725a2 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 2 Nov 2016 01:07:39 -0700 Subject: [PATCH 061/719] Specify a "comp_op" as a binary operator. --- CHANGELOG | 4 ++++ yapf/yapflib/subtype_assigner.py | 7 +++++-- yapftests/reformatter_buganizer_test.py | 11 +++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c1f63c54b..3249efb7d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.13.3] UNRELEASED +### Fixed +- "not in" and "is not" should be subtyped as binary operators. + ## [0.13.2] 2016-10-22 ### Fixed - REGRESSION: A comment may have a prefix with newlines in it. When calculating diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index a0af020f0..e0df517d2 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -132,9 +132,12 @@ def Visit_comparison(self, node): # pylint: disable=invalid-name for child in node.children: self.Visit(child) if (isinstance(child, pytree.Leaf) and child.value in { - '<', '>', '==', '>=', '<=', '<>', '!=', 'in', 'not in', 'is', 'is not' - }): + '<', '>', '==', '>=', '<=', '<>', '!=', 'in', 'is' + }): _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + elif pytree_utils.NodeName(child) == 'comp_op': + for grandchild in child.children: + _AppendTokenSubtype(grandchild, format_token.Subtype.BINARY_OPERATOR) def Visit_star_expr(self, node): # pylint: disable=invalid-name # star_expr ::= '*' expr diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 3676fd510..fcf2be9b3 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,17 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB32570937(self): + code = textwrap.dedent("""\ + def _(): + if (job_message.ball not in ('*', ball) or + job_message.call not in ('*', call) or + job_message.mall not in ('*', job_name)): + return False + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB31937033(self): code = textwrap.dedent("""\ class _(): From 8d380d0d81e1cab99d9325d05ba433f580b953fa Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 8 Nov 2016 16:26:21 -0800 Subject: [PATCH 062/719] Encompass the dictionary value in pseudo parens If a dictionary's value has a comment before it, then we want to include the value within the pseudo parens. Otherwise only the comment is seen as being part of the dictionary's value. --- CHANGELOG | 3 +++ yapf/yapflib/comment_splicer.py | 21 +++++++++++---------- yapf/yapflib/subtype_assigner.py | 12 ++++++++++++ yapftests/reformatter_buganizer_test.py | 17 +++++++++++++++++ 4 files changed, 43 insertions(+), 10 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 3249efb7d..57672605b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,9 @@ ## [0.13.3] UNRELEASED ### Fixed - "not in" and "is not" should be subtyped as binary operators. +- A non-Node dictionary value may have a comment before it. In those cases, we + want to avoid encompassing only the comment in pseudo parens. So we include + the actual value as well. ## [0.13.2] 2016-10-22 ### Fixed diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index 4cf70be63..b51d5bf68 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -176,16 +176,17 @@ def _VisitNodeRec(node): if comment_lineno == prev_leaf[0].lineno: comment_lines = comment_prefix.splitlines() value = comment_lines[0].lstrip() - comment_column = prev_leaf[0].column + len(prev_leaf[0].value) - comment_column += ( - len(comment_lines[0]) - len(comment_lines[0].lstrip())) - comment_leaf = pytree.Leaf( - type=token.COMMENT, - value=value.rstrip('\n'), - context=('', (comment_lineno, comment_column))) - pytree_utils.InsertNodesAfter([comment_leaf], prev_leaf[0]) - comment_prefix = '\n'.join(comment_lines[1:]) - comment_lineno += 1 + if value.rstrip('\n'): + comment_column = prev_leaf[0].column + len(prev_leaf[0].value) + comment_column += ( + len(comment_lines[0]) - len(comment_lines[0].lstrip())) + comment_leaf = pytree.Leaf( + type=token.COMMENT, + value=value.rstrip('\n'), + context=('', (comment_lineno, comment_column))) + pytree_utils.InsertNodesAfter([comment_leaf], prev_leaf[0]) + comment_prefix = '\n'.join(comment_lines[1:]) + comment_lineno += 1 rindex = (0 if '\n' not in comment_prefix.rstrip() else comment_prefix.rstrip().rindex('\n') + 1) diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index e0df517d2..23230e9a0 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -347,6 +347,18 @@ def _InsertPseudoParentheses(node): first = _GetFirstLeafNode(node) last = _GetLastLeafNode(node) + if first == last and first.type == token.COMMENT: + # A comment was inserted before the value, which is a pytree.Leaf. + # Encompass the dictionary's value into an ATOM node. + last = first.next_sibling + new_node = pytree.Node(syms.atom, [first.clone(), last.clone()]) + node.replace(new_node) + node = new_node + last.remove() + + first = _GetFirstLeafNode(node) + last = _GetLastLeafNode(node) + lparen = pytree.Leaf( token.LPAR, u'(', context=('', (first.get_lineno(), first.column - 1))) last_lineno = last.get_lineno() diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index fcf2be9b3..71731543b 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,23 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB32737279(self): + unformatted_code = textwrap.dedent("""\ + here_is_a_dict = { + 'key': + # Comment. + 'value' + } + """) + expected_formatted_code = textwrap.dedent("""\ + here_is_a_dict = { + 'key': # Comment. + 'value' + } + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB32570937(self): code = textwrap.dedent("""\ def _(): From f2272acf00af2002f1947e4db2d7b3ba5715dd22 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 16 Nov 2016 17:52:50 -0800 Subject: [PATCH 063/719] Pseudo-parentheses have no length. --- CHANGELOG | 2 ++ yapf/yapflib/format_decision_state.py | 5 ++++- yapf/yapflib/unwrapped_line.py | 4 ++-- yapftests/reformatter_basic_test.py | 14 ++++++++------ yapftests/reformatter_buganizer_test.py | 4 ++-- yapftests/style_test.py | 22 ++++++++++++++++++---- 6 files changed, 36 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 57672605b..59ac70437 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,8 @@ - A non-Node dictionary value may have a comment before it. In those cases, we want to avoid encompassing only the comment in pseudo parens. So we include the actual value as well. +- Adjust calculation so that pseudo-parentheses don't count towards the total + line length. ## [0.13.2] 2016-10-22 ### Fixed diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 3494b3e62..d98fcf3c6 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -547,9 +547,12 @@ def _EachDictEntryFitsOnOneLine(self, opening): current = current.matching_bracket else: current = current.next_token + # At this point, current is the closing bracket. Go back one to get the the + # end of the dictionary entry. + current = current.previous_token length = current.total_length - entry_start.total_length length += len(entry_start.value) - return length + self.stack[-2].indent + 2 < self.column_limit + return length + self.stack[-2].indent <= self.column_limit def _IsFunctionCallWithArguments(token): diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 25892db28..0f419d1a5 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -72,8 +72,8 @@ def CalculateFormattingInformation(self): _SpaceRequiredBetween(prev_token, token)): token.spaces_required_before = 1 - token.total_length = ( - prev_length + len(token.value) + token.spaces_required_before) + tok_len = len(token.value) if not token.is_pseudo_paren else 0 + token.total_length = prev_length + tok_len + token.spaces_required_before # The split penalty has to be computed before {must|can}_break_before, # because these may use it for their decision. diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 06048bec7..984823382 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1907,12 +1907,7 @@ def _(): 'title': title }, ] - breadcrumbs = [{ - 'name': 'Admin', - 'url': url_for(".home") - }, { - 'title': title - }] + breadcrumbs = [{'name': 'Admin', 'url': url_for(".home")}, {'title': title}] """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1926,6 +1921,13 @@ class _(): {'HTTP_' + xsrf._XSRF_TOKEN_HEADER.replace('-', '_'): 'atoken'}) def _(): pass + + + AAAAAAAAAAAAAAAAAAAAAAAA = { + Environment.XXXXXXXXXX: 'some text more text even more tex', + Environment.YYYYYYY: 'some text more text even more text yet ag', + Environment.ZZZZZZZZZZZ: 'some text more text even mor etext yet again tex', + } """) uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 71731543b..4028c94da 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -675,8 +675,8 @@ def testB20849933(self): def main(unused_argv): if True: aaaaaaaa = { - 'xxx': - '%s/cccccc/ddddddddddddddddddd.jar' % (eeeeee.FFFFFFFFFFFFFFFFFF), + 'xxx': '%s/cccccc/ddddddddddddddddddd.jar' % + (eeeeee.FFFFFFFFFFFFFFFFFF), } """) uwlines = yapf_test_helper.ParseAndUnwrap(code) diff --git a/yapftests/style_test.py b/yapftests/style_test.py index c8ba03bc7..84567275b 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -60,20 +60,29 @@ def _LooksLikeFacebookStyle(cfg): class PredefinedStylesByNameTest(unittest.TestCase): + @classmethod + def setUpClass(cls): + style.SetGlobalStyle(style.CreatePEP8Style()) + def testDefault(self): # default is PEP8 cfg = style.CreateStyleFromConfig(None) self.assertTrue(_LooksLikePEP8Style(cfg)) + def testPEP8ByName(self): + for pep8_name in ('PEP8', 'pep8', 'Pep8'): + cfg = style.CreateStyleFromConfig(pep8_name) + self.assertTrue(_LooksLikePEP8Style(cfg)) + def testGoogleByName(self): for google_name in ('google', 'Google', 'GOOGLE'): cfg = style.CreateStyleFromConfig(google_name) self.assertTrue(_LooksLikeGoogleStyle(cfg)) - def testPEP8ByName(self): - for pep8_name in ('PEP8', 'pep8', 'Pep8'): - cfg = style.CreateStyleFromConfig(pep8_name) - self.assertTrue(_LooksLikePEP8Style(cfg)) + def testChromiumByName(self): + for chromium_name in ('chromium', 'Chromium', 'CHROMIUM'): + cfg = style.CreateStyleFromConfig(chromium_name) + self.assertTrue(_LooksLikeChromiumStyle(cfg)) def testFacebookByName(self): for fb_name in ('facebook', 'FACEBOOK', 'Facebook'): @@ -94,6 +103,7 @@ class StyleFromFileTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.test_tmpdir = tempfile.mkdtemp() + style.SetGlobalStyle(style.CreatePEP8Style()) @classmethod def tearDownClass(cls): @@ -206,6 +216,10 @@ def testErrorUnknownStyleOption(self): class StyleFromCommandLine(unittest.TestCase): + @classmethod + def setUpClass(cls): + style.SetGlobalStyle(style.CreatePEP8Style()) + def testDefaultBasedOnStyle(self): cfg = style.CreateStyleFromConfig( '{based_on_style: pep8,' From 605be656fca15f4cb2e06d22dbf5268a4e48c440 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 20 Nov 2016 23:52:52 -0800 Subject: [PATCH 064/719] A dictionary entry doesn't count Ignore dictionary entries in dictionaries when determining if each dictionary entry can fit on single lines. If one can't, it looks better not to split because the dictionary entry would split nicely anyway. --- CHANGELOG | 2 ++ yapf/yapflib/format_decision_state.py | 19 +++++++++++++++- yapftests/reformatter_buganizer_test.py | 30 +++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 59ac70437..222e2d538 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,8 @@ the actual value as well. - Adjust calculation so that pseudo-parentheses don't count towards the total line length. +- Don't count a dictionary entry as not fitting on a single line in a + dictionary. ## [0.13.2] 2016-10-22 ### Fixed diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index d98fcf3c6..a785ba290 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -536,6 +536,7 @@ def _EachDictEntryFitsOnOneLine(self, opening): closing = opening.matching_bracket entry_start = opening.next_token current = opening.next_token.next_token + while current and current != closing: if format_token.Subtype.DICTIONARY_KEY in current.subtypes: length = current.previous_token.total_length - entry_start.total_length @@ -544,9 +545,25 @@ def _EachDictEntryFitsOnOneLine(self, opening): return False entry_start = current if current.OpensScope(): - current = current.matching_bracket + if ((current.value == '{' or + (current.is_pseudo_paren and current.next_token.value == '{')) and + format_token.Subtype.DICTIONARY_VALUE in current.subtypes): + # A dictionary entry that cannot fit on a single line shouldn't matter + # to this calcuation. If it can't fit on a single line, then the + # opening should be on the same line as the key and the rest on + # newlines after it. But the other entries should be on single lines + # if possible. + while current: + if current == closing: + return True + if format_token.Subtype.DICTIONARY_KEY in current.subtypes: + break + current = current.next_token + else: + current = current.matching_bracket else: current = current.next_token + # At this point, current is the closing bracket. Go back one to get the the # end of the dictionary entry. current = current.previous_token diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 4028c94da..4d4e29ccb 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,36 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB32714745(self): + code = textwrap.dedent("""\ + class _(): + + def _BlankDefinition(): + '''Return a generic blank dictionary for a new field.''' + return { + 'type': '', + 'validation': '', + 'name': 'fieldname', + 'label': 'Field Label', + 'help': '', + 'initial': '', + 'required': False, + 'required_msg': 'Required', + 'invalid_msg': 'Please enter a valid value', + 'options': { + 'regex': '', + 'widget_attr': '', + 'choices_checked': '', + 'choices_count': '', + 'choices': {} + }, + 'isnew': True, + 'dirty': False, + } + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB32737279(self): unformatted_code = textwrap.dedent("""\ here_is_a_dict = { From 83a831593e6f76c2c58ed21125131a7205e696d1 Mon Sep 17 00:00:00 2001 From: Diogo de Campos Date: Thu, 6 Oct 2016 14:04:38 +0200 Subject: [PATCH 065/719] Using concurrent.futures to format multiple files at the same time --- CHANGELOG | 4 ++- README.rst | 10 +++++- yapf/__init__.py | 83 +++++++++++++++++++++++++++++++++++------------- 3 files changed, 73 insertions(+), 24 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 222e2d538..1a9b7b3ea 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,9 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.13.3] UNRELEASED +## [0.14.0] UNRELEASED +#### Added +- formatting can be run in parallel using the "-p" / "--parallel" flags. ### Fixed - "not in" and "is not" should be subtyped as binary operators. - A non-Node dictionary value may have a comment before it. In those cases, we diff --git a/README.rst b/README.rst index 8a80a7860..81fffadd4 100644 --- a/README.rst +++ b/README.rst @@ -53,6 +53,12 @@ To install YAPF from PyPI: $ pip install yapf +(optional) If you are using Python 2.7 and want to enable multiprocessing: + +.. code-block:: + + $ pip install futures + YAPF is still considered in "alpha" stage, and the released version may change often; therefore, the best way to keep up-to-date with the latest development is to clone this repository. @@ -83,7 +89,7 @@ Usage Options:: usage: yapf [-h] [-v] [-d | -i] [-r | -l START-END] [-e PATTERN] - [--style STYLE] [--style-help] [--no-local-style] + [--style STYLE] [--style-help] [--no-local-style] [-p] [files [files ...]] Formatter for Python code. @@ -109,6 +115,8 @@ Options:: directory for stdin) --style-help show style settings and exit --no-local-style don't search for local style definition (.style.yapf) + -p, --parallel Run yapf in parallel when formatting multiple files. + Requires concurrent.futures in Python 2.X Formatting style diff --git a/yapf/__init__.py b/yapf/__init__.py index 22a5ceea8..dc0bc1bda 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -113,6 +113,12 @@ def main(argv): action='store_true', help="don't search for local style definition") parser.add_argument('--verify', action='store_true', help=argparse.SUPPRESS) + parser.add_argument( + '-p', + '--parallel', + action='store_true', + help=('Run yapf in parallel when formatting multiple files. Requires ' + 'concurrent.futures in Python 2.X')) parser.add_argument('files', nargs='*') args = parser.parse_args(argv[1:]) @@ -178,7 +184,8 @@ def main(argv): no_local_style=args.no_local_style, in_place=args.in_place, print_diff=args.diff, - verify=args.verify) + verify=args.verify, + parallel=args.parallel) return 0 @@ -188,7 +195,8 @@ def FormatFiles(filenames, no_local_style=False, in_place=False, print_diff=False, - verify=True): + verify=True, + parallel=False): """Format a list of files. Arguments: @@ -204,27 +212,58 @@ def FormatFiles(filenames, print_diff: (bool) Instead of returning the reformatted source, return a diff that turns the formatted source into reformatter source. verify: (bool) True if reformatted code should be verified for syntax. + parallel: (bool) True if should format multiple files in parallel. + + Returns: + True if the source code changed in any of the files being formatted. """ - for filename in filenames: - logging.info('Reformatting %s', filename) - if style_config is None and not no_local_style: - style_config = ( - file_resources.GetDefaultStyleForDir(os.path.dirname(filename))) - try: - reformatted_code, encoding, _ = yapf_api.FormatFile( - filename, - in_place=in_place, - style_config=style_config, - lines=lines, - print_diff=print_diff, - verify=verify, - logger=logging.warning) - if not in_place and reformatted_code: - file_resources.WriteReformattedCode(filename, reformatted_code, - in_place, encoding) - except SyntaxError as e: - e.filename = filename - raise + changed = False + if parallel: + import multiprocessing + import concurrent.futures + workers = min(multiprocessing.cpu_count(), len(filenames)) + with concurrent.futures.ProcessPoolExecutor(workers) as executor: + future_formats = [ + executor.submit(_FormatFile, filename, lines, style_config, + no_local_style, in_place, print_diff, verify) + for filename in filenames + ] + for future in concurrent.futures.as_completed(future_formats): + changed |= future.result() + else: + for filename in filenames: + changed |= _FormatFile(filename, lines, style_config, no_local_style, + in_place, print_diff, verify) + return changed + + +def _FormatFile(filename, + lines, + style_config=None, + no_local_style=False, + in_place=False, + print_diff=False, + verify=True): + logging.info('Reformatting %s', filename) + if style_config is None and not no_local_style: + style_config = ( + file_resources.GetDefaultStyleForDir(os.path.dirname(filename))) + try: + reformatted_code, encoding, has_change = yapf_api.FormatFile( + filename, + in_place=in_place, + style_config=style_config, + lines=lines, + print_diff=print_diff, + verify=verify, + logger=logging.warning) + if not in_place and reformatted_code: + file_resources.WriteReformattedCode(filename, reformatted_code, in_place, + encoding) + return has_change + except SyntaxError as e: + e.filename = filename + raise def _GetLines(line_strings): From 20409b1ad751b8202d1daa4b409e8748bfb3ce71 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 21 Nov 2016 00:41:07 -0800 Subject: [PATCH 066/719] Fix lint warnings. --- yapf/yapflib/comment_splicer.py | 3 ++- yapf/yapflib/subtype_assigner.py | 2 +- yapftests/reformatter_basic_test.py | 4 +--- yapftests/reformatter_buganizer_test.py | 4 ++-- yapftests/reformatter_facebook_test.py | 3 +-- yapftests/reformatter_pep8_test.py | 2 +- yapftests/reformatter_python3_test.py | 2 +- yapftests/reformatter_style_config_test.py | 2 +- yapftests/reformatter_verify_test.py | 2 +- yapftests/yapf_test_helper.py | 2 +- 10 files changed, 12 insertions(+), 14 deletions(-) diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index b51d5bf68..822e28b41 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -177,7 +177,8 @@ def _VisitNodeRec(node): comment_lines = comment_prefix.splitlines() value = comment_lines[0].lstrip() if value.rstrip('\n'): - comment_column = prev_leaf[0].column + len(prev_leaf[0].value) + comment_column = prev_leaf[0].column + comment_column += len(prev_leaf[0].value) comment_column += ( len(comment_lines[0]) - len(comment_lines[0].lstrip())) comment_leaf = pytree.Leaf( diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 23230e9a0..55b7058ba 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -133,7 +133,7 @@ def Visit_comparison(self, node): # pylint: disable=invalid-name self.Visit(child) if (isinstance(child, pytree.Leaf) and child.value in { '<', '>', '==', '>=', '<=', '<>', '!=', 'in', 'is' - }): + }): _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) elif pytree_utils.NodeName(child) == 'comp_op': for grandchild in child.children: diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 984823382..d145d6465 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2016 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,10 +16,8 @@ import textwrap import unittest -from yapf.yapflib import pytree_utils from yapf.yapflib import reformatter from yapf.yapflib import style -from yapf.yapflib import verifier from yapftests import yapf_test_helper diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 4d4e29ccb..1ea8c89e6 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2016 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -61,7 +61,7 @@ def _BlankDefinition(): def testB32737279(self): unformatted_code = textwrap.dedent("""\ here_is_a_dict = { - 'key': + 'key': # Comment. 'value' } diff --git a/yapftests/reformatter_facebook_test.py b/yapftests/reformatter_facebook_test.py index 51801346f..a4e88a941 100644 --- a/yapftests/reformatter_facebook_test.py +++ b/yapftests/reformatter_facebook_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2016 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,7 +18,6 @@ from yapf.yapflib import reformatter from yapf.yapflib import style -from yapf.yapflib import verifier from yapftests import yapf_test_helper diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 6f7f8548d..a7c822599 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2016 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index 4b3a19e9d..c5a97e61c 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2016 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/reformatter_style_config_test.py b/yapftests/reformatter_style_config_test.py index c413129e8..64df9b849 100644 --- a/yapftests/reformatter_style_config_test.py +++ b/yapftests/reformatter_style_config_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2016 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/reformatter_verify_test.py b/yapftests/reformatter_verify_test.py index a32f6c7df..0838135d5 100644 --- a/yapftests/reformatter_verify_test.py +++ b/yapftests/reformatter_verify_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2016 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/yapf_test_helper.py b/yapftests/yapf_test_helper.py index 313318048..53357a2b1 100644 --- a/yapftests/yapf_test_helper.py +++ b/yapftests/yapf_test_helper.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2016 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. From d94f050194b0714bcb2470246159064fba1e7a98 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 21 Nov 2016 15:25:09 -0800 Subject: [PATCH 067/719] Don't count pseudo-parens in the length of the line. --- CHANGELOG | 1 + yapf/yapflib/format_decision_state.py | 8 ++++--- yapf/yapflib/subtype_assigner.py | 5 ++--- yapf/yapflib/unwrapped_line.py | 5 ++++- yapftests/pytree_utils_test.py | 3 +-- yapftests/reformatter_buganizer_test.py | 28 ++++++++++++++++++++++--- yapftests/reformatter_facebook_test.py | 4 +--- 7 files changed, 39 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1a9b7b3ea..a79f16ccc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,7 @@ line length. - Don't count a dictionary entry as not fitting on a single line in a dictionary. +- Don't count pseudo-parentheses in the length of the line. ## [0.13.2] 2016-10-22 ### Fixed diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index a785ba290..32493e766 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -508,7 +508,7 @@ def _MoveStateToNextToken(self): if is_multiline_string: # This is a multiline string. Only look at the first line. self.column += len(current.value.split('\n')[0]) - elif not current.is_pseudo_paren or current.value == '(': + elif not current.is_pseudo_paren: self.column += len(current.value) self.next_token = self.next_token.next_token @@ -528,8 +528,10 @@ def _MoveStateToNextToken(self): def _FitsOnLine(self, start, end): """Determines if line between start and end can fit on the current line.""" - length = end.total_length - start.total_length + len(start.value) - return length + self.column < self.column_limit + length = end.total_length - start.total_length + if not start.is_pseudo_paren: + length += len(start.value) + return length + self.column <= self.column_limit def _EachDictEntryFitsOnOneLine(self, opening): """Determine if each dict elems can fit on one line.""" diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 55b7058ba..f7223a8bd 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -131,9 +131,8 @@ def Visit_comparison(self, node): # pylint: disable=invalid-name # comp_op ::= '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not in'|'is'|'is not' for child in node.children: self.Visit(child) - if (isinstance(child, pytree.Leaf) and child.value in { - '<', '>', '==', '>=', '<=', '<>', '!=', 'in', 'is' - }): + if (isinstance(child, pytree.Leaf) and + child.value in {'<', '>', '==', '>=', '<=', '<>', '!=', 'in', 'is'}): _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) elif pytree_utils.NodeName(child) == 'comp_op': for grandchild in child.children: diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 0f419d1a5..712dabe71 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -194,7 +194,10 @@ def _SpaceRequiredBetween(left, right): # Space between keyword... tokens and pseudo parens. return True if left.is_pseudo_paren or right.is_pseudo_paren: - # The pseudo-parens shouldn't affect spacing. + # There should be a space after the ':' in a dictionary. + if left.OpensScope(): + return True + # The closing pseudo-paren shouldn't affect spacing. return False if left.is_continuation or right.is_continuation: # The continuation node's value has all of the spaces it needs. diff --git a/yapftests/pytree_utils_test.py b/yapftests/pytree_utils_test.py index 8861a4070..161c93906 100644 --- a/yapftests/pytree_utils_test.py +++ b/yapftests/pytree_utils_test.py @@ -188,8 +188,7 @@ def testSubtype(self): self.assertSetEqual( pytree_utils.GetNodeAnnotation(self._leaf, - pytree_utils.Annotation.SUBTYPE), - {_FOO}) + pytree_utils.Annotation.SUBTYPE), {_FOO}) pytree_utils.RemoveSubtypeAnnotation(self._leaf, _FOO) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 1ea8c89e6..58fb261a8 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,20 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB33047408(self): + code = textwrap.dedent("""\ + def _(): + for sort in (sorts or []): + request['sorts'].append({ + 'field': { + 'user_field': sort + }, + 'order': 'ASCENDING' + }) + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB32714745(self): code = textwrap.dedent("""\ class _(): @@ -701,7 +715,7 @@ def f(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB20849933(self): - code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ def main(unused_argv): if True: aaaaaaaa = { @@ -709,8 +723,16 @@ def main(unused_argv): (eeeeee.FFFFFFFFFFFFFFFFFF), } """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + expected_formatted_code = textwrap.dedent("""\ + def main(unused_argv): + if True: + aaaaaaaa = { + 'xxx': + '%s/cccccc/ddddddddddddddddddd.jar' % (eeeeee.FFFFFFFFFFFFFFFFFF), + } + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB20813997(self): code = textwrap.dedent("""\ diff --git a/yapftests/reformatter_facebook_test.py b/yapftests/reformatter_facebook_test.py index a4e88a941..7ed26311a 100644 --- a/yapftests/reformatter_facebook_test.py +++ b/yapftests/reformatter_facebook_test.py @@ -317,9 +317,7 @@ class _(): def _(): effect_line = FrontInput( effect_line_offset, line_content, - LineSource( - 'localhost', xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - ) + LineSource('localhost', xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) ) """) uwlines = yapf_test_helper.ParseAndUnwrap(code) From 895916ca8f5986a7450423f6213d604bb8471ae6 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 21 Nov 2016 15:29:19 -0800 Subject: [PATCH 068/719] Bump version to v0.14.0 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a79f16ccc..fb887b66c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.14.0] UNRELEASED +## [0.14.0] 2016-11-21 #### Added - formatting can be run in parallel using the "-p" / "--parallel" flags. ### Fixed diff --git a/yapf/__init__.py b/yapf/__init__.py index dc0bc1bda..807a02349 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.13.2' +__version__ = '0.14.0' def main(argv): From 1f0ed96921df73191928819ded432d46463c602e Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 27 Nov 2016 17:06:58 -0800 Subject: [PATCH 069/719] Don't count comments for dict entries Comments aren't part of a dictionary key, so it shouldn't be counted when looking at the length of an entry. --- CHANGELOG | 7 +++ yapf/yapflib/format_decision_state.py | 29 +++++++++-- yapf/yapflib/subtype_assigner.py | 5 +- yapftests/reformatter_buganizer_test.py | 69 +++++++++++++++++++++++-- 4 files changed, 99 insertions(+), 11 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index fb887b66c..9fea46555 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,13 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.14.1] UNRELEASED +### Fixed +- When determining if each element in a dictionary can fit on a single line, we + are skipping dictionary entries. However, we need to ignore comments in our + calculations and implicitly concatenated strings, which are already placed on + separate lines. + ## [0.14.0] 2016-11-21 #### Added - formatting can be run in parallel using the "-p" / "--parallel" flags. diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 32493e766..3d703b846 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -535,30 +535,51 @@ def _FitsOnLine(self, start, end): def _EachDictEntryFitsOnOneLine(self, opening): """Determine if each dict elems can fit on one line.""" + + def PreviousNonCommentToken(tok): + tok = tok.previous_token + while tok.is_comment: + tok = tok.previous_token + return tok + + def ImplicitStringConcatenation(tok): + num_strings = 0 + if tok.is_pseudo_paren: + tok = tok.next_token + while tok.is_string: + num_strings += 1 + tok = tok.next_token + return num_strings > 1 + closing = opening.matching_bracket entry_start = opening.next_token current = opening.next_token.next_token while current and current != closing: if format_token.Subtype.DICTIONARY_KEY in current.subtypes: - length = current.previous_token.total_length - entry_start.total_length + prev = PreviousNonCommentToken(current) + length = prev.total_length - entry_start.total_length length += len(entry_start.value) if length + self.stack[-2].indent >= self.column_limit: return False entry_start = current if current.OpensScope(): if ((current.value == '{' or - (current.is_pseudo_paren and current.next_token.value == '{')) and - format_token.Subtype.DICTIONARY_VALUE in current.subtypes): + (current.is_pseudo_paren and current.next_token.value == '{') and + format_token.Subtype.DICTIONARY_VALUE in current.subtypes) or + ImplicitStringConcatenation(current)): # A dictionary entry that cannot fit on a single line shouldn't matter # to this calcuation. If it can't fit on a single line, then the # opening should be on the same line as the key and the rest on # newlines after it. But the other entries should be on single lines # if possible. + if current.matching_bracket: + current = current.matching_bracket while current: if current == closing: return True if format_token.Subtype.DICTIONARY_KEY in current.subtypes: + entry_start = current break current = current.next_token else: @@ -568,7 +589,7 @@ def _EachDictEntryFitsOnOneLine(self, opening): # At this point, current is the closing bracket. Go back one to get the the # end of the dictionary entry. - current = current.previous_token + current = PreviousNonCommentToken(current) length = current.total_length - entry_start.total_length length += len(entry_start.value) return length + self.stack[-2].indent <= self.column_limit diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index f7223a8bd..b978368ec 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -88,8 +88,9 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name else: _AppendFirstLeafTokenSubtype( child, format_token.Subtype.DICTIONARY_VALUE) - elif (child is not None and - (isinstance(child, pytree.Node) or child.value not in '{:,')): + elif (child is not None and (isinstance(child, pytree.Node) or + (not child.value.startswith('#') and + child.value not in '{:,'))): # Mark the first leaf of a key entry as a DICTIONARY_KEY. We # normally want to split before them if the dictionary cannot exist # on a single line. diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 58fb261a8..bae4dafe3 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,67 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB32931780(self): + unformatted_code = textwrap.dedent("""\ + environments = { + 'prod': { + # this is a comment before the first entry. + 'entry one': + 'an entry.', + # this is the comment before the second entry. + 'entry number 2.': + 'something', + # this is the comment before the third entry and it's a doozy. So big! + 'who': + 'allin', + # This is an entry that has a dictionary in it. It's ugly + 'something': { + 'page': ['this-is-a-page@xxxxxxxx.com', 'something-for-eml@xxxxxx.com'], + 'bug': ['bugs-go-here5300@xxxxxx.com'], + 'email': ['sometypeof-email@xxxxxx.com'], + }, + # a short comment + 'yolo!!!!!': + 'another-email-address@xxxxxx.com', + # this entry has an implicit string concatenation + 'implicit': + 'https://this-is-very-long.url-addr.com/' + '?something=something%20some%20more%20stuff..', + # A more normal entry. + '.....': + 'this is an entry', + } + } + """) + expected_formatted_code = textwrap.dedent("""\ + environments = { + 'prod': { + # this is a comment before the first entry. + 'entry one': 'an entry.', + # this is the comment before the second entry. + 'entry number 2.': 'something', + # this is the comment before the third entry and it's a doozy. So big! + 'who': 'allin', + # This is an entry that has a dictionary in it. It's ugly + 'something': { + 'page': + ['this-is-a-page@xxxxxxxx.com', 'something-for-eml@xxxxxx.com'], + 'bug': ['bugs-go-here5300@xxxxxx.com'], + 'email': ['sometypeof-email@xxxxxx.com'], + }, + # a short comment + 'yolo!!!!!': 'another-email-address@xxxxxx.com', + # this entry has an implicit string concatenation + 'implicit': 'https://this-is-very-long.url-addr.com/' + '?something=something%20some%20more%20stuff..', + # A more normal entry. + '.....': 'this is an entry', + } + } + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB33047408(self): code = textwrap.dedent("""\ def _(): @@ -748,11 +809,9 @@ def testB20605036(self): foo = { 'aaaa': { # A comment for no particular reason. - 'xxxxxxxx': - 'bbbbbbbbb', - 'yyyyyyyyyyyyyyyyyy': - 'cccccccccccccccccccccccccccccc' - 'dddddddddddddddddddddddddddddddddddddddddd', + 'xxxxxxxx': 'bbbbbbbbb', + 'yyyyyyyyyyyyyyyyyy': 'cccccccccccccccccccccccccccccc' + 'dddddddddddddddddddddddddddddddddddddddddd', } } """) From 4b2764b9fd3beef8a4d8fd96023ad0938e3355c7 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 28 Nov 2016 13:08:57 -0800 Subject: [PATCH 070/719] Allow text before 'pylint' comments. b/32567870 --- CHANGELOG | 1 + yapf/yapflib/format_token.py | 2 +- yapftests/reformatter_buganizer_test.py | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9fea46555..fe61a1846 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,7 @@ are skipping dictionary entries. However, we need to ignore comments in our calculations and implicitly concatenated strings, which are already placed on separate lines. +- Allow text before a "pylint" comment. ## [0.14.0] 2016-11-21 #### Added diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 23fcf0098..4e8678afa 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -277,4 +277,4 @@ def is_pseudo_paren(self): @property def is_pylint_comment(self): - return self.is_comment and re.match(r'#\s*\bpylint:\b', self.value) + return self.is_comment and re.match(r'#.*\bpylint:\s*(disable|enable)=', self.value) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index bae4dafe3..7a8df0491 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -190,7 +190,7 @@ def testB31847238(self): unformatted_code = textwrap.dedent("""\ class _(): - def aaaaa(self, bbbbb, cccccccccccccc=None): # pylint: disable=unused-argument + def aaaaa(self, bbbbb, cccccccccccccc=None): # TODO(who): pylint: disable=unused-argument return 1 def xxxxx(self, yyyyy, zzzzzzzzzzzzzz=None): # A normal comment that runs over the column limit. @@ -199,7 +199,7 @@ def xxxxx(self, yyyyy, zzzzzzzzzzzzzz=None): # A normal comment that runs over expected_formatted_code = textwrap.dedent("""\ class _(): - def aaaaa(self, bbbbb, cccccccccccccc=None): # pylint: disable=unused-argument + def aaaaa(self, bbbbb, cccccccccccccc=None): # TODO(who): pylint: disable=unused-argument return 1 def xxxxx( From d408fd622f6ea81d9b563981ba1d3f8542401a6f Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 28 Nov 2016 13:16:04 -0800 Subject: [PATCH 071/719] Allow text before a 'yapf:' comment --- CHANGELOG | 1 + yapf/yapflib/yapf_api.py | 4 ++-- yapftests/yapf_test.py | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index fe61a1846..3fcdd59e9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,7 @@ calculations and implicitly concatenated strings, which are already placed on separate lines. - Allow text before a "pylint" comment. +- Also allow text before a "yapf: (disable|enable)" comment. ## [0.14.0] 2016-11-21 #### Added diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index acfbb825f..32b4c61a4 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -201,8 +201,8 @@ def ReadFile(filename, logger=None): raise -DISABLE_PATTERN = r'^#+ +yapf: *disable$' -ENABLE_PATTERN = r'^#+ +yapf: *enable$' +DISABLE_PATTERN = r'^#.*\byapf:\s*disable\b' +ENABLE_PATTERN = r'^#.*\byapf:\s*enable\b' def _MarkLinesToFormat(uwlines, lines): diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index bba17fb42..1c390d801 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -308,6 +308,25 @@ def testDisabledMultilineStringInDictionary(self): formatted_code, _, _ = yapf_api.FormatFile(f, style_config='chromium') self.assertCodeEqual(code, formatted_code) + def testDisabledWithPrecedingText(self): + code = textwrap.dedent("""\ + # TODO(fix formatting): yapf: disable + + A = [ + { + "aaaaaaaaaaaaaaaaaaa": ''' + bbbbbbbbbbb: "ccccccccccc" + dddddddddddddd: 1 + eeeeeeee: 0 + ffffffffff: "ggggggg" + ''', + }, + ] + """) + f = self._MakeTempFileWithContents('testfile1.py', code) + formatted_code, _, _ = yapf_api.FormatFile(f, style_config='chromium') + self.assertCodeEqual(code, formatted_code) + def testCRLFLineEnding(self): code = 'class _():\r\n pass\r\n' f = self._MakeTempFileWithContents('testfile1.py', code) From 00afcbf689ba299a89882514c8af6e9e92584fee Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 13 Dec 2016 23:44:52 -0800 Subject: [PATCH 072/719] Fix some formatting issues. --- yapf/__init__.py | 4 ++-- yapf/yapflib/format_token.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 807a02349..7edafd975 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -219,8 +219,8 @@ def FormatFiles(filenames, """ changed = False if parallel: - import multiprocessing - import concurrent.futures + import multiprocessing # pylint: disable=g-import-not-at-top + import concurrent.futures # pylint: disable=g-import-not-at-top workers = min(multiprocessing.cpu_count(), len(filenames)) with concurrent.futures.ProcessPoolExecutor(workers) as executor: future_formats = [ diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 4e8678afa..bef414ed4 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -277,4 +277,5 @@ def is_pseudo_paren(self): @property def is_pylint_comment(self): - return self.is_comment and re.match(r'#.*\bpylint:\s*(disable|enable)=', self.value) + return self.is_comment and re.match(r'#.*\bpylint:\s*(disable|enable)=', + self.value) From 0f8280b89717ef1a32495b37fd4f905fae2c353b Mon Sep 17 00:00:00 2001 From: Sebastian Hillig Date: Thu, 29 Dec 2016 17:44:25 +0100 Subject: [PATCH 073/719] Add handling for unpacking with dict expressions Only works on Python 3.6, since lib2to3 in Python 3.5 fails to work with with PEP448 unpacking syntax. --- tox.ini | 2 +- yapf/yapflib/py3compat.py | 1 + yapf/yapflib/subtype_assigner.py | 4 +++- yapftests/reformatter_python3_test.py | 17 +++++++++++++++++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 3109915bb..dca30d2b3 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist=py27,py34,py35 +envlist=py27,py34,py35,py36 [testenv] commands= diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py index 81d4847ce..f2ef31e1f 100644 --- a/yapf/yapflib/py3compat.py +++ b/yapf/yapflib/py3compat.py @@ -17,6 +17,7 @@ import sys PY3 = sys.version_info[0] == 3 +PY36 = sys.version_info[0] == 3 and sys.version_info[1] == 6 if PY3: StringIO = io.StringIO diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index b978368ec..0f0180783 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -75,13 +75,15 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name comp_for = True _AppendFirstLeafTokenSubtype(child, format_token.Subtype.DICT_SET_GENERATOR) - elif pytree_utils.NodeName(child) == 'COLON': + elif pytree_utils.NodeName(child) in ('COLON', 'DOUBLESTAR'): dict_maker = True if not comp_for and dict_maker: last_was_colon = False for child in node.children: if dict_maker: + if pytree_utils.NodeName(child) == "DOUBLESTAR": + _AppendFirstLeafTokenSubtype(child, format_token.Subtype.KWARGS_STAR_STAR) if last_was_colon: if style.Get('INDENT_DICTIONARY_VALUE'): _InsertPseudoParentheses(child) diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index c5a97e61c..9ddf4dc45 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -59,6 +59,23 @@ def foo(a, *, kw): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') + def testPEP448ParameterExpansion(self): + unformatted_code = textwrap.dedent("""\ + { ** x } + { **{} } + { **{ **x }, **x } + {'a': 1, **kw , 'b':3, **kw2 } + """) + expected_formatted_code = textwrap.dedent("""\ + {**x} + {**{}} + {**{**x}, **x} + {'a': 1, **kw, 'b': 3, **kw2} + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testAnnotations(self): unformatted_code = textwrap.dedent("""\ def foo(a: list, b: "bar") -> dict: From 80e6fb6e09ffd3978984ed8e278ba27dd188f85e Mon Sep 17 00:00:00 2001 From: Sebastian Hillig Date: Thu, 29 Dec 2016 18:17:50 +0100 Subject: [PATCH 074/719] Make travis build 3.6 as well, plus handle versions beyond 3.6 --- .travis.yml | 1 + yapf/yapflib/py3compat.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 87965b4ab..1d905185d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ python: - 2.7 - 3.4 - 3.5 + - 3.6 - nightly matrix: diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py index f2ef31e1f..78047cb09 100644 --- a/yapf/yapflib/py3compat.py +++ b/yapf/yapflib/py3compat.py @@ -17,7 +17,7 @@ import sys PY3 = sys.version_info[0] == 3 -PY36 = sys.version_info[0] == 3 and sys.version_info[1] == 6 +PY36 = sys.version_info[0] == 3 and sys.version_info[1] >= 6 if PY3: StringIO = io.StringIO From 86db31633b62d85114c7ff77a421e82a780b84d2 Mon Sep 17 00:00:00 2001 From: Sebastian Hillig Date: Fri, 30 Dec 2016 11:50:20 +0100 Subject: [PATCH 075/719] Align with project code style --- yapf/yapflib/subtype_assigner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 0f0180783..48a9bed92 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -82,7 +82,7 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name last_was_colon = False for child in node.children: if dict_maker: - if pytree_utils.NodeName(child) == "DOUBLESTAR": + if pytree_utils.NodeName(child) == 'DOUBLESTAR': _AppendFirstLeafTokenSubtype(child, format_token.Subtype.KWARGS_STAR_STAR) if last_was_colon: if style.Get('INDENT_DICTIONARY_VALUE'): From 2fcfa67e923d01fc87d86910f795004d26fd3fb5 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 12 Jan 2017 20:58:55 -0800 Subject: [PATCH 076/719] Keep type annotations intact if possible --- CHANGELOG | 7 +++++-- yapf/yapflib/split_penalty.py | 17 +++++++++++++---- yapf/yapflib/subtype_assigner.py | 3 ++- yapftests/reformatter_python3_test.py | 18 ++++++++++++++++++ 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 3fcdd59e9..9a0104e1f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.14.1] UNRELEASED +## [0.15.0] 2017-01-12 +### Added +- Keep type annotations intact as much as possible. Don't try to split the over + mutliple lines. ### Fixed - When determining if each element in a dictionary can fit on a single line, we are skipping dictionary entries. However, we need to ignore comments in our @@ -12,7 +15,7 @@ - Also allow text before a "yapf: (disable|enable)" comment. ## [0.14.0] 2016-11-21 -#### Added +### Added - formatting can be run in parallel using the "-p" / "--parallel" flags. ### Fixed - "not in" and "is not" should be subtyped as binary operators. diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 9960c3380..cef83d3e9 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -82,13 +82,22 @@ def Visit_funcdef(self, node): # pylint: disable=invalid-name while pytree_utils.NodeName(node.children[colon_idx]) == 'simple_stmt': colon_idx += 1 self._SetUnbreakable(node.children[colon_idx]) + arrow_idx = -1 while colon_idx < len(node.children): - if (isinstance(node.children[colon_idx], pytree.Leaf) and - node.children[colon_idx].value == ':'): - break + if isinstance(node.children[colon_idx], pytree.Leaf): + if node.children[colon_idx].value == ':': + break + if node.children[colon_idx].value == '->': + arrow_idx = colon_idx colon_idx += 1 self._SetUnbreakable(node.children[colon_idx]) self.DefaultNodeVisit(node) + if arrow_idx > 0: + pytree_utils.SetNodeAnnotation( + _LastChildNode(node.children[arrow_idx - 1]), + pytree_utils.Annotation.SPLIT_PENALTY, 0) + self._SetUnbreakable(node.children[arrow_idx]) + self._SetStronglyConnected(node.children[arrow_idx + 1]) def Visit_lambdef(self, node): # pylint: disable=invalid-name # lambdef ::= 'lambda' [varargslist] ':' test @@ -317,7 +326,7 @@ def _SetUnbreakableOnChildren(self, node): self._SetUnbreakable(node.children[i]) def _SetExpressionPenalty(self, node, penalty): - """Set an ARITHMETIC_EXPRESSION penalty annotation children nodes.""" + """Set a penalty annotation on children nodes.""" def RecArithmeticExpression(node, first_child_leaf): if node is first_child_leaf: diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 48a9bed92..4bfc1b290 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -83,7 +83,8 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name for child in node.children: if dict_maker: if pytree_utils.NodeName(child) == 'DOUBLESTAR': - _AppendFirstLeafTokenSubtype(child, format_token.Subtype.KWARGS_STAR_STAR) + _AppendFirstLeafTokenSubtype(child, + format_token.Subtype.KWARGS_STAR_STAR) if last_was_colon: if style.Get('INDENT_DICTIONARY_VALUE'): _InsertPseudoParentheses(child) diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index 9ddf4dc45..dcc2d6458 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -179,6 +179,24 @@ async def foo(): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testKeepTypesIntact(self): + if sys.version_info[1] < 5: + return + unformatted_code = textwrap.dedent("""\ + def _ReduceAbstractContainers( + self, *args: Optional[automation_converter.PyiCollectionAbc]) -> List[ + automation_converter.PyiCollectionAbc]: + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def _ReduceAbstractContainers( + self, *args: Optional[automation_converter.PyiCollectionAbc] + ) -> List[automation_converter.PyiCollectionAbc]: + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From 76cc23d06a1544d3ae8b81c650bfebd59f7b1847 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 14 Jan 2017 16:35:48 -0800 Subject: [PATCH 077/719] No space after type hint Closes #351 --- CHANGELOG | 4 ++++ yapf/__init__.py | 2 +- yapf/yapflib/unwrapped_line.py | 15 +++++++++++---- yapftests/reformatter_python3_test.py | 20 ++++++++++++++++++++ 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9a0104e1f..5818acfe0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.15.1] UNRELEASED +### Fixed +- Don't insert a space between a type hint and the '=' sign. + ## [0.15.0] 2017-01-12 ### Added - Keep type annotations intact as much as possible. Don't try to split the over diff --git a/yapf/__init__.py b/yapf/__init__.py index 7edafd975..e84c87e9e 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.14.0' +__version__ = '0.15.0' def main(argv): diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 712dabe71..252c32878 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -230,10 +230,17 @@ def _SpaceRequiredBetween(left, right): (left.is_keyword or left.is_name)): # Don't merge two keywords/identifiers. return True - if left.is_string and rval not in '[)]}.': - # A string followed by something other than a subscript, closing bracket, - # or dot should have a space after it. - return True + if left.is_string: + if (rval == '=' and + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in + right.subtypes): + # If there is a type hint, then we don't want to add a space between the + # equal sign and the hint. + return False + if rval not in '[)]}.': + # A string followed by something other than a subscript, closing bracket, + # or dot should have a space after it. + return True if left.is_binary_op and lval != '**' and _IsUnaryOperator(right): # Space between the binary opertor and the unary operator. return True diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index dcc2d6458..f9690ee46 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -151,6 +151,26 @@ def testSpacesAroundDefaultOrNamedAssign(self): finally: style.SetGlobalStyle(style.CreatePEP8Style()) + def testTypeHint(self): + unformatted_code = textwrap.dedent("""\ + def foo(x: int=42): + pass + + + def foo2(x: 'int' =42): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def foo(x: int=42): + pass + + + def foo2(x: 'int'=42): + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testAsyncWithPrecedingComment(self): if sys.version_info[1] < 5: return From 2dfad8c384427f377b430ae3cd39254189bbeddd Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 14 Jan 2017 16:51:35 -0800 Subject: [PATCH 078/719] Distinguish decorator '@' from matrix mult. Closes #350 --- CHANGELOG | 2 ++ yapf/yapflib/format_token.py | 1 + yapf/yapflib/subtype_assigner.py | 8 ++++++++ yapf/yapflib/unwrapped_line.py | 2 +- yapftests/reformatter_python3_test.py | 10 ++++++++++ 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 5818acfe0..569afe2c0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,8 @@ ## [0.15.1] UNRELEASED ### Fixed - Don't insert a space between a type hint and the '=' sign. +- The '@' operator can be used in Python 3 for matrix multiplication. Give the + '@' in the decorator a DECORATOR subtype to distinguish it. ## [0.15.0] 2017-01-12 ### Added diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index bef414ed4..3ae371c6a 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -52,6 +52,7 @@ class Subtype(object): COMP_FOR = 14 COMP_IF = 15 FUNC_DEF = 16 + DECORATOR = 17 class FormatToken(object): diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 4bfc1b290..f20fa0897 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -243,6 +243,14 @@ def Visit_tname(self, node): # pylint: disable=invalid-name self._ProcessArgLists(node) _SetDefaultOrNamedAssignArgListSubtype(node) + def Visit_decorator(self, node): # pylint: disable=invalid-name + # decorator ::= + # '@' dotted_name [ '(' [arglist] ')' ] NEWLINE + for child in node.children: + if isinstance(child, pytree.Leaf) and child.value == '@': + _AppendTokenSubtype(child, subtype=format_token.Subtype.DECORATOR) + self.Visit(child) + def Visit_funcdef(self, node): # pylint: disable=invalid-name # funcdef ::= # 'def' NAME parameters ['->' test] ':' suite diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 252c32878..c2ac72911 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -274,7 +274,7 @@ def _SpaceRequiredBetween(left, right): format_token.Subtype.KWARGS_STAR_STAR in left.subtypes): # Don't add a space after a vararg's star or a keyword's star-star. return False - if lval == '@': + if (lval == '@' and format_token.Subtype.DECORATOR in left.subtypes): # Decorators shouldn't be separated from the 'at' sign. return False if lval == '.' or rval == '.': diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index f9690ee46..b17b89c45 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -171,6 +171,16 @@ def foo2(x: 'int'=42): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testMatrixMultiplication(self): + unformatted_code = textwrap.dedent("""\ + a=b@c + """) + expected_formatted_code = textwrap.dedent("""\ + a = b @ c + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testAsyncWithPrecedingComment(self): if sys.version_info[1] < 5: return From 9a643a5c40267ddd720eaa72efca04bc82044e10 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 15 Jan 2017 16:45:24 -0800 Subject: [PATCH 079/719] Split at beginning of list instead of later. This is done when the formatter has to decide such things as whether it should split at the beginning of the list or, say, and empty list. We prefer the former in this situation. --- CHANGELOG | 5 ++ yapf/yapflib/blank_line_calculator.py | 4 +- yapf/yapflib/format_decision_state.py | 18 +++---- yapf/yapflib/reformatter.py | 5 +- yapf/yapflib/split_penalty.py | 67 ++++++++++++++++++++----- yapf/yapflib/style.py | 25 +++++---- yapf/yapflib/subtype_assigner.py | 5 +- yapf/yapflib/unwrapped_line.py | 3 +- yapftests/reformatter_basic_test.py | 19 ++++--- yapftests/reformatter_buganizer_test.py | 56 +++++++++++++-------- yapftests/reformatter_pep8_test.py | 4 +- 11 files changed, 136 insertions(+), 75 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 569afe2c0..9625bbb77 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,11 @@ - Don't insert a space between a type hint and the '=' sign. - The '@' operator can be used in Python 3 for matrix multiplication. Give the '@' in the decorator a DECORATOR subtype to distinguish it. +- Encourage the formatter to split at the beginning of an argument list instead + of in the middle. Especially if the middle is an empty parameter list. This + adjusts the affinity of binary and comparison operators. In particular, the + "not in" and other such operators don't want to have a split after it (or + before it) if at all possible. ## [0.15.0] 2017-01-12 ### Added diff --git a/yapf/yapflib/blank_line_calculator.py b/yapf/yapflib/blank_line_calculator.py index 81f6de210..2ae29dafd 100644 --- a/yapf/yapflib/blank_line_calculator.py +++ b/yapf/yapflib/blank_line_calculator.py @@ -140,8 +140,8 @@ def _SetBlankLinesBetweenCommentAndClassFunc(self, node): if not self.last_was_decorator: self._SetNumNewlines(node.children[index].children[0], _ONE_BLANK_LINE) index += 1 - if (index and node.children[index].lineno - 1 == - node.children[index - 1].children[0].lineno): + if (index and node.children[index].lineno - + 1 == node.children[index - 1].children[0].lineno): self._SetNumNewlines(node.children[index], _NO_BLANK_LINES) else: if self.last_comment_lineno + 1 == node.children[index].lineno: diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 3d703b846..8167c41c1 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -95,9 +95,9 @@ def __eq__(self, other): self.column == other.column and self.paren_level == other.paren_level and self.start_of_line_level == other.start_of_line_level and - self.lowest_level_on_line == other.lowest_level_on_line and - (self.ignore_stack_for_comparison or - other.ignore_stack_for_comparison or self.stack == other.stack)) + self.lowest_level_on_line == other.lowest_level_on_line and ( + self.ignore_stack_for_comparison or + other.ignore_stack_for_comparison or self.stack == other.stack)) def __ne__(self, other): return not self == other @@ -406,9 +406,9 @@ def _AddTokenOnNewline(self, dry_run, must_split): self.start_of_line_level = self.paren_level self.lowest_level_on_line = self.paren_level - if (previous.OpensScope() or (previous.is_comment and - previous.previous_token is not None and - previous.previous_token.OpensScope())): + if (previous.OpensScope() or + (previous.is_comment and previous.previous_token is not None and + previous.previous_token.OpensScope())): self.stack[-1].closing_scope_indent = max( 0, self.stack[-1].indent - style.Get('CONTINUATION_INDENT_WIDTH')) self.stack[-1].split_before_closing_bracket = True @@ -447,9 +447,9 @@ def _GetNewlineColumn(self): return top_of_stack.indent if self.paren_level else self.first_indent if current.ClosesScope(): - if (previous.OpensScope() or (previous.is_comment and - previous.previous_token is not None and - previous.previous_token.OpensScope())): + if (previous.OpensScope() or + (previous.is_comment and previous.previous_token is not None and + previous.previous_token.OpensScope())): return max(0, top_of_stack.indent - style.Get('CONTINUATION_INDENT_WIDTH')) return top_of_stack.closing_scope_indent diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 338395156..d2a87d941 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -484,9 +484,8 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, else: prev_last_token.AdjustNewlinesBefore(TWO_BLANK_LINES) if first_token.newlines is not None: - pytree_utils.SetNodeAnnotation(first_token.node, - pytree_utils.Annotation.NEWLINES, - None) + pytree_utils.SetNodeAnnotation( + first_token.node, pytree_utils.Annotation.NEWLINES, None) return NO_BLANK_LINES elif prev_uwline.first.value in {'class', 'def', 'async'}: if not style.Get('BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'): diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index cef83d3e9..c941645c6 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -29,9 +29,11 @@ STRONGLY_CONNECTED = 2000 CONTIGUOUS_LIST = 500 -NOT_TEST = 242 -COMPARISON_EXPRESSION = 842 -ARITHMETIC_EXPRESSION = 942 +NOT_TEST = 50 +COMPARISON_EXPRESSION = 550 +ARITHMETIC_EXPRESSION = 600 +TERM_EXPRESSION = 650 +ONE_ELEMENT_ARGUMENT = 650 def ComputeSplitPenalties(tree): @@ -148,14 +150,23 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name self.DefaultNodeVisit(node) if node.children[0].value == '.': self._SetUnbreakableOnChildren(node) - pytree_utils.SetNodeAnnotation(node.children[1], - pytree_utils.Annotation.SPLIT_PENALTY, - DOTTED_NAME) + pytree_utils.SetNodeAnnotation( + node.children[1], pytree_utils.Annotation.SPLIT_PENALTY, DOTTED_NAME) elif len(node.children) == 2: # Don't split an empty argument list if at all possible. - self._SetStronglyConnected(node.children[1]) + pytree_utils.SetNodeAnnotation(node.children[1], + pytree_utils.Annotation.SPLIT_PENALTY, + VERY_STRONGLY_CONNECTED) elif len(node.children) == 3: - if pytree_utils.NodeName(node.children[1]) not in { + name = pytree_utils.NodeName(node.children[1]) + if name == 'power': + if pytree_utils.NodeName(node.children[1].children[0]) != 'atom': + # Don't split an argument list with one element if at all possible. + self._SetStronglyConnected(node.children[1], node.children[2]) + pytree_utils.SetNodeAnnotation( + _FirstChildNode(node.children[1]), + pytree_utils.Annotation.SPLIT_PENALTY, ONE_ELEMENT_ARGUMENT) + elif name not in { 'arglist', 'argument', 'term', 'or_test', 'and_test', 'comparison', 'atom' }: @@ -163,7 +174,7 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name self._SetStronglyConnected(node.children[1], node.children[2]) if pytree_utils.NodeName(node.children[-1]) == 'RSQB': # Don't split the ending bracket of a subscript list. - self._SetStronglyConnected(node.children[-1]) + self._SetVeryStronglyConnected(*node.children) def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring # power ::= atom trailer* ['**' factor] @@ -269,13 +280,26 @@ def Visit_not_test(self, node): # pylint: disable=invalid-name def Visit_comparison(self, node): # pylint: disable=invalid-name # comparison ::= expr (comp_op expr)* self.DefaultNodeVisit(node) - self._SetExpressionPenalty(node, COMPARISON_EXPRESSION) + if len(node.children) == 3 and _StronglyConnectedCompOp(node): + pytree_utils.SetNodeAnnotation( + _FirstChildNode(node.children[1]), + pytree_utils.Annotation.SPLIT_PENALTY, STRONGLY_CONNECTED) + pytree_utils.SetNodeAnnotation( + _FirstChildNode(node.children[2]), + pytree_utils.Annotation.SPLIT_PENALTY, STRONGLY_CONNECTED) + else: + self._SetExpressionPenalty(node, COMPARISON_EXPRESSION) def Visit_arith_expr(self, node): # pylint: disable=invalid-name # arith_expr ::= term (('+'|'-') term)* self.DefaultNodeVisit(node) self._SetExpressionPenalty(node, ARITHMETIC_EXPRESSION) + def Visit_term_expr(self, node): # pylint: disable=invalid-name + # term ::= factor (('*'|'@'|'/'|'%'|'//') factor)* + self.DefaultNodeVisit(node) + self._SetExpressionPenalty(node, TERM_EXPRESSION) + def Visit_atom(self, node): # pylint: disable=invalid-name # atom ::= ('(' [yield_expr|testlist_gexp] ')' # '[' [listmaker] ']' | @@ -311,6 +335,12 @@ def _SetUnbreakable(self, node): """Set an UNBREAKABLE penalty annotation for the given node.""" _RecAnnotate(node, pytree_utils.Annotation.SPLIT_PENALTY, UNBREAKABLE) + def _SetVeryStronglyConnected(self, *nodes): + """Set a STRONGLY_CONNECTED penalty annotation for the given nodes.""" + for node in nodes: + _RecAnnotate(node, pytree_utils.Annotation.SPLIT_PENALTY, + VERY_STRONGLY_CONNECTED) + def _SetStronglyConnected(self, *nodes): """Set a STRONGLY_CONNECTED penalty annotation for the given nodes.""" for node in nodes: @@ -338,9 +368,8 @@ def RecArithmeticExpression(node, first_child_leaf): penalty_annotation = pytree_utils.GetNodeAnnotation( node, pytree_utils.Annotation.SPLIT_PENALTY, default=0) if penalty_annotation < penalty: - pytree_utils.SetNodeAnnotation(node, - pytree_utils.Annotation.SPLIT_PENALTY, - penalty) + pytree_utils.SetNodeAnnotation( + node, pytree_utils.Annotation.SPLIT_PENALTY, penalty) else: for child in node.children: RecArithmeticExpression(child, first_child_leaf) @@ -389,6 +418,18 @@ def RecGetLeaves(node): prev_child = child +def _StronglyConnectedCompOp(op): + if (len(op.children[1].children) == 2 and + pytree_utils.NodeName(op.children[1]) == 'comp_op' and + _FirstChildNode(op.children[1]).value == 'not' and + _LastChildNode(op.children[1]).value == 'in'): + return True + if (isinstance(op.children[1], pytree.Leaf) and + op.children[1].value in {'==', 'in'}): + return True + return False + + def _FirstChildNode(node): if isinstance(node, pytree.Leaf): return node diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index b45383c3e..ed7c32087 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -229,7 +229,6 @@ def CreateChromiumStyle(): style['INDENT_WIDTH'] = 2 style['JOIN_MULTIPLE_LINES'] = False style['SPLIT_BEFORE_BITWISE_OPERATOR'] = True - style['SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT'] = 0 return style @@ -362,8 +361,8 @@ def GlobalStyles(): def _CreateConfigParserFromConfigString(config_string): """Given a config string from the command line, return a config parser.""" if config_string[0] != '{' or config_string[-1] != '}': - raise StyleConfigError("Invalid style dict syntax: '{}'.".format( - config_string)) + raise StyleConfigError( + "Invalid style dict syntax: '{}'.".format(config_string)) config = py3compat.ConfigParser() config.add_section('style') for key, value in re.findall(r'([a-zA-Z0-9_]+)\s*[:=]\s*([a-zA-Z0-9_]+)', @@ -376,23 +375,23 @@ def _CreateConfigParserFromConfigFile(config_filename): """Read the file and return a ConfigParser object.""" if not os.path.exists(config_filename): # Provide a more meaningful error here. - raise StyleConfigError('"{0}" is not a valid style or file path'.format( - config_filename)) + raise StyleConfigError( + '"{0}" is not a valid style or file path'.format(config_filename)) with open(config_filename) as style_file: config = py3compat.ConfigParser() config.read_file(style_file) if config_filename.endswith(SETUP_CONFIG): if not config.has_section('yapf'): - raise StyleConfigError('Unable to find section [yapf] in {0}'.format( - config_filename)) + raise StyleConfigError( + 'Unable to find section [yapf] in {0}'.format(config_filename)) elif config_filename.endswith(LOCAL_STYLE): if not config.has_section('style'): - raise StyleConfigError('Unable to find section [style] in {0}'.format( - config_filename)) + raise StyleConfigError( + 'Unable to find section [style] in {0}'.format(config_filename)) else: if not config.has_section('style'): - raise StyleConfigError('Unable to find section [style] in {0}'.format( - config_filename)) + raise StyleConfigError( + 'Unable to find section [style] in {0}'.format(config_filename)) return config @@ -431,8 +430,8 @@ def _CreateStyleFromConfigParser(config): try: base_style[option] = _STYLE_OPTION_VALUE_CONVERTER[option](value) except ValueError: - raise StyleConfigError("'{}' is not a valid setting for {}.".format( - value, option)) + raise StyleConfigError( + "'{}' is not a valid setting for {}.".format(value, option)) return base_style diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index f20fa0897..b5287cb68 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -91,9 +91,8 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name else: _AppendFirstLeafTokenSubtype( child, format_token.Subtype.DICTIONARY_VALUE) - elif (child is not None and (isinstance(child, pytree.Node) or - (not child.value.startswith('#') and - child.value not in '{:,'))): + elif (child is not None and (isinstance(child, pytree.Node) or ( + not child.value.startswith('#') and child.value not in '{:,'))): # Mark the first leaf of a key entry as a DICTIONARY_KEY. We # normally want to split before them if the dictionary cannot exist # on a single line. diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index c2ac72911..6101784ac 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -231,8 +231,7 @@ def _SpaceRequiredBetween(left, right): # Don't merge two keywords/identifiers. return True if left.is_string: - if (rval == '=' and - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in + if (rval == '=' and format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in right.subtypes): # If there is a type hint, then we don't want to add a space between the # equal sign and the hint. diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index d145d6465..907790a96 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1539,13 +1539,18 @@ def method(self): style.SetGlobalStyle(style.CreateChromiumStyle()) def testDontSplitKeywordValueArguments(self): - code = textwrap.dedent("""\ - def mark_game_scored(gid): - _connect.execute(_games.update().where(_games.c.gid == gid).values( - scored=True)) - """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + unformatted_code = textwrap.dedent("""\ + def mark_game_scored(gid): + _connect.execute(_games.update().where(_games.c.gid == gid).values( + scored=True)) + """) + expected_formatted_code = textwrap.dedent("""\ + def mark_game_scored(gid): + _connect.execute( + _games.update().where(_games.c.gid == gid).values(scored=True)) + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testDontAddBlankLineAfterMultilineString(self): code = textwrap.dedent("""\ diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 7a8df0491..80cf47b5d 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,22 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB33842726(self): + unformatted_code = textwrap.dedent("""\ + class _(): + def _(): + hints.append(('hg tag -f -l -r %s %s # %s' % (short(ctx.node( + )), candidatetag, firstline))[:78]) + """) + expected_formatted_code = textwrap.dedent("""\ + class _(): + def _(): + hints.append(('hg tag -f -l -r %s %s # %s' % + (short(ctx.node()), candidatetag, firstline))[:78]) + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB32931780(self): unformatted_code = textwrap.dedent("""\ environments = { @@ -672,27 +688,25 @@ def functioni(self, aaaaaaa, bbbbbbb, cccccc, dddddddddddddd, def testB28414371(self): code = textwrap.dedent("""\ def _(): - return ( - (m.fffff( - m.rrr('mmmmmmmmmmmmmmmm', 'ssssssssssssssssssssssssss'), - ffffffffffffffff) - | m.wwwwww(m.ddddd('1h')) - | m.ggggggg(bbbbbbbbbbbbbbb) - | m.ppppp( - (1 - m.ffffffffffffffff(llllllllllllllllllllll * 1000000, m.vvv)) * - m.ddddddddddddddddd(m.vvv)), m.fffff( - m.rrr('mmmmmmmmmmmmmmmm', 'sssssssssssssssssssssss'), - dict( - ffffffffffffffff, - **{ - 'mmmmmm:ssssss': - m.rrrrrrrrrrr( - '|'.join(iiiiiiiiiiiiii), iiiiii=True) - })) - | m.wwwwww(m.rrrr('1h')) - | m.ggggggg(bbbbbbbbbbbbbbb)) - | m.jjjj() - | m.ppppp(m.vvv[0] + m.vvv[1])) + return ((m.fffff( + m.rrr('mmmmmmmmmmmmmmmm', 'ssssssssssssssssssssssssss'), ffffffffffffffff) + | m.wwwwww(m.ddddd('1h')) + | m.ggggggg(bbbbbbbbbbbbbbb) + | m.ppppp( + (1 - m.ffffffffffffffff(llllllllllllllllllllll * 1000000, m.vvv)) + * m.ddddddddddddddddd(m.vvv)), m.fffff( + m.rrr('mmmmmmmmmmmmmmmm', 'sssssssssssssssssssssss'), + dict( + ffffffffffffffff, + **{ + 'mmmmmm:ssssss': + m.rrrrrrrrrrr( + '|'.join(iiiiiiiiiiiiii), iiiiii=True) + })) + | m.wwwwww(m.rrrr('1h')) + | m.ggggggg(bbbbbbbbbbbbbbb)) + | m.jjjj() + | m.ppppp(m.vvv[0] + m.vvv[1])) """) uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index a7c822599..6ba4a8c8c 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -169,8 +169,8 @@ def g(): def f(): def g(): while (xxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz]) == 'aaaaaaaaaaa' and - xxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == - 'bbbbbbb'): + xxxxxxxxxxxxxxxxxxxx( + yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): pass """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) From df712b809eb2519d46733c0ae0abaa0c522ca16d Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 17 Jan 2017 10:47:24 -0800 Subject: [PATCH 080/719] Bump up year in copyright statement --- setup.py | 2 +- yapf/__init__.py | 2 +- yapf/__main__.py | 2 +- yapf/yapflib/__init__.py | 2 +- yapf/yapflib/blank_line_calculator.py | 2 +- yapf/yapflib/comment_splicer.py | 2 +- yapf/yapflib/continuation_splicer.py | 2 +- yapf/yapflib/errors.py | 2 +- yapf/yapflib/file_resources.py | 2 +- yapf/yapflib/format_decision_state.py | 2 +- yapf/yapflib/format_token.py | 2 +- yapf/yapflib/line_joiner.py | 2 +- yapf/yapflib/py3compat.py | 2 +- yapf/yapflib/pytree_unwrapper.py | 2 +- yapf/yapflib/pytree_utils.py | 2 +- yapf/yapflib/pytree_visitor.py | 2 +- yapf/yapflib/reformatter.py | 2 +- yapf/yapflib/split_penalty.py | 2 +- yapf/yapflib/style.py | 2 +- yapf/yapflib/subtype_assigner.py | 2 +- yapf/yapflib/unwrapped_line.py | 2 +- yapf/yapflib/verifier.py | 2 +- yapf/yapflib/yapf_api.py | 2 +- yapftests/__init__.py | 2 +- yapftests/blank_line_calculator_test.py | 2 +- yapftests/comment_splicer_test.py | 2 +- yapftests/file_resources_test.py | 2 +- yapftests/format_decision_state_test.py | 2 +- yapftests/format_token_test.py | 2 +- yapftests/line_joiner_test.py | 2 +- yapftests/main_test.py | 2 +- yapftests/pytree_unwrapper_test.py | 2 +- yapftests/pytree_utils_test.py | 2 +- yapftests/pytree_visitor_test.py | 2 +- yapftests/reformatter_basic_test.py | 2 +- yapftests/reformatter_buganizer_test.py | 2 +- yapftests/reformatter_facebook_test.py | 2 +- yapftests/reformatter_pep8_test.py | 2 +- yapftests/reformatter_python3_test.py | 2 +- yapftests/reformatter_style_config_test.py | 2 +- yapftests/reformatter_verify_test.py | 2 +- yapftests/split_penalty_test.py | 2 +- yapftests/style_test.py | 2 +- yapftests/subtype_assigner_test.py | 2 +- yapftests/unwrapped_line_test.py | 2 +- yapftests/yapf_test.py | 2 +- yapftests/yapf_test_helper.py | 2 +- 47 files changed, 47 insertions(+), 47 deletions(-) diff --git a/setup.py b/setup.py index 59042c009..fc8781ef3 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/__init__.py b/yapf/__init__.py index e84c87e9e..89ca667ae 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/__main__.py b/yapf/__main__.py index b9c20bdd9..88f1ec69e 100644 --- a/yapf/__main__.py +++ b/yapf/__main__.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/__init__.py b/yapf/yapflib/__init__.py index 67076fe58..80217ac4a 100644 --- a/yapf/yapflib/__init__.py +++ b/yapf/yapflib/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/blank_line_calculator.py b/yapf/yapflib/blank_line_calculator.py index 2ae29dafd..bcd7a867a 100644 --- a/yapf/yapflib/blank_line_calculator.py +++ b/yapf/yapflib/blank_line_calculator.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index 822e28b41..4559bdef7 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/continuation_splicer.py b/yapf/yapflib/continuation_splicer.py index 0a459e17f..74ea1a0cb 100644 --- a/yapf/yapflib/continuation_splicer.py +++ b/yapf/yapflib/continuation_splicer.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/errors.py b/yapf/yapflib/errors.py index e5ab9c2d7..03f3ae48a 100644 --- a/yapf/yapflib/errors.py +++ b/yapf/yapflib/errors.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index dab68ca3d..5f2e3c123 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 8167c41c1..df4e24e55 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 3ae371c6a..45eb49506 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/line_joiner.py b/yapf/yapflib/line_joiner.py index e7a168440..860fce788 100644 --- a/yapf/yapflib/line_joiner.py +++ b/yapf/yapflib/line_joiner.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py index 78047cb09..2ca5523b5 100644 --- a/yapf/yapflib/py3compat.py +++ b/yapf/yapflib/py3compat.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index e651061b5..7232b65e7 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/pytree_utils.py b/yapf/yapflib/pytree_utils.py index 1bebcb8ac..60fd955ff 100644 --- a/yapf/yapflib/pytree_utils.py +++ b/yapf/yapflib/pytree_utils.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/pytree_visitor.py b/yapf/yapflib/pytree_visitor.py index c13aea5c4..3f1ab0b71 100644 --- a/yapf/yapflib/pytree_visitor.py +++ b/yapf/yapflib/pytree_visitor.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index d2a87d941..935a13eb7 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index c941645c6..02d5efa9a 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index ed7c32087..64a5343e0 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index b5287cb68..f9277dcfc 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 6101784ac..89a30f9a1 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/verifier.py b/yapf/yapflib/verifier.py index 891798d2f..b16aefb88 100644 --- a/yapf/yapflib/verifier.py +++ b/yapf/yapflib/verifier.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 32b4c61a4..3a5031998 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/__init__.py b/yapftests/__init__.py index 67076fe58..80217ac4a 100644 --- a/yapftests/__init__.py +++ b/yapftests/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/blank_line_calculator_test.py b/yapftests/blank_line_calculator_test.py index f8fee8778..07710ea07 100644 --- a/yapftests/blank_line_calculator_test.py +++ b/yapftests/blank_line_calculator_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/comment_splicer_test.py b/yapftests/comment_splicer_test.py index c26cac8c1..ee0527e24 100644 --- a/yapftests/comment_splicer_test.py +++ b/yapftests/comment_splicer_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 743df5f20..7bf6b2735 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/format_decision_state_test.py b/yapftests/format_decision_state_test.py index c4b1ce868..5f0979511 100644 --- a/yapftests/format_decision_state_test.py +++ b/yapftests/format_decision_state_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index 7f5368f6f..ff1d01555 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/line_joiner_test.py b/yapftests/line_joiner_test.py index c2bd496fc..518ea0887 100644 --- a/yapftests/line_joiner_test.py +++ b/yapftests/line_joiner_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/main_test.py b/yapftests/main_test.py index 4293b19d6..d5b0317b3 100644 --- a/yapftests/main_test.py +++ b/yapftests/main_test.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/pytree_unwrapper_test.py b/yapftests/pytree_unwrapper_test.py index fa1f70bcf..ab634a57e 100644 --- a/yapftests/pytree_unwrapper_test.py +++ b/yapftests/pytree_unwrapper_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/pytree_utils_test.py b/yapftests/pytree_utils_test.py index 161c93906..db5d36357 100644 --- a/yapftests/pytree_utils_test.py +++ b/yapftests/pytree_utils_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/pytree_visitor_test.py b/yapftests/pytree_visitor_test.py index 057748311..c86ffc960 100644 --- a/yapftests/pytree_visitor_test.py +++ b/yapftests/pytree_visitor_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 907790a96..85d293163 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1,4 +1,4 @@ -# Copyright 2016 Google Inc. All Rights Reserved. +# Copyright 2016-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 80cf47b5d..57c942859 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -1,4 +1,4 @@ -# Copyright 2016 Google Inc. All Rights Reserved. +# Copyright 2016-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/reformatter_facebook_test.py b/yapftests/reformatter_facebook_test.py index 7ed26311a..ba2558a5a 100644 --- a/yapftests/reformatter_facebook_test.py +++ b/yapftests/reformatter_facebook_test.py @@ -1,4 +1,4 @@ -# Copyright 2016 Google Inc. All Rights Reserved. +# Copyright 2016-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 6ba4a8c8c..709d87190 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -1,4 +1,4 @@ -# Copyright 2016 Google Inc. All Rights Reserved. +# Copyright 2016-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index b17b89c45..3dcbe4bbd 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -1,4 +1,4 @@ -# Copyright 2016 Google Inc. All Rights Reserved. +# Copyright 2016-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/reformatter_style_config_test.py b/yapftests/reformatter_style_config_test.py index 64df9b849..5a04930d3 100644 --- a/yapftests/reformatter_style_config_test.py +++ b/yapftests/reformatter_style_config_test.py @@ -1,4 +1,4 @@ -# Copyright 2016 Google Inc. All Rights Reserved. +# Copyright 2016-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/reformatter_verify_test.py b/yapftests/reformatter_verify_test.py index 0838135d5..dd1d60f4a 100644 --- a/yapftests/reformatter_verify_test.py +++ b/yapftests/reformatter_verify_test.py @@ -1,4 +1,4 @@ -# Copyright 2016 Google Inc. All Rights Reserved. +# Copyright 2016-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index 7aa1b292c..00a870e6f 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 84567275b..f752d8ccb 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index 75c907c8e..72cb6a278 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/unwrapped_line_test.py b/yapftests/unwrapped_line_test.py index 03581d56e..310b51bbd 100644 --- a/yapftests/unwrapped_line_test.py +++ b/yapftests/unwrapped_line_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 1c390d801..8aa402d9c 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright 2015-2016 Google Inc. All Rights Reserved. +# Copyright 2015-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/yapf_test_helper.py b/yapftests/yapf_test_helper.py index 53357a2b1..95edd29b4 100644 --- a/yapftests/yapf_test_helper.py +++ b/yapftests/yapf_test_helper.py @@ -1,4 +1,4 @@ -# Copyright 2016 Google Inc. All Rights Reserved. +# Copyright 2016-2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. From 622af84c75f95eeb212c904b10ad80aca6966d07 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 21 Jan 2017 23:43:35 -0800 Subject: [PATCH 081/719] Bump to v0.15.1 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9625bbb77..47f9f03bb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.15.1] UNRELEASED +## [0.15.1] 2017-01-21 ### Fixed - Don't insert a space between a type hint and the '=' sign. - The '@' operator can be used in Python 3 for matrix multiplication. Give the diff --git a/yapf/__init__.py b/yapf/__init__.py index 89ca667ae..52d01b842 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.15.0' +__version__ = '0.15.1' def main(argv): From 1935f6bb3d480bfd26efcd1616b1db6f859a5cbe Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 24 Jan 2017 15:34:35 -0800 Subject: [PATCH 082/719] Don't split too aggressively with named assigns If a function call that has a named assign is part of an argument list, don't cause the other arguments to split just because it has a named assign. I.e., 'a' won't be forced to split here: func(a, b, c, d(x, y, z=42)) --- CHANGELOG | 8 ++++++ yapf/yapflib/comment_splicer.py | 12 +++------ yapf/yapflib/format_decision_state.py | 22 ++++++++++++--- yapf/yapflib/subtype_assigner.py | 3 ++- yapftests/reformatter_basic_test.py | 18 +++++++++++++ yapftests/reformatter_buganizer_test.py | 36 ++++++++++++++----------- yapftests/reformatter_verify_test.py | 15 +++++------ 7 files changed, 77 insertions(+), 37 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 47f9f03bb..1b7e55e47 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,14 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.15.2] UNRELEASED +### Fixed +- Don't perform a global split when a named assign is part of a function call + which itself is an argument to a function call. I.e., don't cause 'a' to + split here: + + func(a, b, c, d(x, y, z=42)) + ## [0.15.1] 2017-01-21 ### Fixed - Don't insert a space between a type hint and the '=' sign. diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index 4559bdef7..a7b37a804 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -78,8 +78,7 @@ def _VisitNodeRec(node): comment_prefix, comment_lineno, comment_column, - standalone=False), - prev_leaf[0]) + standalone=False), prev_leaf[0]) elif child.type == token.DEDENT: # Comment prefixes on DEDENT nodes also deserve special treatment, # because their final placement depends on their prefix. @@ -124,8 +123,7 @@ def _VisitNodeRec(node): '\n'.join(before) + '\n', comment_lineno, comment_column, - standalone=True), - ancestor_at_indent) + standalone=True), ancestor_at_indent) if after: after_column = len(after[0]) - len(after[0].lstrip()) comment_column -= comment_column - after_column @@ -134,16 +132,14 @@ def _VisitNodeRec(node): '\n'.join(after) + '\n', after_lineno, comment_column, - standalone=True), - _FindNextAncestor(ancestor_at_indent)) + standalone=True), _FindNextAncestor(ancestor_at_indent)) else: pytree_utils.InsertNodesAfter( _CreateCommentsFromPrefix( comment_prefix, comment_lineno, comment_column, - standalone=True), - ancestor_at_indent) + standalone=True), ancestor_at_indent) else: # Otherwise there are two cases. # diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index df4e24e55..3bd3b3669 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -192,11 +192,25 @@ def MustSplit(self): # a( # b=1, # c=2) - indent_amt = self.stack[-1].indent * style.Get('INDENT_WIDTH') - pptoken = previous.previous_token - opening_column = len(pptoken.value) if pptoken else 0 - indent_amt - 1 if previous.value == '(': - return opening_column >= style.Get('CONTINUATION_INDENT_WIDTH') + if (self._FitsOnLine(previous, previous.matching_bracket) and + unwrapped_line.IsSurroundedByBrackets(previous)): + # An argument to a function is a function call with named + # assigns. + return False + + func_start = previous.previous_token + while func_start and func_start.previous_token: + prev = func_start.previous_token + if not prev.is_name and prev.value != '.': + break + func_start = prev + + if func_start: + func_name_len = previous.total_length - func_start.total_length + func_name_len += len(func_start.value) + return func_name_len > style.Get('CONTINUATION_INDENT_WIDTH') + opening = _GetOpeningBracket(current) if opening: arglist_length = (opening.matching_bracket.total_length - diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index f9277dcfc..155994aee 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -313,7 +313,8 @@ def HasDefaultOrNamedAssignSubtype(node): return False has_subtype = False for child in node.children: - has_subtype |= HasDefaultOrNamedAssignSubtype(child) + if pytree_utils.NodeName(child) != 'arglist': + has_subtype |= HasDefaultOrNamedAssignSubtype(child) return has_subtype if HasDefaultOrNamedAssignSubtype(node): diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 85d293163..f180ace79 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1946,6 +1946,24 @@ def testNotInParams(self): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + def testNamedAssignNotAtEndOfLine(self): + unformatted_code = textwrap.dedent("""\ + def _(): + if True: + with py3compat.open_with_encoding(filename, mode='w', + encoding=encoding) as fd: + pass + """) + expected_code = textwrap.dedent("""\ + def _(): + if True: + with py3compat.open_with_encoding( + filename, mode='w', encoding=encoding) as fd: + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 57c942859..79d064170 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,17 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB34682902(self): + unformatted_code = textwrap.dedent("""\ + logging.info("Mean angular velocity norm: %.3f", np.linalg.norm(np.mean(ang_vel_arr, axis=0))) + """) + expected_formatted_code = textwrap.dedent("""\ + logging.info("Mean angular velocity norm: %.3f", + np.linalg.norm(np.mean(ang_vel_arr, axis=0))) + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB33842726(self): unformatted_code = textwrap.dedent("""\ class _(): @@ -407,12 +418,9 @@ def testB27616132(self): expected_formatted_code = textwrap.dedent("""\ if True: query.fetch_page.assert_has_calls([ - mock.call( - 100, start_cursor=None), - mock.call( - 100, start_cursor=cursor_1), - mock.call( - 100, start_cursor=cursor_2), + mock.call(100, start_cursor=None), + mock.call(100, start_cursor=cursor_1), + mock.call(100, start_cursor=cursor_2), ]) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) @@ -696,13 +704,10 @@ def _(): (1 - m.ffffffffffffffff(llllllllllllllllllllll * 1000000, m.vvv)) * m.ddddddddddddddddd(m.vvv)), m.fffff( m.rrr('mmmmmmmmmmmmmmmm', 'sssssssssssssssssssssss'), - dict( - ffffffffffffffff, - **{ - 'mmmmmm:ssssss': - m.rrrrrrrrrrr( - '|'.join(iiiiiiiiiiiiii), iiiiii=True) - })) + dict(ffffffffffffffff, **{ + 'mmmmmm:ssssss': + m.rrrrrrrrrrr('|'.join(iiiiiiiiiiiiii), iiiiii=True) + })) | m.wwwwww(m.rrrr('1h')) | m.ggggggg(bbbbbbbbbbbbbbb)) | m.jjjj() @@ -965,8 +970,9 @@ def bar(self): def testB19194420(self): code = textwrap.dedent("""\ - method.Set('long argument goes here that causes the line to break', - lambda arg2=0.5: arg2) + method.Set( + 'long argument goes here that causes the line to break', + lambda arg2=0.5: arg2) """) uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_verify_test.py b/yapftests/reformatter_verify_test.py index dd1d60f4a..a585c3b84 100644 --- a/yapftests/reformatter_verify_test.py +++ b/yapftests/reformatter_verify_test.py @@ -51,9 +51,8 @@ class ABC(metaclass=type): pass """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat( - uwlines, verify=False)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines, verify=False)) def testVerifyFutureImport(self): unformatted_code = textwrap.dedent("""\ @@ -81,9 +80,8 @@ def call_my_function(the_function): call_my_function(print) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat( - uwlines, verify=False)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines, verify=False)) def testContinuationLineShouldBeDistinguished(self): unformatted_code = textwrap.dedent("""\ @@ -102,9 +100,8 @@ def bar(self): pass """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat( - uwlines, verify=False)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines, verify=False)) if __name__ == '__main__': From fb4d0555602f9a181bc9585a0c055a08f8a5c1c2 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 25 Jan 2017 09:44:41 -0800 Subject: [PATCH 083/719] Allow subscript splitting around and/or ops The LHS and RHS of the ops are still left contiguous, but loosen the restriction when it's and/or ops. Closes #332 --- CHANGELOG | 2 ++ yapf/yapflib/split_penalty.py | 24 +++++++++++++++++++++--- yapftests/reformatter_pep8_test.py | 13 +++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1b7e55e47..2ec10fb08 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,8 @@ split here: func(a, b, c, d(x, y, z=42)) +- Allow splitting inside a subscript if it's a logical or bitwise operating. + This should keep the subscript mostly contiguous otherwise. ## [0.15.1] 2017-01-21 ### Fixed diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 02d5efa9a..5ebdf7346 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -166,15 +166,33 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name pytree_utils.SetNodeAnnotation( _FirstChildNode(node.children[1]), pytree_utils.Annotation.SPLIT_PENALTY, ONE_ELEMENT_ARGUMENT) + elif (pytree_utils.NodeName(node.children[0]) == 'LSQB' and + (name.endswith('_test') or name.endswith('_expr'))): + self._SetStronglyConnected(node.children[1].children[0]) + self._SetStronglyConnected(node.children[1].children[2]) + + # Still allow splitting around the operator. + split_before = ((name.endswith('_test') and + style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR')) or + (name.endswith('_expr') and + style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'))) + if split_before: + pytree_utils.SetNodeAnnotation( + _LastChildNode(node.children[1].children[1]), + pytree_utils.Annotation.SPLIT_PENALTY, 0) + else: + pytree_utils.SetNodeAnnotation( + _FirstChildNode(node.children[1].children[2]), + pytree_utils.Annotation.SPLIT_PENALTY, 0) + + # Don't split the ending bracket of a subscript list. + self._SetVeryStronglyConnected(node.children[-1]) elif name not in { 'arglist', 'argument', 'term', 'or_test', 'and_test', 'comparison', 'atom' }: # Don't split an argument list with one element if at all possible. self._SetStronglyConnected(node.children[1], node.children[2]) - if pytree_utils.NodeName(node.children[-1]) == 'RSQB': - # Don't split the ending bracket of a subscript list. - self._SetVeryStronglyConnected(*node.children) def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring # power ::= atom trailer* ['**' factor] diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 709d87190..7a62bce51 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -296,6 +296,19 @@ def testSplittingBeforeFirstArgument(self): finally: style.SetGlobalStyle(style.CreatePEP8Style()) + def testSplittingExpressionsInsideSubscripts(self): + unformatted_code = textwrap.dedent("""\ + def foo(): + df = df[(df['campaign_status'] == 'LIVE') & (df['action_status'] == 'LIVE')] + """) + expected_formatted_code = textwrap.dedent("""\ + def foo(): + df = df[(df['campaign_status'] == 'LIVE') & + (df['action_status'] == 'LIVE')] + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From b69149a25a873692d2532fc3f2d701951e755c85 Mon Sep 17 00:00:00 2001 From: teoric Date: Sat, 28 Jan 2017 16:46:48 +0100 Subject: [PATCH 084/719] Suggestion: VIM command I do not use YAPF so often, so I do not want a mapping. But calling the function is unhandy, too. Therefore I created a VIM command `:YAPF` that can take a range (see comments in code for how to use it). --- plugins/yapf.vim | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugins/yapf.vim b/plugins/yapf.vim index 24b351070..82f999176 100644 --- a/plugins/yapf.vim +++ b/plugins/yapf.vim @@ -20,6 +20,13 @@ " map :call yapf#YAPF() " imap :call yapf#YAPF() " +" Alternatively, you can call the command YAPF. If you omit the range, +" it will reformat the whole buffer. +" +" example: +" :YAPF " formats whole buffer +" :'<,'>YAPF " formats lines selected in visual mode +" function! yapf#YAPF() range " Determine range to format. let l:line_ranges = a:firstline . '-' . a:lastline @@ -35,3 +42,5 @@ function! yapf#YAPF() range " Reset cursor to first line of the formatted range. call cursor(a:firstline, 1) endfunction + +command! -range=% YAPF ,call yapf#YAPF() From d1f8613872e3c2c8d3de44d9fcd1d99f357c9343 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 29 Jan 2017 19:45:13 -0800 Subject: [PATCH 085/719] Bump to v0.15.2 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 2ec10fb08..73adb25b5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.15.2] UNRELEASED +## [0.15.2] 2017-01-29 ### Fixed - Don't perform a global split when a named assign is part of a function call which itself is an argument to a function call. I.e., don't cause 'a' to diff --git a/yapf/__init__.py b/yapf/__init__.py index 52d01b842..3f34c9f31 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.15.1' +__version__ = '0.15.2' def main(argv): From 2f762cc2e4580e3a91141b1659fa2aa3cd37078a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 30 Jan 2017 05:33:52 -0800 Subject: [PATCH 086/719] Remove superfluous parentheses --- yapf/yapflib/unwrapped_line.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 89a30f9a1..8e0d3d138 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -273,7 +273,7 @@ def _SpaceRequiredBetween(left, right): format_token.Subtype.KWARGS_STAR_STAR in left.subtypes): # Don't add a space after a vararg's star or a keyword's star-star. return False - if (lval == '@' and format_token.Subtype.DECORATOR in left.subtypes): + if lval == '@' and format_token.Subtype.DECORATOR in left.subtypes: # Decorators shouldn't be separated from the 'at' sign. return False if lval == '.' or rval == '.': From 26fbc0c1ad5a15642dcc280776a6032baced07ee Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 30 Jan 2017 23:17:16 -0800 Subject: [PATCH 087/719] Remove some pylint warnings. --- yapf/__init__.py | 2 +- yapf/yapflib/errors.py | 1 + yapf/yapflib/format_decision_state.py | 1 + yapf/yapflib/format_token.py | 1 - yapf/yapflib/reformatter.py | 3 +- yapf/yapflib/subtype_assigner.py | 2 ++ yapftests/main_test.py | 40 ++++++++++++--------------- yapftests/style_test.py | 2 +- yapftests/yapf_test.py | 11 ++++---- 9 files changed, 29 insertions(+), 34 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 3f34c9f31..991c445b2 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -163,7 +163,7 @@ def main(argv): style_config = file_resources.GetDefaultStyleForDir(os.getcwd()) source = [line.rstrip() for line in original_source] - reformatted_source, changed = yapf_api.FormatCode( + reformatted_source, _ = yapf_api.FormatCode( py3compat.unicode('\n'.join(source) + '\n'), filename='', style_config=style_config, diff --git a/yapf/yapflib/errors.py b/yapf/yapflib/errors.py index 03f3ae48a..aa8f3eada 100644 --- a/yapf/yapflib/errors.py +++ b/yapf/yapflib/errors.py @@ -11,6 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""YAPF error object.""" class YapfError(Exception): diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 3bd3b3669..4934769ab 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -629,6 +629,7 @@ def _GetLengthOfSubtype(token, subtype, exclude=None): def _GetOpeningBracket(current): + """Get the opening bracket containing the current token.""" if current.matching_bracket and not current.is_pseudo_paren: return current.matching_bracket while current: diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 45eb49506..13d78ff17 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -19,7 +19,6 @@ import keyword import re -from lib2to3 import pytree from lib2to3.pgen2 import token from yapf.yapflib import py3compat diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 935a13eb7..0eed432c5 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -230,6 +230,7 @@ def _CanPlaceOnSingleLine(uwline): def _FormatFinalLines(final_lines, verify): + """Compose the final output from the finalized lines.""" formatted_code = [] for line in final_lines: formatted_line = [] @@ -310,7 +311,6 @@ def _AnalyzeSolutionSpace(initial_state): heapq.heappush(p_queue, _QueueItem(_OrderedPenalty(0, count), node)) count += 1 - prev_penalty = 0 while p_queue: item = p_queue[0] penalty = item.ordered_penalty.penalty @@ -325,7 +325,6 @@ def _AnalyzeSolutionSpace(initial_state): if node.state in seen: continue - prev_penalty = penalty seen.add(node.state) # FIXME(morbo): Add a 'decision' element? diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 155994aee..098eb54cc 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -303,8 +303,10 @@ def _ProcessArgLists(self, node): def _SetDefaultOrNamedAssignArgListSubtype(node): + """Set named assign subtype on elements in a arg list.""" def HasDefaultOrNamedAssignSubtype(node): + """Return True if the arg list has a named assign subtype.""" if isinstance(node, pytree.Leaf): if (format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in pytree_utils.GetNodeAnnotation(node, pytree_utils.Annotation.SUBTYPE, diff --git a/yapftests/main_test.py b/yapftests/main_test.py index d5b0317b3..95e199182 100644 --- a/yapftests/main_test.py +++ b/yapftests/main_test.py @@ -19,12 +19,6 @@ import unittest import yapf -try: - from StringIO import StringIO -except ImportError: # Python 3 - # Note: io.StringIO is different in Python 2, so try for python 2 first. - from io import StringIO - from yapf.yapflib import py3compat @@ -38,7 +32,7 @@ class IO(object): class Buffer(object): def __init__(self): - self.string_io = StringIO() + self.string_io = py3compat.StringIO() def write(self, s): if py3compat.PY3 and isinstance(s, bytes): @@ -71,7 +65,7 @@ def captured_output(): @contextmanager def patched_input(code): - "Monkey patch code as though it were coming from stdin." + """Monkey patch code as though it were coming from stdin.""" def lines(): for line in code.splitlines(): @@ -82,17 +76,17 @@ def patch_raw_input(lines=lines()): return next(lines) try: - raw_input = yapf.py3compat.raw_input + orig_raw_import = yapf.py3compat.raw_input yapf.py3compat.raw_input = patch_raw_input yield finally: - yapf.py3compat.raw_input = raw_input + yapf.py3compat.raw_input = orig_raw_import class RunMainTest(unittest.TestCase): def testShouldHandleYapfError(self): - """run_main should handle YapfError and sys.exit(1)""" + """run_main should handle YapfError and sys.exit(1).""" expected_message = 'yapf: Input filenames did not match any python files\n' sys.argv = ['yapf', 'foo.c'] with captured_output() as (out, err): @@ -110,40 +104,40 @@ def testNoPythonFilesMatched(self): yapf.main(['yapf', 'foo.c']) def testEchoInput(self): - code = "a = 1\nb = 2\n" + code = 'a = 1\nb = 2\n' with patched_input(code): - with captured_output() as (out, err): + with captured_output() as (out, _): ret = yapf.main([]) self.assertEqual(ret, 0) self.assertEqual(out.getvalue(), code) def testEchoInputWithStyle(self): - code = "def f(a = 1):\n return 2*a\n" - chromium_code = "def f(a=1):\n return 2 * a\n" + code = 'def f(a = 1):\n return 2*a\n' + chromium_code = 'def f(a=1):\n return 2 * a\n' with patched_input(code): - with captured_output() as (out, err): + with captured_output() as (out, _): ret = yapf.main(['-', '--style=chromium']) self.assertEqual(ret, 0) self.assertEqual(out.getvalue(), chromium_code) def testEchoBadInput(self): - bad_syntax = " a = 1\n" + bad_syntax = ' a = 1\n' with patched_input(bad_syntax): - with captured_output() as (out, err): - with self.assertRaisesRegexp(SyntaxError, "unexpected indent"): + with captured_output() as (out, _): + with self.assertRaisesRegexp(SyntaxError, 'unexpected indent'): yapf.main([]) def testHelp(self): - with captured_output() as (out, err): + with captured_output() as (out, _): ret = yapf.main(['-', '--style-help', '--style=pep8']) self.assertEqual(ret, 0) help_message = out.getvalue() - self.assertIn("indent_width=4", help_message) - self.assertIn("The number of spaces required before a trailing comment.", + self.assertIn('indent_width=4', help_message) + self.assertIn('The number of spaces required before a trailing comment.', help_message) def testVersion(self): - with captured_output() as (out, err): + with captured_output() as (out, _): ret = yapf.main(['-', '--version']) self.assertEqual(ret, 0) version = 'yapf {}\n'.format(yapf.__version__) diff --git a/yapftests/style_test.py b/yapftests/style_test.py index f752d8ccb..2cfbefed6 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -55,7 +55,7 @@ def _LooksLikePEP8Style(cfg): def _LooksLikeFacebookStyle(cfg): - return (cfg['INDENT_WIDTH'] == 4 and cfg['DEDENT_CLOSING_BRACKETS']) + return cfg['INDENT_WIDTH'] == 4 and cfg['DEDENT_CLOSING_BRACKETS'] class PredefinedStylesByNameTest(unittest.TestCase): diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 8aa402d9c..9509c1af5 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1011,12 +1011,11 @@ def overly_long_function_name( second_argument_makes_the_line_too_long): pass """) - expected_formatted_pep8_code = textwrap.dedent("""\ - def overly_long_function_name( - first_argument_on_the_same_line, \ -second_argument_makes_the_line_too_long): - pass - """) + # expected_formatted_pep8_code = textwrap.dedent("""\ + # def overly_long_function_name( + # first_argument_on_the_same_line, second_argument_makes_the_line_too_long): + # pass + # """) expected_formatted_fb_code = textwrap.dedent("""\ def overly_long_function_name( first_argument_on_the_same_line, second_argument_makes_the_line_too_long From 4a4e460d4e04d73ba5867d0014c8646f6608d3cd Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 31 Jan 2017 14:41:00 -0800 Subject: [PATCH 088/719] Add two knobs for formatting dictionaries and sets - The EACH_DICT_ENTRY_ON_SEPARATE_LINE knob places each dict entry on separate lines if the full dictionary can't fit on a single line. - The `SPLIT_BEFORE_DICT_SET_GENERATOR` knob splits before the `for` part of a dict/set generator. --- CHANGELOG | 8 + README.rst | 14 ++ yapf/yapflib/format_decision_state.py | 204 ++++++++++++++------------ yapf/yapflib/style.py | 12 ++ 4 files changed, 144 insertions(+), 94 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 73adb25b5..fdd0acc33 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,14 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.16.0] UNRELEASED +### Added +- The `EACH_DICT_ENTRY_ON_SEPARATE_LINE` knob indicates that each dictionary + entry should be in separate lines if the full dictionary isn't able to fit on + a single line. +- The `SPLIT_BEFORE_DICT_SET_GENERATOR` knob splits before the `for` part of a + dictionary/set generator. + ## [0.15.2] 2017-01-29 ### Fixed - Don't perform a global split when a named assign is part of a function call diff --git a/README.rst b/README.rst index 81fffadd4..6cbd0ceea 100644 --- a/README.rst +++ b/README.rst @@ -350,6 +350,9 @@ Knobs end_ts=now(), ) # <--- this bracket is dedented and on a separate line +``EACH_DICT_ENTRY_ON_SEPARATE_LINE`` + Place each dictionary entry onto its own line. + ``I18N_COMMENT`` The regex for an internationalization comment. The presence of this comment stops reformatting of that line, because the comments are required to be @@ -399,6 +402,17 @@ Knobs Set to ``True`` to prefer splitting before ``&``, ``|`` or ``^`` rather than after. +``SPLIT_BEFORE_DICT_SET_GENERATOR`` + Split before a dictionary or set generator (comp_for). For example, note + the split before the ``for``: + + .. code-block:: python + + foo = { + variable: 'Hello world, have a nice day!' + for variable in bar if variable != 42 + } + ``SPLIT_BEFORE_FIRST_ARGUMENT`` If an argument / parameter list is going to be split, then split before the first argument. diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 4934769ab..93379e2a1 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -131,13 +131,23 @@ def MustSplit(self): if current.must_break_before: return True - if (previous and (style.Get('DEDENT_CLOSING_BRACKETS') or - style.Get('SPLIT_BEFORE_FIRST_ARGUMENT'))): + if not previous: + return False + + if self.stack[-1].split_before_closing_bracket and current.value in '}]': + # Split before the closing bracket if we can. + return current.node_split_penalty != split_penalty.UNBREAKABLE + + ########################################################################### + # List Splitting + if (style.Get('DEDENT_CLOSING_BRACKETS') or + style.Get('SPLIT_BEFORE_FIRST_ARGUMENT')): bracket = current if current.ClosesScope() else previous if format_token.Subtype.SUBSCRIPT_BRACKET not in bracket.subtypes: if bracket.OpensScope(): if style.Get('COALESCE_BRACKETS'): if current.OpensScope(): + # Prefer to keep all opening brackets together. return False if (not _IsLastScopeInLine(bracket) or @@ -147,23 +157,21 @@ def MustSplit(self): last_token = _LastTokenInLine(bracket.matching_bracket) if not self._FitsOnLine(bracket, last_token): + # Split before the first element if the whole list can't fit on a + # single line. self.stack[-1].split_before_closing_bracket = True return True elif style.Get('DEDENT_CLOSING_BRACKETS') and current.ClosesScope(): + # Split before and dedent the closing bracket. return self.stack[-1].split_before_closing_bracket - if self.stack[-1].split_before_closing_bracket and current.value in '}]': - # Split if we need to split before the closing bracket. - return current.node_split_penalty != split_penalty.UNBREAKABLE - - if not previous: - return False - - # TODO(morbo): This should be controlled with a knob. - if (format_token.Subtype.DICTIONARY_KEY in current.subtypes and + ########################################################################### + # Dict/Set Splitting + if (style.Get('EACH_DICT_ENTRY_ON_SEPARATE_LINE') and + format_token.Subtype.DICTIONARY_KEY in current.subtypes and not current.is_comment): - # Place each dictionary entry on its own line. + # Place each dictionary entry onto its own line. if previous.value == '{' and previous.previous_token: opening = _GetOpeningBracket(previous.previous_token) if (opening and opening.value == '(' and opening.previous_token and @@ -173,49 +181,69 @@ def MustSplit(self): return False return True - # TODO(morbo): This should be controlled with a knob. - if format_token.Subtype.DICT_SET_GENERATOR in current.subtypes: + if (style.Get('SPLIT_BEFORE_DICT_SET_GENERATOR') and + format_token.Subtype.DICT_SET_GENERATOR in current.subtypes): + # Split before a dict/set generator. return True + if (format_token.Subtype.DICTIONARY_VALUE in current.subtypes or + (previous.is_pseudo_paren and previous.value == '(')): + # Split before the dictionary value if we can't fit every dictionary + # entry on its own line. + if not current.OpensScope(): + opening = _GetOpeningBracket(current) + if not self._EachDictEntryFitsOnOneLine(opening): + return True + + if previous.value == '{': + # Split if the dict/set cannot fit on one line and ends in a comma. + closing = previous.matching_bracket + if (not self._FitsOnLine(previous, closing) and + closing.previous_token.value == ','): + self.stack[-1].split_before_closing_bracket = True + return True + + ########################################################################### + # Argument List Splitting if (style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and not current.is_comment and format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in current.subtypes): if (previous.value not in {'=', ':', '*', '**'} and - current.value not in ':=,)'): + current.value not in ':=,)' and + not _IsFunctionDefinition(previous)): # If we're going to split the lines because of named arguments, then we # want to split after the opening bracket as well. But not when this is - # part of function definition. - if not _IsFunctionDefinition(previous): + # part of a function definition. + if previous.value == '(': # Make sure we don't split after the opening bracket if the # continuation indent is greater than the opening bracket: # # a( # b=1, # c=2) - if previous.value == '(': - if (self._FitsOnLine(previous, previous.matching_bracket) and - unwrapped_line.IsSurroundedByBrackets(previous)): - # An argument to a function is a function call with named - # assigns. - return False + if (self._FitsOnLine(previous, previous.matching_bracket) and + unwrapped_line.IsSurroundedByBrackets(previous)): + # An argument to a function is a function call with named + # assigns. + return False - func_start = previous.previous_token - while func_start and func_start.previous_token: - prev = func_start.previous_token - if not prev.is_name and prev.value != '.': - break - func_start = prev + func_start = previous.previous_token + while func_start and func_start.previous_token: + prev = func_start.previous_token + if not prev.is_name and prev.value != '.': + break + func_start = prev - if func_start: - func_name_len = previous.total_length - func_start.total_length - func_name_len += len(func_start.value) - return func_name_len > style.Get('CONTINUATION_INDENT_WIDTH') + if func_start: + func_name_len = previous.total_length - func_start.total_length + func_name_len += len(func_start.value) + return func_name_len > style.Get('CONTINUATION_INDENT_WIDTH') - opening = _GetOpeningBracket(current) - if opening: - arglist_length = (opening.matching_bracket.total_length - - opening.total_length + self.stack[-1].indent) - return arglist_length > self.column_limit + opening = _GetOpeningBracket(current) + if opening: + arglist_length = (opening.matching_bracket.total_length - + opening.total_length + self.stack[-1].indent) + return arglist_length > self.column_limit if style.Get('SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED'): # Split before arguments in a function call or definition if the @@ -226,21 +254,48 @@ def MustSplit(self): if opening.matching_bracket.previous_token.value == ',': return True - if (format_token.Subtype.DICTIONARY_VALUE in current.subtypes or - (previous.is_pseudo_paren and previous.value == '(')): - if not current.OpensScope(): - opening = _GetOpeningBracket(current) - if previous.is_pseudo_paren: - # Split before the dictionary value if we can't fit the whole - # dictionary on one line. - if not self._EachDictEntryFitsOnOneLine(opening): + if current.is_name and previous.value == ',': + # If we have a function call within an argument list and it won't fit on + # the remaining line, but it will fit on a line by itself, then go ahead + # and split before the call. + opening = _GetOpeningBracket(current) + if (opening and opening.value == '(' and opening.previous_token and + opening.previous_token.is_name): + is_func_call = False + token = current + while token: + if token.value == '(': + is_func_call = True + break + if not token.is_name and token.value != '.': + break + token = token.next_token + + if is_func_call: + if not self._FitsOnLine(current, opening.matching_bracket): return True + pprevious = previous.previous_token + if (current.is_name and pprevious and + pprevious.is_name and previous.value == '('): + if (not self._FitsOnLine(previous, previous.matching_bracket) and + _IsFunctionCallWithArguments(current)): + # There is a function call, with more than 1 argument, where the first + # argument is itself a function call with arguments. In this specific + # case, if we split after the first argument's opening '(', then the + # formatting will look bad for the rest of the arguments. E.g.: + # + # outer_function_call(inner_function_call( + # inner_arg1, inner_arg2), + # outer_arg1, outer_arg2) + # + # Instead, enforce a split before that argument to keep things looking + # good. + return True + if (previous.OpensScope() and not current.OpensScope() and format_token.Subtype.SUBSCRIPT_BRACKET not in previous.subtypes): - if not current.is_comment: - pprevious = previous.previous_token if pprevious and not pprevious.is_keyword and not pprevious.is_name: # We want to split if there's a comment in the container. token = current @@ -262,13 +317,8 @@ def MustSplit(self): if not self._FitsOnLine(previous, previous.matching_bracket): return True - if previous.value == '{': - closing = previous.matching_bracket - if (not self._FitsOnLine(previous, closing) and - closing.previous_token.value == ','): - self.stack[-1].split_before_closing_bracket = True - return True - + ########################################################################### + # List Comprehension Splitting if (format_token.Subtype.COMP_FOR in current.subtypes and format_token.Subtype.COMP_FOR not in previous.subtypes): # Split at the beginning of a list comprehension. @@ -284,24 +334,11 @@ def MustSplit(self): if length + self.column > self.column_limit: return True - previous_previous_token = previous.previous_token - if (current.is_name and previous_previous_token and - previous_previous_token.is_name and previous.value == '('): - if not self._FitsOnLine(previous, previous.matching_bracket): - if _IsFunctionCallWithArguments(current): - # There is a function call, with more than 1 argument, where - # the first argument is itself a function call with arguments. - # In this specific case, if we split after the first argument's - # opening '(', then the formatting will look bad for the rest - # of the arguments. Instead, enforce a split before that - # argument to keep things looking good. - return True - elif current.OpensScope(): - if not self._FitsOnLine(current, current.matching_bracket): - # There is a data literal that will need to be split and could mess - # up the formatting. - return True - + ########################################################################### + # Original Formatting Splitting + # These checks rely upon the original formatting. This is in order to + # attempt to keep hand-written code in the same condition as it was before. + # However, this may cause the formatter to fail to be idempotent. if (style.Get('SPLIT_BEFORE_BITWISE_OPERATOR') and current.value in '&|' and previous.lineno < current.lineno): # Retain the split before a bitwise operator. @@ -314,27 +351,6 @@ def MustSplit(self): # original comments were on a separate line. return True - if current.is_name and previous.value == ',': - # If we have a function call within an argument list and it won't fit on - # the remaining line, but it will fit on a line by itself, then go ahead - # and split before the call. - opening = _GetOpeningBracket(current) - if (opening and opening.value == '(' and opening.previous_token and - opening.previous_token.is_name): - is_func_call = False - token = current - while token: - if token.value == '(': - is_func_call = True - break - if not token.is_name and token.value != '.': - break - token = token.next_token - - if is_func_call: - if not self._FitsOnLine(current, opening.matching_bracket): - return True - return False def AddTokenToState(self, newline, dry_run, must_split=False): diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 64a5343e0..128cff80c 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -97,6 +97,8 @@ def method(): start_ts=now()-timedelta(days=3), end_ts=now(), ) # <--- this bracket is dedented and on a separate line"""), + EACH_DICT_ENTRY_ON_SEPARATE_LINE=textwrap.dedent("""\ + Place each dictionary entry onto its own line."""), I18N_COMMENT=textwrap.dedent("""\ The regex for an i18n comment. The presence of this comment stops reformatting of that line, because the comments are required to be @@ -134,6 +136,14 @@ def method(): SPLIT_BEFORE_BITWISE_OPERATOR=textwrap.dedent("""\ Set to True to prefer splitting before '&', '|' or '^' rather than after."""), + SPLIT_BEFORE_DICT_SET_GENERATOR=textwrap.dedent("""\ + Split before a dictionary or set generator (comp_for). For example, note + the split before the 'for': + + foo = { + variable: 'Hello world, have a nice day!' + for variable in bar if variable != 42 + }"""), SPLIT_BEFORE_FIRST_ARGUMENT=textwrap.dedent("""\ If an argument / parameter list is going to be split, then split before the first argument."""), @@ -184,6 +194,7 @@ def CreatePEP8Style(): COLUMN_LIMIT=79, COALESCE_BRACKETS=False, DEDENT_CLOSING_BRACKETS=False, + EACH_DICT_ENTRY_ON_SEPARATE_LINE=True, I18N_COMMENT='', I18N_FUNCTION_CALL='', INDENT_DICTIONARY_VALUE=False, @@ -197,6 +208,7 @@ def CreatePEP8Style(): SPACES_BEFORE_COMMENT=2, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False, SPLIT_BEFORE_BITWISE_OPERATOR=False, + SPLIT_BEFORE_DICT_SET_GENERATOR=True, SPLIT_BEFORE_FIRST_ARGUMENT=False, SPLIT_BEFORE_LOGICAL_OPERATOR=False, SPLIT_BEFORE_NAMED_ASSIGNS=True, From d034ef73c37c384987ee6766c31e369d04200ab1 Mon Sep 17 00:00:00 2001 From: Lars Volker Date: Thu, 2 Feb 2017 01:34:53 +0100 Subject: [PATCH 089/719] Don't print trailing white space with --style-help. --- yapf/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 991c445b2..304af1f2b 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -132,7 +132,7 @@ def main(argv): print('[style]') for option, docstring in sorted(style.Help().items()): for line in docstring.splitlines(): - print('#', line) + print('#', line and ' ' or '', line, sep='') print(option.lower(), '=', style.Get(option), sep='') print() return 0 From 40eee2a451c60ea4e360279c1ea951ed5b94cb35 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 3 Feb 2017 13:55:11 -0800 Subject: [PATCH 090/719] Add converters for new knobs Also reorder so that they're alphabetical. Noticed by @kobras8 Closes #364 --- yapf/yapflib/style.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 128cff80c..ee9bb2830 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -121,15 +121,15 @@ def method(): The number of columns to use for indentation."""), JOIN_MULTIPLE_LINES=textwrap.dedent("""\ Join short lines into one line. E.g., single line 'if' statements."""), + SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=textwrap.dedent("""\ + Insert a space between the ending comma and closing bracket of a list, + etc."""), SPACES_AROUND_POWER_OPERATOR=textwrap.dedent("""\ Use spaces around the power operator."""), SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=textwrap.dedent("""\ Use spaces around default or named assigns."""), SPACES_BEFORE_COMMENT=textwrap.dedent("""\ The number of spaces required before a trailing comment."""), - SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=textwrap.dedent("""\ - Insert a space between the ending comma and closing bracket of a list, - etc."""), SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=textwrap.dedent("""\ Split before arguments if the argument list is terminated by a comma."""), @@ -298,15 +298,16 @@ def _BoolConverter(s): _STYLE_OPTION_VALUE_CONVERTER = dict( ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=_BoolConverter, ALLOW_MULTILINE_LAMBDAS=_BoolConverter, + BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=_BoolConverter, COALESCE_BRACKETS=_BoolConverter, COLUMN_LIMIT=int, + CONTINUATION_INDENT_WIDTH=int, DEDENT_CLOSING_BRACKETS=_BoolConverter, + EACH_DICT_ENTRY_ON_SEPARATE_LINE=_BoolConverter, I18N_COMMENT=str, I18N_FUNCTION_CALL=_StringListConverter, INDENT_DICTIONARY_VALUE=_BoolConverter, INDENT_WIDTH=int, - CONTINUATION_INDENT_WIDTH=int, - BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=_BoolConverter, JOIN_MULTIPLE_LINES=_BoolConverter, SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=_BoolConverter, SPACES_AROUND_POWER_OPERATOR=_BoolConverter, @@ -314,17 +315,18 @@ def _BoolConverter(s): SPACES_BEFORE_COMMENT=int, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter, SPLIT_BEFORE_BITWISE_OPERATOR=_BoolConverter, + SPLIT_BEFORE_DICT_SET_GENERATOR=_BoolConverter, SPLIT_BEFORE_FIRST_ARGUMENT=_BoolConverter, SPLIT_BEFORE_LOGICAL_OPERATOR=_BoolConverter, SPLIT_BEFORE_NAMED_ASSIGNS=_BoolConverter, + SPLIT_PENALTY_AFTER_OPENING_BRACKET=int, SPLIT_PENALTY_AFTER_UNARY_OPERATOR=int, - SPLIT_PENALTY_EXCESS_CHARACTER=int, + SPLIT_PENALTY_BEFORE_IF_EXPR=int, SPLIT_PENALTY_BITWISE_OPERATOR=int, + SPLIT_PENALTY_EXCESS_CHARACTER=int, + SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=int, SPLIT_PENALTY_IMPORT_NAMES=int, SPLIT_PENALTY_LOGICAL_OPERATOR=int, - SPLIT_PENALTY_AFTER_OPENING_BRACKET=int, - SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=int, - SPLIT_PENALTY_BEFORE_IF_EXPR=int, USE_TABS=_BoolConverter,) From f15dead2674f0684072936b1ece1e040120f5ea3 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 4 Feb 2017 04:07:19 -0800 Subject: [PATCH 091/719] Split comma-term dict/set and list makers If there's a comma-terminated dict/set or list maker, then ensure a split even if there's only one entry. Closes #359 --- CHANGELOG | 3 +++ yapf/yapflib/pytree_unwrapper.py | 6 ++---- yapf/yapflib/reformatter.py | 4 ++-- yapftests/reformatter_basic_test.py | 13 +++++++------ yapftests/reformatter_facebook_test.py | 9 +-------- yapftests/reformatter_pep8_test.py | 26 +++++++++++++++++++++++--- 6 files changed, 38 insertions(+), 23 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index fdd0acc33..fa1edc00e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,9 @@ a single line. - The `SPLIT_BEFORE_DICT_SET_GENERATOR` knob splits before the `for` part of a dictionary/set generator. +### Fixed +- Split before all entries in a dict/set or list maker when comma-terminated, + even if there's only one entry. ## [0.15.2] 2017-01-29 ### Fixed diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index 7232b65e7..c67c1c6ea 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -258,7 +258,8 @@ def Visit_import_as_names(self, node): # pylint: disable=invalid-name self.DefaultNodeVisit(node) def Visit_testlist_gexp(self, node): # pylint: disable=invalid-name - _DetermineMustSplitAnnotation(node) + if _ContainsComments(node): + _DetermineMustSplitAnnotation(node) self.DefaultNodeVisit(node) def Visit_arglist(self, node): # pylint: disable=invalid-name @@ -335,9 +336,6 @@ def _AdjustSplitPenalty(uwline): def _DetermineMustSplitAnnotation(node): """Enforce a split in the list if the list ends with a comma.""" if not _ContainsComments(node): - if sum(1 for ch in node.children - if pytree_utils.NodeName(ch) == 'COMMA') < 2: - return if (not isinstance(node.children[-1], pytree.Leaf) or node.children[-1].value != ','): return diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 0eed432c5..8d8fe297d 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -74,8 +74,8 @@ def Reformat(uwlines, verify=False): _RetainHorizontalSpacing(uwline) _RetainVerticalSpacing(uwline, prev_uwline) _EmitLineUnformatted(state) - elif (_CanPlaceOnSingleLine(uwline) and not any(tok.must_split - for tok in uwline.tokens)): + elif _CanPlaceOnSingleLine(uwline) and not any(tok.must_split + for tok in uwline.tokens): # The unwrapped line fits on one line. while state.next_token: state.AddTokenToState(newline=False, dry_run=False) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index f180ace79..28a708012 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -450,10 +450,7 @@ def testOpeningAndClosingBrackets(self): foo( ( 1, 2, 3, ) ) """) expected_formatted_code = textwrap.dedent("""\ - foo(( - 1, - 2, - 3,)) + foo((1, 2, 3,)) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -685,9 +682,13 @@ def testTrailingCommaAndBracket(self): c = [ 42, ] ''') expected_formatted_code = textwrap.dedent('''\ - a = {42,} + a = { + 42, + } b = (42,) - c = [42,] + c = [ + 42, + ] ''') uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_facebook_test.py b/yapftests/reformatter_facebook_test.py index ba2558a5a..470678646 100644 --- a/yapftests/reformatter_facebook_test.py +++ b/yapftests/reformatter_facebook_test.py @@ -107,9 +107,6 @@ def testDedentImportAsNames(self): self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testDedentTestListGexp(self): - # TODO(ambv): Arguably _DetermineMustSplitAnnotation shouldn't enforce - # breaks only on the basis of a trailing comma if the entire thing fits - # in a single line. code = textwrap.dedent("""\ try: pass @@ -121,11 +118,7 @@ def testDedentTestListGexp(self): try: pass except ( - IOError, - OSError, - LookupError, - RuntimeError, - OverflowError, + IOError, OSError, LookupError, RuntimeError, OverflowError, ) as exception: pass """) diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 7a62bce51..49f084173 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -96,12 +96,12 @@ def f(): def testSpaceBetweenEndingCommandAndClosingBracket(self): unformatted_code = textwrap.dedent("""\ - a = [ + a = ( 1, - ] + ) """) expected_formatted_code = textwrap.dedent("""\ - a = [1, ] + a = (1, ) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -309,6 +309,26 @@ def foo(): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testSplitListsAndDictSetMakersIfCommaTerminated(self): + unformatted_code = textwrap.dedent("""\ + DJANGO_TEMPLATES_OPTIONS = {"context_processors": []} + DJANGO_TEMPLATES_OPTIONS = {"context_processors": [],} + x = ["context_processors"] + x = ["context_processors",] + """) + expected_formatted_code = textwrap.dedent("""\ + DJANGO_TEMPLATES_OPTIONS = {"context_processors": []} + DJANGO_TEMPLATES_OPTIONS = { + "context_processors": [], + } + x = ["context_processors"] + x = [ + "context_processors", + ] + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From f8f0e248eceed091259e7d4ad50b62777113be8b Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 4 Feb 2017 04:39:47 -0800 Subject: [PATCH 092/719] Add blank line before class's docstring. Closes #358 --- CHANGELOG | 2 + README.rst | 3 ++ yapf/yapflib/reformatter.py | 5 ++- yapf/yapflib/style.py | 22 ++++++----- yapftests/reformatter_basic_test.py | 58 +++++++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 10 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index fa1edc00e..da2f8c441 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,8 @@ a single line. - The `SPLIT_BEFORE_DICT_SET_GENERATOR` knob splits before the `for` part of a dictionary/set generator. +- The `BLANK_LINE_BEFORE_CLASS_DOCSTRING` knob adds a blank line before a + class's docstring. ### Fixed - Split before all entries in a dict/set or list maker when comma-terminated, even if there's only one entry. diff --git a/README.rst b/README.rst index 6cbd0ceea..6abb80d5e 100644 --- a/README.rst +++ b/README.rst @@ -301,6 +301,9 @@ Knobs def method(): pass +``BLANK_LINE_BEFORE_CLASS_DOCSTRING`` + Insert a blank line before a class-level docstring. + ``COALESCE_BRACKETS`` Do not split consecutive brackets. Only relevant when ``DEDENT_CLOSING_BRACKETS`` is set. For example: diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 8d8fe297d..1d697832c 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -444,8 +444,11 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, return 0 if first_token.is_docstring: + if (prev_uwline.first.value == 'class' and + style.Get('BLANK_LINE_BEFORE_CLASS_DOCSTRING')): + # Enforce a blank line before a class's docstring. + return ONE_BLANK_LINE # The docstring shouldn't have a newline before it. - # TODO(morbo): Add a knob to adjust this. return NO_BLANK_LINES prev_last_token = prev_uwline.last diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index ee9bb2830..0b4a1f48d 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -59,6 +59,8 @@ class Foo: # <------ this blank line def method(): ..."""), + BLANK_LINE_BEFORE_CLASS_DOCSTRING=textwrap.dedent("""\ + Insert a blank line before a class-level docstring."""), COALESCE_BRACKETS=textwrap.dedent("""\ Do not split consecutive brackets. Only relevant when dedent_closing_brackets is set. For example: @@ -191,16 +193,17 @@ def CreatePEP8Style(): return dict( ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=True, ALLOW_MULTILINE_LAMBDAS=False, - COLUMN_LIMIT=79, + BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=False, + BLANK_LINE_BEFORE_CLASS_DOCSTRING=False, COALESCE_BRACKETS=False, + COLUMN_LIMIT=79, + CONTINUATION_INDENT_WIDTH=4, DEDENT_CLOSING_BRACKETS=False, EACH_DICT_ENTRY_ON_SEPARATE_LINE=True, I18N_COMMENT='', I18N_FUNCTION_CALL='', INDENT_DICTIONARY_VALUE=False, INDENT_WIDTH=4, - CONTINUATION_INDENT_WIDTH=4, - BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=False, JOIN_MULTIPLE_LINES=True, SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=True, SPACES_AROUND_POWER_OPERATOR=False, @@ -212,23 +215,23 @@ def CreatePEP8Style(): SPLIT_BEFORE_FIRST_ARGUMENT=False, SPLIT_BEFORE_LOGICAL_OPERATOR=False, SPLIT_BEFORE_NAMED_ASSIGNS=True, + SPLIT_PENALTY_AFTER_OPENING_BRACKET=30, SPLIT_PENALTY_AFTER_UNARY_OPERATOR=10000, - SPLIT_PENALTY_EXCESS_CHARACTER=2600, + SPLIT_PENALTY_BEFORE_IF_EXPR=0, SPLIT_PENALTY_BITWISE_OPERATOR=300, + SPLIT_PENALTY_EXCESS_CHARACTER=2600, + SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=30, SPLIT_PENALTY_IMPORT_NAMES=0, SPLIT_PENALTY_LOGICAL_OPERATOR=300, - SPLIT_PENALTY_AFTER_OPENING_BRACKET=30, - SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=30, - SPLIT_PENALTY_BEFORE_IF_EXPR=0, USE_TABS=False,) def CreateGoogleStyle(): style = CreatePEP8Style() style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False + style['BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'] = True style['COLUMN_LIMIT'] = 80 style['INDENT_WIDTH'] = 4 - style['BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'] = True style['I18N_COMMENT'] = r'#\..*' style['I18N_FUNCTION_CALL'] = ['N_', '_'] style['SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET'] = False @@ -252,8 +255,8 @@ def CreateFacebookStyle(): style['JOIN_MULTIPLE_LINES'] = False style['SPACES_BEFORE_COMMENT'] = 2 style['SPLIT_PENALTY_AFTER_OPENING_BRACKET'] = 0 - style['SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT'] = 30 style['SPLIT_PENALTY_BEFORE_IF_EXPR'] = 30 + style['SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT'] = 30 return style @@ -299,6 +302,7 @@ def _BoolConverter(s): ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=_BoolConverter, ALLOW_MULTILINE_LAMBDAS=_BoolConverter, BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=_BoolConverter, + BLANK_LINE_BEFORE_CLASS_DOCSTRING=_BoolConverter, COALESCE_BRACKETS=_BoolConverter, COLUMN_LIMIT=int, CONTINUATION_INDENT_WIDTH=int, diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 28a708012..b6120993b 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1965,6 +1965,64 @@ def _(): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + def testBlankLineBeforeClassDocstring(self): + unformatted_code = textwrap.dedent('''\ + class A: + + """Does something. + + Also, here are some details. + """ + + def __init__(self): + pass + ''') + expected_code = textwrap.dedent('''\ + class A: + """Does something. + + Also, here are some details. + """ + + def __init__(self): + pass + ''') + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: chromium, \ +blank_line_before_class_docstring: True}')) + unformatted_code = textwrap.dedent('''\ + class A: + + """Does something. + + Also, here are some details. + """ + + def __init__(self): + pass + ''') + expected_formatted_code = textwrap.dedent('''\ + class A: + + """Does something. + + Also, here are some details. + """ + + def __init__(self): + pass + ''') + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + if __name__ == '__main__': unittest.main() From cea0a89c84ff0816c8660d8dcb5fe418b6a3d485 Mon Sep 17 00:00:00 2001 From: Adrian Tejn Kern Date: Sat, 4 Feb 2017 18:22:02 +0100 Subject: [PATCH 093/719] Make unittest work on windows. A new yapftest/utils.py file is created. It provides a NamedTempFile alternative standard libarary 'tempfile.NamedTemporaryFile' which sadly dosn't do what one would want. Utils also provides 'TempFileContents' and 'stdout_redirectory'. --- yapftests/file_resources_test.py | 24 +-- yapftests/style_test.py | 65 +++---- yapftests/utils.py | 113 +++++++++++ yapftests/yapf_test.py | 309 +++++++++++++++---------------- 4 files changed, 300 insertions(+), 211 deletions(-) create mode 100644 yapftests/utils.py diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 7bf6b2735..5236b5468 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -14,10 +14,8 @@ # limitations under the License. """Tests for yapf.file_resources.""" -import contextlib import os import shutil -import sys import tempfile import unittest @@ -25,15 +23,7 @@ from yapf.yapflib import file_resources from yapf.yapflib import py3compat - -@contextlib.contextmanager -def stdout_redirector(stream): # pylint: disable=invalid-name - old_stdout = sys.stdout - sys.stdout = stream - try: - yield - finally: - sys.stdout = old_stdout +from .utils import NamedTempFile, stdout_redirector class GetDefaultStyleForDirTest(unittest.TestCase): @@ -77,7 +67,7 @@ def tearDown(self): shutil.rmtree(self.test_tmpdir) def _make_test_dir(self, name): - fullpath = os.path.join(self.test_tmpdir, name) + fullpath = os.path.normpath(os.path.join(self.test_tmpdir, name)) os.makedirs(fullpath) return fullpath @@ -213,13 +203,13 @@ def tearDownClass(cls): def test_write_to_file(self): s = u'foobar\n' - with tempfile.NamedTemporaryFile(dir=self.test_tmpdir) as testfile: + with NamedTempFile(dir=self.test_tmpdir) as (f, fname): file_resources.WriteReformattedCode( - testfile.name, s, in_place=True, encoding='utf-8') - testfile.flush() + fname, s, in_place=True, encoding='utf-8') + f.flush() - with open(testfile.name) as f: - self.assertEqual(f.read(), s) + with open(fname) as f2: + self.assertEqual(f2.read(), s) def test_write_to_stdout(self): s = u'foobar' diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 2cfbefed6..b6344fd91 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -14,7 +14,6 @@ # limitations under the License. """Tests for yapf.style.""" -import contextlib import shutil import tempfile import textwrap @@ -22,6 +21,8 @@ from yapf.yapflib import style +from .utils import TempFileContents + class UtilsTest(unittest.TestCase): @@ -90,14 +91,6 @@ def testFacebookByName(self): self.assertTrue(_LooksLikeFacebookStyle(cfg)) -@contextlib.contextmanager -def _TempFileContents(dirname, contents): - with tempfile.NamedTemporaryFile(dir=dirname, mode='w') as f: - f.write(contents) - f.flush() - yield f - - class StyleFromFileTest(unittest.TestCase): @classmethod @@ -110,80 +103,80 @@ def tearDownClass(cls): shutil.rmtree(cls.test_tmpdir) def testDefaultBasedOnStyle(self): - cfg = textwrap.dedent('''\ + cfg = textwrap.dedent(u'''\ [style] continuation_indent_width = 20 ''') - with _TempFileContents(self.test_tmpdir, cfg) as f: - cfg = style.CreateStyleFromConfig(f.name) + with TempFileContents(self.test_tmpdir, cfg) as filepath: + cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikePEP8Style(cfg)) self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) def testDefaultBasedOnPEP8Style(self): - cfg = textwrap.dedent('''\ + cfg = textwrap.dedent(u'''\ [style] based_on_style = pep8 continuation_indent_width = 40 ''') - with _TempFileContents(self.test_tmpdir, cfg) as f: - cfg = style.CreateStyleFromConfig(f.name) + with TempFileContents(self.test_tmpdir, cfg) as filepath: + cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikePEP8Style(cfg)) self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 40) def testDefaultBasedOnChromiumStyle(self): - cfg = textwrap.dedent('''\ + cfg = textwrap.dedent(u'''\ [style] based_on_style = chromium continuation_indent_width = 30 ''') - with _TempFileContents(self.test_tmpdir, cfg) as f: - cfg = style.CreateStyleFromConfig(f.name) + with TempFileContents(self.test_tmpdir, cfg) as filepath: + cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikeChromiumStyle(cfg)) self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 30) def testDefaultBasedOnGoogleStyle(self): - cfg = textwrap.dedent('''\ + cfg = textwrap.dedent(u'''\ [style] based_on_style = google continuation_indent_width = 20 ''') - with _TempFileContents(self.test_tmpdir, cfg) as f: - cfg = style.CreateStyleFromConfig(f.name) + with TempFileContents(self.test_tmpdir, cfg) as filepath: + cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikeGoogleStyle(cfg)) self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) def testDefaultBasedOnFacebookStyle(self): - cfg = textwrap.dedent('''\ + cfg = textwrap.dedent(u'''\ [style] based_on_style = facebook continuation_indent_width = 20 ''') - with _TempFileContents(self.test_tmpdir, cfg) as f: - cfg = style.CreateStyleFromConfig(f.name) + with TempFileContents(self.test_tmpdir, cfg) as filepath: + cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikeFacebookStyle(cfg)) self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) def testBoolOptionValue(self): - cfg = textwrap.dedent('''\ + cfg = textwrap.dedent(u'''\ [style] based_on_style = chromium SPLIT_BEFORE_NAMED_ASSIGNS=False split_before_logical_operator = true ''') - with _TempFileContents(self.test_tmpdir, cfg) as f: - cfg = style.CreateStyleFromConfig(f.name) + with TempFileContents(self.test_tmpdir, cfg) as filepath: + cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikeChromiumStyle(cfg)) self.assertEqual(cfg['SPLIT_BEFORE_NAMED_ASSIGNS'], False) self.assertEqual(cfg['SPLIT_BEFORE_LOGICAL_OPERATOR'], True) def testStringListOptionValue(self): - cfg = textwrap.dedent('''\ + cfg = textwrap.dedent(u'''\ [style] based_on_style = chromium I18N_FUNCTION_CALL = N_, V_, T_ ''') - with _TempFileContents(self.test_tmpdir, cfg) as f: - cfg = style.CreateStyleFromConfig(f.name) + with TempFileContents(self.test_tmpdir, cfg) as filepath: + cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikeChromiumStyle(cfg)) self.assertEqual(cfg['I18N_FUNCTION_CALL'], ['N_', 'V_', 'T_']) @@ -193,25 +186,25 @@ def testErrorNoStyleFile(self): style.CreateStyleFromConfig('/8822/xyznosuchfile') def testErrorNoStyleSection(self): - cfg = textwrap.dedent('''\ + cfg = textwrap.dedent(u'''\ [s] indent_width=2 ''') - with _TempFileContents(self.test_tmpdir, cfg) as f: + with TempFileContents(self.test_tmpdir, cfg) as filepath: with self.assertRaisesRegexp(style.StyleConfigError, 'Unable to find section'): - style.CreateStyleFromConfig(f.name) + style.CreateStyleFromConfig(filepath) def testErrorUnknownStyleOption(self): - cfg = textwrap.dedent('''\ + cfg = textwrap.dedent(u'''\ [style] indent_width=2 hummus=2 ''') - with _TempFileContents(self.test_tmpdir, cfg) as f: + with TempFileContents(self.test_tmpdir, cfg) as filepath: with self.assertRaisesRegexp(style.StyleConfigError, 'Unknown style option'): - style.CreateStyleFromConfig(f.name) + style.CreateStyleFromConfig(filepath) class StyleFromCommandLine(unittest.TestCase): diff --git a/yapftests/utils.py b/yapftests/utils.py new file mode 100644 index 000000000..c4302eaa7 --- /dev/null +++ b/yapftests/utils.py @@ -0,0 +1,113 @@ +# -*- coding: utf-8 -*- +# Copyright 2015-2017 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Utilities for tests""" + +import sys +import os +import tempfile +import contextlib +import io + + +@contextlib.contextmanager +def stdout_redirector(stream): # pylint: disable=invalid-name + old_stdout = sys.stdout + sys.stdout = stream + try: + yield + finally: + sys.stdout = old_stdout + + +# NamedTemporaryFile is useless because on Windows the temporary file would be +# created with O_TEMPORARY, which would not allow the file to be opened a +# second time, even by the same process, unless the same flag is used. +# Thus we provide a simplifed version ourselfs. +# +# Note: returns a tuple of (io.file_obj, file_path), instead of a file_obj with a +# .name attribute +if sys.version_info[0] >= 3: + # Note: `buffering` is set to -1 despite documentation of NamedTemporaryFile + # says None. This is probably a problem with the python documenation. + @contextlib.contextmanager + def NamedTempFile(mode='w+b', + buffering=-1, + encoding=None, + errors=None, + newline=None, + suffix=None, + prefix=None, + dir=None, + text=False): + """Context manager creating a new temporary file in text mode. + returns (fileobj, filepath) + """ + (fd, fname) = tempfile.mkstemp( + suffix=suffix, prefix=prefix, dir=dir, text=text) + f = open( + fd, + mode=mode, + buffering=buffering, + encoding=encoding, + errors=errors, + newline=newline) + yield f, fname + f.close() + os.remove(fname) + +else: + # Parameters `suffix` and `prefix` can't be set to None, so use values + # according to Python 2.7 documentation. + @contextlib.contextmanager + def NamedTempFile(mode='w+b', + buffering=-1, + encoding=None, + errors=None, + newline=None, + suffix=None, + prefix=None, + dir=None, + text=False): + if suffix is None: + suffix = '' + if prefix is None: + prefix = 'tmp' + (fd, fname) = tempfile.mkstemp( + suffix=suffix, prefix=prefix, dir=dir, text=text) + f = io.open( + fd, + mode=mode, + buffering=buffering, + encoding=encoding, + errors=errors, + newline=newline) + yield f, fname + f.close() + os.remove(fname) + + +@contextlib.contextmanager +def TempFileContents(dirname, + contents, + encoding='utf-8', + newline='', + suffix=None): + # Note: NamedTempFile properly handles unicode encoding when using mode='w' + with NamedTempFile( + dir=dirname, mode='w', encoding=encoding, newline=newline, + suffix=suffix) as (f, fname): + f.write(contents) + f.flush() + yield fname diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 9509c1af5..5e270c0f0 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -28,6 +28,8 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api +from .utils import TempFileContents, NamedTempFile + ROOT_DIR = os.path.dirname(os.path.abspath(os.path.dirname(__file__))) # Verification is turned off by default, but want to enable it for testing. @@ -76,36 +78,29 @@ def assertCodeEqual(self, expected_code, code): # TODO(sbc): maybe using difflib here to produce easy to read deltas? self.fail(msg) - def _MakeTempFileWithContents(self, filename, contents): - path = os.path.join(self.test_tmpdir, filename) - with py3compat.open_with_encoding(path, mode='w', encoding='utf-8') as f: - f.write(py3compat.unicode(contents)) - return path - def testFormatFile(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent(u"""\ if True: pass """) - f = self._MakeTempFileWithContents('testfile1.py', unformatted_code) - - expected_formatted_code_pep8 = textwrap.dedent("""\ + expected_formatted_code_pep8 = textwrap.dedent(u"""\ if True: pass """) - expected_formatted_code_chromium = textwrap.dedent("""\ + expected_formatted_code_chromium = textwrap.dedent(u"""\ if True: pass """) + with TempFileContents(self.test_tmpdir, unformatted_code) as filepath: + formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') + self.assertCodeEqual(expected_formatted_code_pep8, formatted_code) - formatted_code, _, _ = yapf_api.FormatFile(f, style_config='pep8') - self.assertCodeEqual(expected_formatted_code_pep8, formatted_code) - - formatted_code, _, _ = yapf_api.FormatFile(f, style_config='chromium') - self.assertCodeEqual(expected_formatted_code_chromium, formatted_code) + formatted_code, _, _ = yapf_api.FormatFile( + filepath, style_config='chromium') + self.assertCodeEqual(expected_formatted_code_chromium, formatted_code) def testDisableLinesPattern(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent(u"""\ if a: b # yapf: disable @@ -113,9 +108,7 @@ def testDisableLinesPattern(self): if h: i """) - f = self._MakeTempFileWithContents('testfile1.py', unformatted_code) - - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent(u"""\ if a: b # yapf: disable @@ -123,11 +116,12 @@ def testDisableLinesPattern(self): if h: i """) - formatted_code, _, _ = yapf_api.FormatFile(f, style_config='pep8') - self.assertCodeEqual(expected_formatted_code, formatted_code) + with TempFileContents(self.test_tmpdir, unformatted_code) as filepath: + formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') + self.assertCodeEqual(expected_formatted_code, formatted_code) def testDisableAndReenableLinesPattern(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent(u"""\ if a: b # yapf: disable @@ -136,9 +130,7 @@ def testDisableAndReenableLinesPattern(self): if h: i """) - f = self._MakeTempFileWithContents('testfile1.py', unformatted_code) - - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent(u"""\ if a: b # yapf: disable @@ -147,11 +139,12 @@ def testDisableAndReenableLinesPattern(self): if h: i """) - formatted_code, _, _ = yapf_api.FormatFile(f, style_config='pep8') - self.assertCodeEqual(expected_formatted_code, formatted_code) + with TempFileContents(self.test_tmpdir, unformatted_code) as filepath: + formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') + self.assertCodeEqual(expected_formatted_code, formatted_code) def testDisablePartOfMultilineComment(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent(u"""\ if a: b # This is a multiline comment that disables YAPF. @@ -162,9 +155,8 @@ def testDisablePartOfMultilineComment(self): if h: i """) - f = self._MakeTempFileWithContents('testfile1.py', unformatted_code) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent(u"""\ if a: b # This is a multiline comment that disables YAPF. @@ -175,10 +167,11 @@ def testDisablePartOfMultilineComment(self): if h: i """) - formatted_code, _, _ = yapf_api.FormatFile(f, style_config='pep8') - self.assertCodeEqual(expected_formatted_code, formatted_code) + with TempFileContents(self.test_tmpdir, unformatted_code) as filepath: + formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') + self.assertCodeEqual(expected_formatted_code, formatted_code) - code = textwrap.dedent("""\ + code = textwrap.dedent(u"""\ def foo_function(): # some comment # yapf: disable @@ -190,62 +183,67 @@ def foo_function(): # yapf: enable """) - f = self._MakeTempFileWithContents('testfile1.py', code) - formatted_code, _, _ = yapf_api.FormatFile(f, style_config='pep8') - self.assertCodeEqual(code, formatted_code) + with TempFileContents(self.test_tmpdir, code) as filepath: + formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') + self.assertCodeEqual(code, formatted_code) def testFormatFileLinesSelection(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent(u"""\ if a: b if f: g if h: i """) - f = self._MakeTempFileWithContents('testfile1.py', unformatted_code) - - expected_formatted_code_lines1and2 = textwrap.dedent("""\ + expected_formatted_code_lines1and2 = textwrap.dedent(u"""\ if a: b if f: g if h: i """) - formatted_code, _, _ = yapf_api.FormatFile( - f, style_config='pep8', lines=[(1, 2)]) - self.assertCodeEqual(expected_formatted_code_lines1and2, formatted_code) - - expected_formatted_code_lines3 = textwrap.dedent("""\ + expected_formatted_code_lines3 = textwrap.dedent(u"""\ if a: b if f: g if h: i """) - formatted_code, _, _ = yapf_api.FormatFile( - f, style_config='pep8', lines=[(3, 3)]) - self.assertCodeEqual(expected_formatted_code_lines3, formatted_code) + with TempFileContents(self.test_tmpdir, unformatted_code) as filepath: + formatted_code, _, _ = yapf_api.FormatFile( + filepath, style_config='pep8', lines=[(1, 2)]) + self.assertCodeEqual(expected_formatted_code_lines1and2, formatted_code) + formatted_code, _, _ = yapf_api.FormatFile( + filepath, style_config='pep8', lines=[(3, 3)]) + self.assertCodeEqual(expected_formatted_code_lines3, formatted_code) def testFormatFileDiff(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent(u"""\ if True: pass """) - f = self._MakeTempFileWithContents('testfile1.py', unformatted_code) - diff, _, _ = yapf_api.FormatFile(f, print_diff=True) - self.assertTrue(u'+ pass' in diff) + with TempFileContents(self.test_tmpdir, unformatted_code) as filepath: + diff, _, _ = yapf_api.FormatFile(filepath, print_diff=True) + self.assertTrue(u'+ pass' in diff) def testFormatFileInPlace(self): - unformatted_code = 'True==False\n' - formatted_code = 'True == False\n' - f = self._MakeTempFileWithContents('testfile1.py', unformatted_code) - result, _, _ = yapf_api.FormatFile(f, in_place=True) - self.assertEqual(result, None) - with open(f) as fd: - self.assertCodeEqual(formatted_code, fd.read()) - - self.assertRaises( - ValueError, yapf_api.FormatFile, f, in_place=True, print_diff=True) + unformatted_code = u'True==False\n' + formatted_code = u'True == False\n' + with TempFileContents(self.test_tmpdir, unformatted_code) as filepath: + result, _, _ = yapf_api.FormatFile(filepath, in_place=True) + self.assertEqual(result, None) + with open(filepath) as fd: + if sys.version_info[0] <= 2: + self.assertCodeEqual(formatted_code, fd.read().decode("ascii")) + else: + self.assertCodeEqual(formatted_code, fd.read()) + + self.assertRaises( + ValueError, + yapf_api.FormatFile, + filepath, + in_place=True, + print_diff=True) def testNoFile(self): stream = py3compat.StringIO() @@ -258,39 +256,39 @@ def testNoFile(self): "[Errno 2] No such file or directory: 'not_a_file.py'\n") def testCommentsUnformatted(self): - code = textwrap.dedent("""\ + code = textwrap.dedent(u"""\ foo = [# A list of things # bork 'one', # quark 'two'] # yapf: disable """) - f = self._MakeTempFileWithContents('testfile1.py', code) - formatted_code, _, _ = yapf_api.FormatFile(f, style_config='pep8') - self.assertCodeEqual(code, formatted_code) + with TempFileContents(self.test_tmpdir, code) as filepath: + formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') + self.assertCodeEqual(code, formatted_code) def testDisabledHorizontalFormattingOnNewLine(self): - code = textwrap.dedent("""\ + code = textwrap.dedent(u"""\ # yapf: disable a = [ 1] # yapf: enable """) - f = self._MakeTempFileWithContents('testfile1.py', code) - formatted_code, _, _ = yapf_api.FormatFile(f, style_config='pep8') - self.assertCodeEqual(code, formatted_code) + with TempFileContents(self.test_tmpdir, code) as filepath: + formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') + self.assertCodeEqual(code, formatted_code) def testDisabledSemiColonSeparatedStatements(self): - code = textwrap.dedent("""\ + code = textwrap.dedent(u"""\ # yapf: disable if True: a ; b """) - f = self._MakeTempFileWithContents('testfile1.py', code) - formatted_code, _, _ = yapf_api.FormatFile(f, style_config='pep8') - self.assertCodeEqual(code, formatted_code) + with TempFileContents(self.test_tmpdir, code) as filepath: + formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') + self.assertCodeEqual(code, formatted_code) def testDisabledMultilineStringInDictionary(self): - code = textwrap.dedent("""\ + code = textwrap.dedent(u"""\ # yapf: disable A = [ @@ -304,12 +302,13 @@ def testDisabledMultilineStringInDictionary(self): }, ] """) - f = self._MakeTempFileWithContents('testfile1.py', code) - formatted_code, _, _ = yapf_api.FormatFile(f, style_config='chromium') - self.assertCodeEqual(code, formatted_code) + with TempFileContents(self.test_tmpdir, code) as filepath: + formatted_code, _, _ = yapf_api.FormatFile( + filepath, style_config='chromium') + self.assertCodeEqual(code, formatted_code) def testDisabledWithPrecedingText(self): - code = textwrap.dedent("""\ + code = textwrap.dedent(u"""\ # TODO(fix formatting): yapf: disable A = [ @@ -323,15 +322,17 @@ def testDisabledWithPrecedingText(self): }, ] """) - f = self._MakeTempFileWithContents('testfile1.py', code) - formatted_code, _, _ = yapf_api.FormatFile(f, style_config='chromium') - self.assertCodeEqual(code, formatted_code) + with TempFileContents(self.test_tmpdir, code) as filepath: + formatted_code, _, _ = yapf_api.FormatFile( + filepath, style_config='chromium') + self.assertCodeEqual(code, formatted_code) def testCRLFLineEnding(self): - code = 'class _():\r\n pass\r\n' - f = self._MakeTempFileWithContents('testfile1.py', code) - formatted_code, _, _ = yapf_api.FormatFile(f, style_config='chromium') - self.assertCodeEqual(code, formatted_code) + code = u'class _():\r\n pass\r\n' + with TempFileContents(self.test_tmpdir, code) as filepath: + formatted_code, _, _ = yapf_api.FormatFile( + filepath, style_config='chromium') + self.assertCodeEqual(code, formatted_code) class CommandLineTest(unittest.TestCase): @@ -371,17 +372,13 @@ def testUnicodeEncodingPipedToFile(self): def foo(): print('⇒') """) - - with tempfile.NamedTemporaryFile( - suffix='.py', dir=self.test_tmpdir) as outfile: - with tempfile.NamedTemporaryFile( - suffix='.py', dir=self.test_tmpdir) as testfile: - testfile.write(unformatted_code.encode('UTF-8')) - subprocess.check_call( - YAPF_BINARY + ['--diff', testfile.name], stdout=outfile) + with NamedTempFile(dir=self.test_tmpdir, suffix='.py') as (out, out_path): + with TempFileContents( + self.test_tmpdir, unformatted_code, suffix=".py") as filepath: + subprocess.check_call(YAPF_BINARY + ['--diff', filepath], stdout=out) def testInPlaceReformatting(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent(u"""\ def foo(): x = 37 """) @@ -389,53 +386,34 @@ def foo(): def foo(): x = 37 """) - - with tempfile.NamedTemporaryFile( - suffix='.py', dir=self.test_tmpdir) as testfile: - testfile.write(unformatted_code.encode('UTF-8')) - testfile.seek(0) - - p = subprocess.Popen(YAPF_BINARY + ['--in-place', testfile.name]) + with TempFileContents( + self.test_tmpdir, unformatted_code, suffix=".py") as filepath: + p = subprocess.Popen(YAPF_BINARY + ['--in-place', filepath]) p.wait() - - with io.open(testfile.name, mode='r', newline='') as fd: + with io.open(filepath, mode='r', newline='') as fd: reformatted_code = fd.read() - self.assertEqual(reformatted_code, expected_formatted_code) def testInPlaceReformattingBlank(self): unformatted_code = u'\n\n' expected_formatted_code = u'\n' - - with tempfile.NamedTemporaryFile( - suffix='.py', dir=self.test_tmpdir) as testfile: - testfile.write(unformatted_code.encode('UTF-8')) - testfile.seek(0) - - p = subprocess.Popen(YAPF_BINARY + ['--in-place', testfile.name]) + with TempFileContents( + self.test_tmpdir, unformatted_code, suffix=".py") as filepath: + p = subprocess.Popen(YAPF_BINARY + ['--in-place', filepath]) p.wait() - - with io.open(testfile.name, mode='r', newline='') as fd: + with io.open(filepath, mode='r', encoding='utf-8', newline='') as fd: reformatted_code = fd.read() - self.assertEqual(reformatted_code, expected_formatted_code) def testInPlaceReformattingEmpty(self): unformatted_code = u'' expected_formatted_code = u'' - - with tempfile.NamedTemporaryFile( - suffix='.py', dir=self.test_tmpdir) as testfile: - testfile.write(unformatted_code.encode('UTF-8')) - testfile.seek(0) - - p = subprocess.Popen(YAPF_BINARY + ['--in-place', testfile.name]) + with TempFileContents( + self.test_tmpdir, unformatted_code, suffix=".py") as filepath: + p = subprocess.Popen(YAPF_BINARY + ['--in-place', filepath]) p.wait() - - with py3compat.open_with_encoding( - testfile.name, mode='r', encoding='utf-8') as fd: + with io.open(filepath, mode='r', encoding='utf-8', newline='') as fd: reformatted_code = fd.read() - self.assertEqual(reformatted_code, expected_formatted_code) def testReadFromStdin(self): @@ -481,19 +459,16 @@ def foo(): # trail def foo(): # trail x = 37 """) - - with tempfile.NamedTemporaryFile(dir=self.test_tmpdir, mode='w') as f: - f.write( - textwrap.dedent('''\ - [style] - based_on_style = chromium - SPACES_BEFORE_COMMENT = 4 - ''')) - f.flush() + style_file = textwrap.dedent(u'''\ + [style] + based_on_style = chromium + SPACES_BEFORE_COMMENT = 4 + ''') + with TempFileContents(self.test_tmpdir, style_file) as stylepath: self.assertYapfReformats( unformatted_code, expected_formatted_code, - extra_options=['--style={0}'.format(f.name)]) + extra_options=['--style={0}'.format(stylepath)]) def testReadSingleLineCodeFromStdin(self): unformatted_code = textwrap.dedent("""\ @@ -505,20 +480,17 @@ def testReadSingleLineCodeFromStdin(self): self.assertYapfReformats(unformatted_code, expected_formatted_code) def testEncodingVerification(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent(u"""\ '''The module docstring.''' # -*- coding: utf-8 -*- def f(): x = 37 """) - with tempfile.NamedTemporaryFile( - suffix='.py', dir=self.test_tmpdir) as outfile: - with tempfile.NamedTemporaryFile( - suffix='.py', dir=self.test_tmpdir) as testfile: - testfile.write(unformatted_code.encode('utf-8')) - subprocess.check_call( - YAPF_BINARY + ['--diff', testfile.name], stdout=outfile) + with NamedTempFile(suffix='.py', dir=self.test_tmpdir) as (out, out_path): + with TempFileContents( + self.test_tmpdir, unformatted_code, suffix='.py') as filepath: + subprocess.check_call(YAPF_BINARY + ['--diff', filepath], stdout=out) def testReformattingSpecificLines(self): unformatted_code = textwrap.dedent("""\ @@ -1045,9 +1017,9 @@ def testCoalesceBrackets(self): 'second_argument_of_the_thing': "some thing" }) """) - with tempfile.NamedTemporaryFile(dir=self.test_tmpdir, mode='w') as f: + with NamedTempFile(dir=self.test_tmpdir, mode='w') as (f, f_name): f.write( - textwrap.dedent('''\ + textwrap.dedent(u'''\ [style] based_on_style = facebook column_limit=82 @@ -1057,7 +1029,7 @@ def testCoalesceBrackets(self): self.assertYapfReformats( unformatted_code, expected_formatted_code, - extra_options=['--style={0}'.format(f.name)]) + extra_options=['--style={0}'.format(f_name)]) def testPseudoParenSpaces(self): unformatted_code = textwrap.dedent("""\ @@ -1140,19 +1112,40 @@ def foo_function(): if True: pass """) - with tempfile.NamedTemporaryFile(dir=self.test_tmpdir, mode='w') as f: - f.write( - textwrap.dedent('''\ - [style] - based_on_style = chromium - USE_TABS = true - INDENT_WIDTH=1 - ''')) - f.flush() + style_contents = textwrap.dedent(u'''\ + [style] + based_on_style = chromium + USE_TABS = true + INDENT_WIDTH=1 + ''') + with TempFileContents(self.test_tmpdir, style_contents) as stylepath: + self.assertYapfReformats( + unformatted_code, + expected_formatted_code, + extra_options=['--style={0}'.format(stylepath)]) + + def testStyleOutputRoundTrip(self): + unformatted_code = textwrap.dedent("""\ + def foo_function(): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def foo_function(): + pass + """) + + with NamedTempFile(dir=self.test_tmpdir) as (stylefile, stylepath): + p = subprocess.Popen( + YAPF_BINARY + ["--style-help"], + stdout=stylefile, + stdin=subprocess.PIPE, + stderr=subprocess.PIPE) + reformatted_code, stderrdata = p.communicate() + self.assertEqual(stderrdata, b'') self.assertYapfReformats( unformatted_code, expected_formatted_code, - extra_options=['--style={0}'.format(f.name)]) + extra_options=['--style={0}'.format(stylepath)]) class BadInputTest(unittest.TestCase): From 4f73069e13ebd3eee6fb574b2f4f664ada0d21d2 Mon Sep 17 00:00:00 2001 From: Adrian Tejn Kern Date: Sat, 4 Feb 2017 18:43:42 +0100 Subject: [PATCH 094/719] Python 2 standard/file output fixes. WriteReformattedCode would do newline transformation even though that step has been manually taken care of before that point. It is more of a coincident that the would not happen on python 2. py3compat.EncodeAndWriteToStdout will now on Python 2 try to set the windows stdout to O_BINARY mode before outputting. Otherwise newline transformation would occur. --- yapf/yapflib/file_resources.py | 2 +- yapf/yapflib/py3compat.py | 30 ++++++++++++++++++++++-------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 5f2e3c123..e7f9acdc7 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -93,7 +93,7 @@ def WriteReformattedCode(filename, """ if in_place: with py3compat.open_with_encoding( - filename, mode='w', encoding=encoding) as fd: + filename, mode='w', encoding=encoding, newline='') as fd: fd.write(reformatted_code) else: py3compat.EncodeAndWriteToStdout(reformatted_code) diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py index 2ca5523b5..aa025bf43 100644 --- a/yapf/yapflib/py3compat.py +++ b/yapf/yapflib/py3compat.py @@ -15,9 +15,10 @@ import io import sys +import os -PY3 = sys.version_info[0] == 3 -PY36 = sys.version_info[0] == 3 and sys.version_info[1] >= 6 +PY3 = sys.version_info[0] >= 3 +PY36 = sys.version_info[0] >= 3 and sys.version_info[1] >= 6 if PY3: StringIO = io.StringIO @@ -76,16 +77,29 @@ def EncodeAndWriteToStdout(s, encoding='utf-8'): encoding: (string) The encoding of the string. """ if PY3: - sys.stdout.buffer.write(codecs.encode(s, encoding)) + sys.stdout.buffer.write(s.encode(encoding)) + elif sys.platform == 'win32': + # On python 2 and Windows universal newline transformation will be in + # effect on stdout. Python 2 will not let us avoid the easily because + # it happens based on whether the file handle is opened in O_BINARY or + # O_TEXT state. However we can tell Windows itself to change the current + # mode, and python 2 will follow suit. However we must take care to change + # the mode on the actual external stdout not just the current sys.stdout + # which may have been monkey-patched inside the python environment. + import msvcrt + if sys.__stdout__ is sys.stdout: + msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) + sys.stdout.write(s.encode(encoding)) else: sys.stdout.write(s.encode(encoding)) -def unicode(s): - """Force conversion of s to unicode.""" - if PY3: - return s - else: +if PY3: + unicode = str +else: + + def unicode(s): + """Force conversion of s to unicode.""" return __builtin__.unicode(s, 'utf-8') From d1fe482e9c0538783653374d57e62aec6fc249eb Mon Sep 17 00:00:00 2001 From: Adrian Tejn Kern Date: Sat, 4 Feb 2017 19:21:46 +0100 Subject: [PATCH 095/719] NamedTempFile support for python 3<..<=3.4 --- yapftests/utils.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/yapftests/utils.py b/yapftests/utils.py index c4302eaa7..d8c14dff5 100644 --- a/yapftests/utils.py +++ b/yapftests/utils.py @@ -54,6 +54,11 @@ def NamedTempFile(mode='w+b', """Context manager creating a new temporary file in text mode. returns (fileobj, filepath) """ + if sys.version_info < (3, 5): + if suffix is None: + suffix = '' + if prefix is None: + prefix = 'tmp' (fd, fname) = tempfile.mkstemp( suffix=suffix, prefix=prefix, dir=dir, text=text) f = open( From 4f1cc3da2d13074c14bf22e88b60a9808705142c Mon Sep 17 00:00:00 2001 From: Adrian Tejn Kern Date: Sat, 4 Feb 2017 23:49:42 +0100 Subject: [PATCH 096/719] Simplify utils.py:NamedTempFile to one version --- yapftests/utils.py | 88 +++++++++++++++------------------------------- 1 file changed, 29 insertions(+), 59 deletions(-) diff --git a/yapftests/utils.py b/yapftests/utils.py index d8c14dff5..20bead005 100644 --- a/yapftests/utils.py +++ b/yapftests/utils.py @@ -38,69 +38,39 @@ def stdout_redirector(stream): # pylint: disable=invalid-name # # Note: returns a tuple of (io.file_obj, file_path), instead of a file_obj with a # .name attribute -if sys.version_info[0] >= 3: - # Note: `buffering` is set to -1 despite documentation of NamedTemporaryFile - # says None. This is probably a problem with the python documenation. - @contextlib.contextmanager - def NamedTempFile(mode='w+b', - buffering=-1, - encoding=None, - errors=None, - newline=None, - suffix=None, - prefix=None, - dir=None, - text=False): - """Context manager creating a new temporary file in text mode. - returns (fileobj, filepath) - """ - if sys.version_info < (3, 5): - if suffix is None: - suffix = '' - if prefix is None: - prefix = 'tmp' - (fd, fname) = tempfile.mkstemp( - suffix=suffix, prefix=prefix, dir=dir, text=text) - f = open( - fd, - mode=mode, - buffering=buffering, - encoding=encoding, - errors=errors, - newline=newline) - yield f, fname - f.close() - os.remove(fname) - -else: - # Parameters `suffix` and `prefix` can't be set to None, so use values - # according to Python 2.7 documentation. - @contextlib.contextmanager - def NamedTempFile(mode='w+b', - buffering=-1, - encoding=None, - errors=None, - newline=None, - suffix=None, - prefix=None, - dir=None, - text=False): +# +# Note: `buffering` is set to -1 despite documentation of NamedTemporaryFile +# says None. This is probably a problem with the python documenation. +@contextlib.contextmanager +def NamedTempFile(mode='w+b', + buffering=-1, + encoding=None, + errors=None, + newline=None, + suffix=None, + prefix=None, + dir=None, + text=False): + """Context manager creating a new temporary file in text mode. + returns (fileobj, filepath) + """ + if sys.version_info < (3, 5): # covers also python 2 if suffix is None: suffix = '' if prefix is None: prefix = 'tmp' - (fd, fname) = tempfile.mkstemp( - suffix=suffix, prefix=prefix, dir=dir, text=text) - f = io.open( - fd, - mode=mode, - buffering=buffering, - encoding=encoding, - errors=errors, - newline=newline) - yield f, fname - f.close() - os.remove(fname) + (fd, fname) = tempfile.mkstemp( + suffix=suffix, prefix=prefix, dir=dir, text=text) + f = io.open( + fd, + mode=mode, + buffering=buffering, + encoding=encoding, + errors=errors, + newline=newline) + yield f, fname + f.close() + os.remove(fname) @contextlib.contextmanager From 13c234f85217c521eccbdf7a2ecee40bcaaa72b2 Mon Sep 17 00:00:00 2001 From: Adrian Tejn Kern Date: Sun, 5 Feb 2017 08:36:02 +0100 Subject: [PATCH 097/719] Document Python 2 fixes to stdout --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index da2f8c441..38e327291 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,9 @@ ### Fixed - Split before all entries in a dict/set or list maker when comma-terminated, even if there's only one entry. +- Will now try to set O_BINARY mode on stdout under Windows and Python 2. +- Avoid unneeded newline transformation when writing formatted code to + output on (affects only Python 2) ## [0.15.2] 2017-01-29 ### Fixed From 4ab0bfb2eba592e9bd2764698ab0024e8b075df7 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 5 Feb 2017 18:29:26 -0800 Subject: [PATCH 098/719] Add ALLOW_MULTILINE_DICTIONARY_KEYS knob This allows us to split a dictionary key over multiple lines, which is something pylint doesn't like. --- CHANGELOG | 2 ++ README.rst | 11 ++++++++ setup.py | 8 ++++-- yapf/yapflib/format_decision_state.py | 25 +++++++++++++----- yapf/yapflib/format_token.py | 13 ++++----- yapf/yapflib/reformatter.py | 4 +-- yapf/yapflib/style.py | 10 +++++++ yapf/yapflib/subtype_assigner.py | 1 + yapftests/format_decision_state_test.py | 28 ++++++++++---------- yapftests/reformatter_basic_test.py | 35 +++++++++++++++++++++++-- 10 files changed, 105 insertions(+), 32 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 38e327291..ed619f147 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,8 @@ dictionary/set generator. - The `BLANK_LINE_BEFORE_CLASS_DOCSTRING` knob adds a blank line before a class's docstring. +- The `ALLOW_MULTILINE_DICTIONARY_KEYS` knob allows dictionary keys to span + more than one line. ### Fixed - Split before all entries in a dict/set or list maker when comma-terminated, even if there's only one entry. diff --git a/README.rst b/README.rst index 6abb80d5e..c15464db6 100644 --- a/README.rst +++ b/README.rst @@ -290,6 +290,17 @@ Knobs ``ALLOW_MULTILINE_LAMBDAS`` Allow lambdas to be formatted on more than one line. +``ALLOW_MULTILINE_DICTIONARY_KEYS`` + Allow dictionary keys to exist on multiple lines. For example: + + .. code-block:: python + + x = { + ('this is the first element of a tuple', + 'this is the second element of a tuple'): + value, + } + ``BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF`` Insert a blank line before a ``def`` or ``class`` immediately nested within another ``def`` or ``class``. For example: diff --git a/setup.py b/setup.py index fc8781ef3..c73016b7a 100644 --- a/setup.py +++ b/setup.py @@ -64,5 +64,9 @@ def run(self): 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Quality Assurance', ], - entry_points={'console_scripts': ['yapf = yapf:run_main'],}, - cmdclass={'test': RunTests,},) + entry_points={ + 'console_scripts': ['yapf = yapf:run_main'], + }, + cmdclass={ + 'test': RunTests, + },) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 93379e2a1..65e4c8d9d 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -111,13 +111,27 @@ def __repr__(self): (self.column, repr(self.next_token), self.paren_level, '\n\t'.join(repr(s) for s in self.stack) + ']')) - def CanSplit(self): - """Returns True if the line can be split before the next token.""" + def CanSplit(self, must_split): + """Determine if we can split before the next token. + + Arguments: + must_split: (bool) A newline was required before this token. + + Returns: + True if the line can be split before the next token. + """ current = self.next_token if current.is_pseudo_paren: return False + if (format_token.Subtype.DICTIONARY_KEY_PART in current.subtypes and + format_token.Subtype.DICTIONARY_KEY not in current.subtypes and + not style.Get('ALLOW_MULTILINE_DICTIONARY_KEYS') and not must_split): + # In some situations, a dictionary may be multiline, but pylint doesn't + # like it. So don't allow it unless forced to. + return False + return current.can_break_before def MustSplit(self): @@ -209,8 +223,7 @@ def MustSplit(self): format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in current.subtypes): if (previous.value not in {'=', ':', '*', '**'} and - current.value not in ':=,)' and - not _IsFunctionDefinition(previous)): + current.value not in ':=,)' and not _IsFunctionDefinition(previous)): # If we're going to split the lines because of named arguments, then we # want to split after the opening bracket as well. But not when this is # part of a function definition. @@ -276,8 +289,8 @@ def MustSplit(self): return True pprevious = previous.previous_token - if (current.is_name and pprevious and - pprevious.is_name and previous.value == '('): + if (current.is_name and pprevious and pprevious.is_name and + previous.value == '('): if (not self._FitsOnLine(previous, previous.matching_bracket) and _IsFunctionCallWithArguments(current)): # There is a function call, with more than 1 argument, where the first diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 13d78ff17..ec9f0e466 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -46,12 +46,13 @@ class Subtype(object): KWARGS_STAR_STAR = 9 ASSIGN_OPERATOR = 10 DICTIONARY_KEY = 11 - DICTIONARY_VALUE = 12 - DICT_SET_GENERATOR = 13 - COMP_FOR = 14 - COMP_IF = 15 - FUNC_DEF = 16 - DECORATOR = 17 + DICTIONARY_KEY_PART = 12 + DICTIONARY_VALUE = 13 + DICT_SET_GENERATOR = 14 + COMP_FOR = 15 + COMP_IF = 16 + FUNC_DEF = 17 + DECORATOR = 18 class FormatToken(object): diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 1d697832c..5fd9ca1cc 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -357,10 +357,10 @@ def _AddNextStateToQueue(penalty, previous_node, newline, count, p_queue): Returns: The updated number of elements in the queue. """ - if newline and not previous_node.state.CanSplit(): + must_split = previous_node.state.MustSplit() + if newline and not previous_node.state.CanSplit(must_split): # Don't add a newline if the token cannot be split. return count - must_split = previous_node.state.MustSplit() if not newline and must_split: # Don't add a token we must split but where we aren't splitting. return count diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 0b4a1f48d..63d110a4b 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -51,6 +51,14 @@ def SetGlobalStyle(style): Align closing bracket with visual indentation."""), ALLOW_MULTILINE_LAMBDAS=textwrap.dedent("""\ Allow lambdas to be formatted on more than one line."""), + ALLOW_MULTILINE_DICTIONARY_KEYS=textwrap.dedent("""\ + Allow dictionary keys to exist on multiple lines. For example: + + x = { + ('this is the first element of a tuple', + 'this is the second element of a tuple'): + value, + }"""), BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=textwrap.dedent("""\ Insert a blank line before a 'def' or 'class' immediately nested within another 'def' or 'class'. For example: @@ -193,6 +201,7 @@ def CreatePEP8Style(): return dict( ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=True, ALLOW_MULTILINE_LAMBDAS=False, + ALLOW_MULTILINE_DICTIONARY_KEYS=False, BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=False, BLANK_LINE_BEFORE_CLASS_DOCSTRING=False, COALESCE_BRACKETS=False, @@ -301,6 +310,7 @@ def _BoolConverter(s): _STYLE_OPTION_VALUE_CONVERTER = dict( ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=_BoolConverter, ALLOW_MULTILINE_LAMBDAS=_BoolConverter, + ALLOW_MULTILINE_DICTIONARY_KEYS=_BoolConverter, BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=_BoolConverter, BLANK_LINE_BEFORE_CLASS_DOCSTRING=_BoolConverter, COALESCE_BRACKETS=_BoolConverter, diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 098eb54cc..3e27fbfe5 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -98,6 +98,7 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name # on a single line. _AppendFirstLeafTokenSubtype(child, format_token.Subtype.DICTIONARY_KEY) + _AppendSubtypeRec(child, format_token.Subtype.DICTIONARY_KEY_PART) last_was_colon = pytree_utils.NodeName(child) == 'COLON' def Visit_expr_stmt(self, node): # pylint: disable=invalid-name diff --git a/yapftests/format_decision_state_test.py b/yapftests/format_decision_state_test.py index 5f0979511..1afa32530 100644 --- a/yapftests/format_decision_state_test.py +++ b/yapftests/format_decision_state_test.py @@ -42,42 +42,42 @@ def f(a, b): # Add: 'f' state = format_decision_state.FormatDecisionState(uwline, 0) self.assertEqual('f', state.next_token.value) - self.assertFalse(state.CanSplit()) + self.assertFalse(state.CanSplit(False)) # Add: '(' state.AddTokenToState(False, True) self.assertEqual('(', state.next_token.value) - self.assertFalse(state.CanSplit()) + self.assertFalse(state.CanSplit(False)) self.assertFalse(state.MustSplit()) # Add: 'a' state.AddTokenToState(False, True) self.assertEqual('a', state.next_token.value) - self.assertTrue(state.CanSplit()) + self.assertTrue(state.CanSplit(False)) self.assertFalse(state.MustSplit()) # Add: ',' state.AddTokenToState(False, True) self.assertEqual(',', state.next_token.value) - self.assertFalse(state.CanSplit()) + self.assertFalse(state.CanSplit(False)) self.assertFalse(state.MustSplit()) # Add: 'b' state.AddTokenToState(False, True) self.assertEqual('b', state.next_token.value) - self.assertTrue(state.CanSplit()) + self.assertTrue(state.CanSplit(False)) self.assertFalse(state.MustSplit()) # Add: ')' state.AddTokenToState(False, True) self.assertEqual(')', state.next_token.value) - self.assertTrue(state.CanSplit()) + self.assertTrue(state.CanSplit(False)) self.assertFalse(state.MustSplit()) # Add: ':' state.AddTokenToState(False, True) self.assertEqual(':', state.next_token.value) - self.assertFalse(state.CanSplit()) + self.assertFalse(state.CanSplit(False)) self.assertFalse(state.MustSplit()) clone = state.Clone() @@ -95,37 +95,37 @@ def f(a, b): # Add: 'f' state = format_decision_state.FormatDecisionState(uwline, 0) self.assertEqual('f', state.next_token.value) - self.assertFalse(state.CanSplit()) + self.assertFalse(state.CanSplit(False)) # Add: '(' state.AddTokenToState(True, True) self.assertEqual('(', state.next_token.value) - self.assertFalse(state.CanSplit()) + self.assertFalse(state.CanSplit(False)) # Add: 'a' state.AddTokenToState(True, True) self.assertEqual('a', state.next_token.value) - self.assertTrue(state.CanSplit()) + self.assertTrue(state.CanSplit(False)) # Add: ',' state.AddTokenToState(True, True) self.assertEqual(',', state.next_token.value) - self.assertFalse(state.CanSplit()) + self.assertFalse(state.CanSplit(False)) # Add: 'b' state.AddTokenToState(True, True) self.assertEqual('b', state.next_token.value) - self.assertTrue(state.CanSplit()) + self.assertTrue(state.CanSplit(False)) # Add: ')' state.AddTokenToState(True, True) self.assertEqual(')', state.next_token.value) - self.assertTrue(state.CanSplit()) + self.assertTrue(state.CanSplit(False)) # Add: ':' state.AddTokenToState(True, True) self.assertEqual(':', state.next_token.value) - self.assertFalse(state.CanSplit()) + self.assertFalse(state.CanSplit(False)) clone = state.Clone() self.assertEqual(repr(state), repr(clone)) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index b6120993b..57241225f 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1510,6 +1510,38 @@ def succeeded(self, dddddddddddddd): finally: style.SetGlobalStyle(style.CreateChromiumStyle()) + def testMultilineDictionaryKeys(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{based_on_style: chromium, ' + 'allow_multiline_dictionary_keys: true}')) + unformatted_code = textwrap.dedent("""\ + MAP_WITH_LONG_KEYS = { + ('lorem ipsum', 'dolor sit amet'): + 1, + ('consectetur adipiscing elit.', 'Vestibulum mauris justo, ornare eget dolor eget'): + 2, + ('vehicula convallis nulla. Vestibulum dictum nisl in malesuada finibus.',): + 3 + } + """) + expected_formatted_code = textwrap.dedent("""\ + MAP_WITH_LONG_KEYS = { + ('lorem ipsum', 'dolor sit amet'): + 1, + ('consectetur adipiscing elit.', + 'Vestibulum mauris justo, ornare eget dolor eget'): + 2, + ('vehicula convallis nulla. Vestibulum dictum nisl in malesuada finibus.',): + 3 + } + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + def testStableDictionaryFormatting(self): try: style.SetGlobalStyle( @@ -1992,8 +2024,7 @@ def __init__(self): try: style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: chromium, \ + style.CreateStyleFromConfig('{based_on_style: chromium, \ blank_line_before_class_docstring: True}')) unformatted_code = textwrap.dedent('''\ class A: From 75f0fffb3d60eb77ee7ec250dee0a9bec423d7e7 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 5 Feb 2017 18:29:26 -0800 Subject: [PATCH 099/719] Add ALLOW_MULTILINE_DICTIONARY_KEYS knob This allows us to split a dictionary key over multiple lines, which is something pylint doesn't like. --- CHANGELOG | 2 + README.rst | 11 ++++ setup.py | 8 ++- yapf/yapflib/format_decision_state.py | 25 +++++++-- yapf/yapflib/format_token.py | 13 +++-- yapf/yapflib/py3compat.py | 8 +-- yapf/yapflib/reformatter.py | 4 +- yapf/yapflib/style.py | 10 ++++ yapf/yapflib/subtype_assigner.py | 1 + yapftests/file_resources_test.py | 8 +-- yapftests/format_decision_state_test.py | 28 +++++----- yapftests/reformatter_basic_test.py | 36 +++++++++++- yapftests/style_test.py | 20 +++---- yapftests/utils.py | 24 ++++---- yapftests/yapf_test.py | 74 +++++++++++++------------ 15 files changed, 174 insertions(+), 98 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 38e327291..ed619f147 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,8 @@ dictionary/set generator. - The `BLANK_LINE_BEFORE_CLASS_DOCSTRING` knob adds a blank line before a class's docstring. +- The `ALLOW_MULTILINE_DICTIONARY_KEYS` knob allows dictionary keys to span + more than one line. ### Fixed - Split before all entries in a dict/set or list maker when comma-terminated, even if there's only one entry. diff --git a/README.rst b/README.rst index 6abb80d5e..c15464db6 100644 --- a/README.rst +++ b/README.rst @@ -290,6 +290,17 @@ Knobs ``ALLOW_MULTILINE_LAMBDAS`` Allow lambdas to be formatted on more than one line. +``ALLOW_MULTILINE_DICTIONARY_KEYS`` + Allow dictionary keys to exist on multiple lines. For example: + + .. code-block:: python + + x = { + ('this is the first element of a tuple', + 'this is the second element of a tuple'): + value, + } + ``BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF`` Insert a blank line before a ``def`` or ``class`` immediately nested within another ``def`` or ``class``. For example: diff --git a/setup.py b/setup.py index fc8781ef3..c73016b7a 100644 --- a/setup.py +++ b/setup.py @@ -64,5 +64,9 @@ def run(self): 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Quality Assurance', ], - entry_points={'console_scripts': ['yapf = yapf:run_main'],}, - cmdclass={'test': RunTests,},) + entry_points={ + 'console_scripts': ['yapf = yapf:run_main'], + }, + cmdclass={ + 'test': RunTests, + },) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 93379e2a1..65e4c8d9d 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -111,13 +111,27 @@ def __repr__(self): (self.column, repr(self.next_token), self.paren_level, '\n\t'.join(repr(s) for s in self.stack) + ']')) - def CanSplit(self): - """Returns True if the line can be split before the next token.""" + def CanSplit(self, must_split): + """Determine if we can split before the next token. + + Arguments: + must_split: (bool) A newline was required before this token. + + Returns: + True if the line can be split before the next token. + """ current = self.next_token if current.is_pseudo_paren: return False + if (format_token.Subtype.DICTIONARY_KEY_PART in current.subtypes and + format_token.Subtype.DICTIONARY_KEY not in current.subtypes and + not style.Get('ALLOW_MULTILINE_DICTIONARY_KEYS') and not must_split): + # In some situations, a dictionary may be multiline, but pylint doesn't + # like it. So don't allow it unless forced to. + return False + return current.can_break_before def MustSplit(self): @@ -209,8 +223,7 @@ def MustSplit(self): format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in current.subtypes): if (previous.value not in {'=', ':', '*', '**'} and - current.value not in ':=,)' and - not _IsFunctionDefinition(previous)): + current.value not in ':=,)' and not _IsFunctionDefinition(previous)): # If we're going to split the lines because of named arguments, then we # want to split after the opening bracket as well. But not when this is # part of a function definition. @@ -276,8 +289,8 @@ def MustSplit(self): return True pprevious = previous.previous_token - if (current.is_name and pprevious and - pprevious.is_name and previous.value == '('): + if (current.is_name and pprevious and pprevious.is_name and + previous.value == '('): if (not self._FitsOnLine(previous, previous.matching_bracket) and _IsFunctionCallWithArguments(current)): # There is a function call, with more than 1 argument, where the first diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 13d78ff17..ec9f0e466 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -46,12 +46,13 @@ class Subtype(object): KWARGS_STAR_STAR = 9 ASSIGN_OPERATOR = 10 DICTIONARY_KEY = 11 - DICTIONARY_VALUE = 12 - DICT_SET_GENERATOR = 13 - COMP_FOR = 14 - COMP_IF = 15 - FUNC_DEF = 16 - DECORATOR = 17 + DICTIONARY_KEY_PART = 12 + DICTIONARY_VALUE = 13 + DICT_SET_GENERATOR = 14 + COMP_FOR = 15 + COMP_IF = 16 + FUNC_DEF = 17 + DECORATOR = 18 class FormatToken(object): diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py index aa025bf43..2886c384d 100644 --- a/yapf/yapflib/py3compat.py +++ b/yapf/yapflib/py3compat.py @@ -14,8 +14,8 @@ """Utilities for Python2 / Python3 compatibility.""" import io -import sys import os +import sys PY3 = sys.version_info[0] >= 3 PY36 = sys.version_info[0] >= 3 and sys.version_info[1] >= 6 @@ -86,7 +86,7 @@ def EncodeAndWriteToStdout(s, encoding='utf-8'): # mode, and python 2 will follow suit. However we must take care to change # the mode on the actual external stdout not just the current sys.stdout # which may have been monkey-patched inside the python environment. - import msvcrt + import msvcrt # pylint: disable=g-import-not-at-top if sys.__stdout__ is sys.stdout: msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) sys.stdout.write(s.encode(encoding)) @@ -95,10 +95,10 @@ def EncodeAndWriteToStdout(s, encoding='utf-8'): if PY3: - unicode = str + unicode = str # pylint: disable=redefined-builtin,invalid-name else: - def unicode(s): + def unicode(s): # pylint: disable=invalid-name """Force conversion of s to unicode.""" return __builtin__.unicode(s, 'utf-8') diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 1d697832c..5fd9ca1cc 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -357,10 +357,10 @@ def _AddNextStateToQueue(penalty, previous_node, newline, count, p_queue): Returns: The updated number of elements in the queue. """ - if newline and not previous_node.state.CanSplit(): + must_split = previous_node.state.MustSplit() + if newline and not previous_node.state.CanSplit(must_split): # Don't add a newline if the token cannot be split. return count - must_split = previous_node.state.MustSplit() if not newline and must_split: # Don't add a token we must split but where we aren't splitting. return count diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 0b4a1f48d..63d110a4b 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -51,6 +51,14 @@ def SetGlobalStyle(style): Align closing bracket with visual indentation."""), ALLOW_MULTILINE_LAMBDAS=textwrap.dedent("""\ Allow lambdas to be formatted on more than one line."""), + ALLOW_MULTILINE_DICTIONARY_KEYS=textwrap.dedent("""\ + Allow dictionary keys to exist on multiple lines. For example: + + x = { + ('this is the first element of a tuple', + 'this is the second element of a tuple'): + value, + }"""), BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=textwrap.dedent("""\ Insert a blank line before a 'def' or 'class' immediately nested within another 'def' or 'class'. For example: @@ -193,6 +201,7 @@ def CreatePEP8Style(): return dict( ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=True, ALLOW_MULTILINE_LAMBDAS=False, + ALLOW_MULTILINE_DICTIONARY_KEYS=False, BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=False, BLANK_LINE_BEFORE_CLASS_DOCSTRING=False, COALESCE_BRACKETS=False, @@ -301,6 +310,7 @@ def _BoolConverter(s): _STYLE_OPTION_VALUE_CONVERTER = dict( ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=_BoolConverter, ALLOW_MULTILINE_LAMBDAS=_BoolConverter, + ALLOW_MULTILINE_DICTIONARY_KEYS=_BoolConverter, BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=_BoolConverter, BLANK_LINE_BEFORE_CLASS_DOCSTRING=_BoolConverter, COALESCE_BRACKETS=_BoolConverter, diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 098eb54cc..3e27fbfe5 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -98,6 +98,7 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name # on a single line. _AppendFirstLeafTokenSubtype(child, format_token.Subtype.DICTIONARY_KEY) + _AppendSubtypeRec(child, format_token.Subtype.DICTIONARY_KEY_PART) last_was_colon = pytree_utils.NodeName(child) == 'COLON' def Visit_expr_stmt(self, node): # pylint: disable=invalid-name diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 5236b5468..67e373b4b 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -23,7 +23,7 @@ from yapf.yapflib import file_resources from yapf.yapflib import py3compat -from .utils import NamedTempFile, stdout_redirector +from yapftests import utils class GetDefaultStyleForDirTest(unittest.TestCase): @@ -203,7 +203,7 @@ def tearDownClass(cls): def test_write_to_file(self): s = u'foobar\n' - with NamedTempFile(dir=self.test_tmpdir) as (f, fname): + with utils.NamedTempFile(dirname=self.test_tmpdir) as (f, fname): file_resources.WriteReformattedCode( fname, s, in_place=True, encoding='utf-8') f.flush() @@ -214,7 +214,7 @@ def test_write_to_file(self): def test_write_to_stdout(self): s = u'foobar' stream = BufferedByteStream() if py3compat.PY3 else py3compat.StringIO() - with stdout_redirector(stream): + with utils.stdout_redirector(stream): file_resources.WriteReformattedCode( None, s, in_place=False, encoding='utf-8') self.assertEqual(stream.getvalue(), s) @@ -222,7 +222,7 @@ def test_write_to_stdout(self): def test_write_encoded_to_stdout(self): s = '\ufeff# -*- coding: utf-8 -*-\nresult = "passed"\n' # pylint: disable=anomalous-unicode-escape-in-string stream = BufferedByteStream() if py3compat.PY3 else py3compat.StringIO() - with stdout_redirector(stream): + with utils.stdout_redirector(stream): file_resources.WriteReformattedCode( None, s, in_place=False, encoding='utf-8') self.assertEqual(stream.getvalue(), s) diff --git a/yapftests/format_decision_state_test.py b/yapftests/format_decision_state_test.py index 5f0979511..1afa32530 100644 --- a/yapftests/format_decision_state_test.py +++ b/yapftests/format_decision_state_test.py @@ -42,42 +42,42 @@ def f(a, b): # Add: 'f' state = format_decision_state.FormatDecisionState(uwline, 0) self.assertEqual('f', state.next_token.value) - self.assertFalse(state.CanSplit()) + self.assertFalse(state.CanSplit(False)) # Add: '(' state.AddTokenToState(False, True) self.assertEqual('(', state.next_token.value) - self.assertFalse(state.CanSplit()) + self.assertFalse(state.CanSplit(False)) self.assertFalse(state.MustSplit()) # Add: 'a' state.AddTokenToState(False, True) self.assertEqual('a', state.next_token.value) - self.assertTrue(state.CanSplit()) + self.assertTrue(state.CanSplit(False)) self.assertFalse(state.MustSplit()) # Add: ',' state.AddTokenToState(False, True) self.assertEqual(',', state.next_token.value) - self.assertFalse(state.CanSplit()) + self.assertFalse(state.CanSplit(False)) self.assertFalse(state.MustSplit()) # Add: 'b' state.AddTokenToState(False, True) self.assertEqual('b', state.next_token.value) - self.assertTrue(state.CanSplit()) + self.assertTrue(state.CanSplit(False)) self.assertFalse(state.MustSplit()) # Add: ')' state.AddTokenToState(False, True) self.assertEqual(')', state.next_token.value) - self.assertTrue(state.CanSplit()) + self.assertTrue(state.CanSplit(False)) self.assertFalse(state.MustSplit()) # Add: ':' state.AddTokenToState(False, True) self.assertEqual(':', state.next_token.value) - self.assertFalse(state.CanSplit()) + self.assertFalse(state.CanSplit(False)) self.assertFalse(state.MustSplit()) clone = state.Clone() @@ -95,37 +95,37 @@ def f(a, b): # Add: 'f' state = format_decision_state.FormatDecisionState(uwline, 0) self.assertEqual('f', state.next_token.value) - self.assertFalse(state.CanSplit()) + self.assertFalse(state.CanSplit(False)) # Add: '(' state.AddTokenToState(True, True) self.assertEqual('(', state.next_token.value) - self.assertFalse(state.CanSplit()) + self.assertFalse(state.CanSplit(False)) # Add: 'a' state.AddTokenToState(True, True) self.assertEqual('a', state.next_token.value) - self.assertTrue(state.CanSplit()) + self.assertTrue(state.CanSplit(False)) # Add: ',' state.AddTokenToState(True, True) self.assertEqual(',', state.next_token.value) - self.assertFalse(state.CanSplit()) + self.assertFalse(state.CanSplit(False)) # Add: 'b' state.AddTokenToState(True, True) self.assertEqual('b', state.next_token.value) - self.assertTrue(state.CanSplit()) + self.assertTrue(state.CanSplit(False)) # Add: ')' state.AddTokenToState(True, True) self.assertEqual(')', state.next_token.value) - self.assertTrue(state.CanSplit()) + self.assertTrue(state.CanSplit(False)) # Add: ':' state.AddTokenToState(True, True) self.assertEqual(':', state.next_token.value) - self.assertFalse(state.CanSplit()) + self.assertFalse(state.CanSplit(False)) clone = state.Clone() self.assertEqual(repr(state), repr(clone)) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index b6120993b..18a6324fd 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1510,6 +1510,38 @@ def succeeded(self, dddddddddddddd): finally: style.SetGlobalStyle(style.CreateChromiumStyle()) + def testMultilineDictionaryKeys(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{based_on_style: chromium, ' + 'allow_multiline_dictionary_keys: true}')) + unformatted_code = textwrap.dedent("""\ + MAP_WITH_LONG_KEYS = { + ('lorem ipsum', 'dolor sit amet'): + 1, + ('consectetur adipiscing elit.', 'Vestibulum mauris justo, ornare eget dolor eget'): + 2, + ('vehicula convallis nulla. Vestibulum dictum nisl in malesuada finibus.',): + 3 + } + """) + expected_formatted_code = textwrap.dedent("""\ + MAP_WITH_LONG_KEYS = { + ('lorem ipsum', 'dolor sit amet'): + 1, + ('consectetur adipiscing elit.', + 'Vestibulum mauris justo, ornare eget dolor eget'): + 2, + ('vehicula convallis nulla. Vestibulum dictum nisl in malesuada finibus.',): + 3 + } + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + def testStableDictionaryFormatting(self): try: style.SetGlobalStyle( @@ -1993,8 +2025,8 @@ def __init__(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig( - '{based_on_style: chromium, \ -blank_line_before_class_docstring: True}')) + '{based_on_style: chromium, ' + 'blank_line_before_class_docstring: True}')) unformatted_code = textwrap.dedent('''\ class A: diff --git a/yapftests/style_test.py b/yapftests/style_test.py index b6344fd91..2bbbd508d 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -21,7 +21,7 @@ from yapf.yapflib import style -from .utils import TempFileContents +from yapftests import utils class UtilsTest(unittest.TestCase): @@ -107,7 +107,7 @@ def testDefaultBasedOnStyle(self): [style] continuation_indent_width = 20 ''') - with TempFileContents(self.test_tmpdir, cfg) as filepath: + with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikePEP8Style(cfg)) self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) @@ -118,7 +118,7 @@ def testDefaultBasedOnPEP8Style(self): based_on_style = pep8 continuation_indent_width = 40 ''') - with TempFileContents(self.test_tmpdir, cfg) as filepath: + with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikePEP8Style(cfg)) self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 40) @@ -129,7 +129,7 @@ def testDefaultBasedOnChromiumStyle(self): based_on_style = chromium continuation_indent_width = 30 ''') - with TempFileContents(self.test_tmpdir, cfg) as filepath: + with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikeChromiumStyle(cfg)) self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 30) @@ -140,7 +140,7 @@ def testDefaultBasedOnGoogleStyle(self): based_on_style = google continuation_indent_width = 20 ''') - with TempFileContents(self.test_tmpdir, cfg) as filepath: + with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikeGoogleStyle(cfg)) self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) @@ -151,7 +151,7 @@ def testDefaultBasedOnFacebookStyle(self): based_on_style = facebook continuation_indent_width = 20 ''') - with TempFileContents(self.test_tmpdir, cfg) as filepath: + with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikeFacebookStyle(cfg)) self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) @@ -163,7 +163,7 @@ def testBoolOptionValue(self): SPLIT_BEFORE_NAMED_ASSIGNS=False split_before_logical_operator = true ''') - with TempFileContents(self.test_tmpdir, cfg) as filepath: + with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikeChromiumStyle(cfg)) self.assertEqual(cfg['SPLIT_BEFORE_NAMED_ASSIGNS'], False) @@ -175,7 +175,7 @@ def testStringListOptionValue(self): based_on_style = chromium I18N_FUNCTION_CALL = N_, V_, T_ ''') - with TempFileContents(self.test_tmpdir, cfg) as filepath: + with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikeChromiumStyle(cfg)) self.assertEqual(cfg['I18N_FUNCTION_CALL'], ['N_', 'V_', 'T_']) @@ -190,7 +190,7 @@ def testErrorNoStyleSection(self): [s] indent_width=2 ''') - with TempFileContents(self.test_tmpdir, cfg) as filepath: + with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: with self.assertRaisesRegexp(style.StyleConfigError, 'Unable to find section'): style.CreateStyleFromConfig(filepath) @@ -201,7 +201,7 @@ def testErrorUnknownStyleOption(self): indent_width=2 hummus=2 ''') - with TempFileContents(self.test_tmpdir, cfg) as filepath: + with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: with self.assertRaisesRegexp(style.StyleConfigError, 'Unknown style option'): style.CreateStyleFromConfig(filepath) diff --git a/yapftests/utils.py b/yapftests/utils.py index 20bead005..0ffe8d265 100644 --- a/yapftests/utils.py +++ b/yapftests/utils.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,13 +12,13 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -"""Utilities for tests""" +"""Utilities for tests.""" -import sys -import os -import tempfile import contextlib import io +import os +import sys +import tempfile @contextlib.contextmanager @@ -36,8 +36,8 @@ def stdout_redirector(stream): # pylint: disable=invalid-name # second time, even by the same process, unless the same flag is used. # Thus we provide a simplifed version ourselfs. # -# Note: returns a tuple of (io.file_obj, file_path), instead of a file_obj with a -# .name attribute +# Note: returns a tuple of (io.file_obj, file_path), instead of a file_obj with +# a .name attribute # # Note: `buffering` is set to -1 despite documentation of NamedTemporaryFile # says None. This is probably a problem with the python documenation. @@ -49,18 +49,16 @@ def NamedTempFile(mode='w+b', newline=None, suffix=None, prefix=None, - dir=None, + dirname=None, text=False): - """Context manager creating a new temporary file in text mode. - returns (fileobj, filepath) - """ + """Context manager creating a new temporary file in text mode.""" if sys.version_info < (3, 5): # covers also python 2 if suffix is None: suffix = '' if prefix is None: prefix = 'tmp' (fd, fname) = tempfile.mkstemp( - suffix=suffix, prefix=prefix, dir=dir, text=text) + suffix=suffix, prefix=prefix, dir=dirname, text=text) f = io.open( fd, mode=mode, @@ -81,7 +79,7 @@ def TempFileContents(dirname, suffix=None): # Note: NamedTempFile properly handles unicode encoding when using mode='w' with NamedTempFile( - dir=dirname, mode='w', encoding=encoding, newline=newline, + dirname=dirname, mode='w', encoding=encoding, newline=newline, suffix=suffix) as (f, fname): f.write(contents) f.flush() diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 5e270c0f0..ed94810c8 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -28,7 +28,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -from .utils import TempFileContents, NamedTempFile +from yapftests import utils ROOT_DIR = os.path.dirname(os.path.abspath(os.path.dirname(__file__))) @@ -91,7 +91,7 @@ def testFormatFile(self): if True: pass """) - with TempFileContents(self.test_tmpdir, unformatted_code) as filepath: + with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(expected_formatted_code_pep8, formatted_code) @@ -116,7 +116,7 @@ def testDisableLinesPattern(self): if h: i """) - with TempFileContents(self.test_tmpdir, unformatted_code) as filepath: + with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(expected_formatted_code, formatted_code) @@ -139,7 +139,7 @@ def testDisableAndReenableLinesPattern(self): if h: i """) - with TempFileContents(self.test_tmpdir, unformatted_code) as filepath: + with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(expected_formatted_code, formatted_code) @@ -167,7 +167,7 @@ def testDisablePartOfMultilineComment(self): if h: i """) - with TempFileContents(self.test_tmpdir, unformatted_code) as filepath: + with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(expected_formatted_code, formatted_code) @@ -183,7 +183,7 @@ def foo_function(): # yapf: enable """) - with TempFileContents(self.test_tmpdir, code) as filepath: + with utils.TempFileContents(self.test_tmpdir, code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(code, formatted_code) @@ -209,7 +209,7 @@ def testFormatFileLinesSelection(self): if h: i """) - with TempFileContents(self.test_tmpdir, unformatted_code) as filepath: + with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: formatted_code, _, _ = yapf_api.FormatFile( filepath, style_config='pep8', lines=[(1, 2)]) self.assertCodeEqual(expected_formatted_code_lines1and2, formatted_code) @@ -222,19 +222,19 @@ def testFormatFileDiff(self): if True: pass """) - with TempFileContents(self.test_tmpdir, unformatted_code) as filepath: + with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: diff, _, _ = yapf_api.FormatFile(filepath, print_diff=True) self.assertTrue(u'+ pass' in diff) def testFormatFileInPlace(self): unformatted_code = u'True==False\n' formatted_code = u'True == False\n' - with TempFileContents(self.test_tmpdir, unformatted_code) as filepath: + with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: result, _, _ = yapf_api.FormatFile(filepath, in_place=True) self.assertEqual(result, None) with open(filepath) as fd: if sys.version_info[0] <= 2: - self.assertCodeEqual(formatted_code, fd.read().decode("ascii")) + self.assertCodeEqual(formatted_code, fd.read().decode('ascii')) else: self.assertCodeEqual(formatted_code, fd.read()) @@ -263,7 +263,7 @@ def testCommentsUnformatted(self): # quark 'two'] # yapf: disable """) - with TempFileContents(self.test_tmpdir, code) as filepath: + with utils.TempFileContents(self.test_tmpdir, code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(code, formatted_code) @@ -274,7 +274,7 @@ def testDisabledHorizontalFormattingOnNewLine(self): 1] # yapf: enable """) - with TempFileContents(self.test_tmpdir, code) as filepath: + with utils.TempFileContents(self.test_tmpdir, code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(code, formatted_code) @@ -283,7 +283,7 @@ def testDisabledSemiColonSeparatedStatements(self): # yapf: disable if True: a ; b """) - with TempFileContents(self.test_tmpdir, code) as filepath: + with utils.TempFileContents(self.test_tmpdir, code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(code, formatted_code) @@ -302,7 +302,7 @@ def testDisabledMultilineStringInDictionary(self): }, ] """) - with TempFileContents(self.test_tmpdir, code) as filepath: + with utils.TempFileContents(self.test_tmpdir, code) as filepath: formatted_code, _, _ = yapf_api.FormatFile( filepath, style_config='chromium') self.assertCodeEqual(code, formatted_code) @@ -322,14 +322,14 @@ def testDisabledWithPrecedingText(self): }, ] """) - with TempFileContents(self.test_tmpdir, code) as filepath: + with utils.TempFileContents(self.test_tmpdir, code) as filepath: formatted_code, _, _ = yapf_api.FormatFile( filepath, style_config='chromium') self.assertCodeEqual(code, formatted_code) def testCRLFLineEnding(self): code = u'class _():\r\n pass\r\n' - with TempFileContents(self.test_tmpdir, code) as filepath: + with utils.TempFileContents(self.test_tmpdir, code) as filepath: formatted_code, _, _ = yapf_api.FormatFile( filepath, style_config='chromium') self.assertCodeEqual(code, formatted_code) @@ -372,9 +372,10 @@ def testUnicodeEncodingPipedToFile(self): def foo(): print('⇒') """) - with NamedTempFile(dir=self.test_tmpdir, suffix='.py') as (out, out_path): - with TempFileContents( - self.test_tmpdir, unformatted_code, suffix=".py") as filepath: + with utils.NamedTempFile( + dirname=self.test_tmpdir, suffix='.py') as (out, _): + with utils.TempFileContents( + self.test_tmpdir, unformatted_code, suffix='.py') as filepath: subprocess.check_call(YAPF_BINARY + ['--diff', filepath], stdout=out) def testInPlaceReformatting(self): @@ -386,8 +387,8 @@ def foo(): def foo(): x = 37 """) - with TempFileContents( - self.test_tmpdir, unformatted_code, suffix=".py") as filepath: + with utils.TempFileContents( + self.test_tmpdir, unformatted_code, suffix='.py') as filepath: p = subprocess.Popen(YAPF_BINARY + ['--in-place', filepath]) p.wait() with io.open(filepath, mode='r', newline='') as fd: @@ -397,8 +398,8 @@ def foo(): def testInPlaceReformattingBlank(self): unformatted_code = u'\n\n' expected_formatted_code = u'\n' - with TempFileContents( - self.test_tmpdir, unformatted_code, suffix=".py") as filepath: + with utils.TempFileContents( + self.test_tmpdir, unformatted_code, suffix='.py') as filepath: p = subprocess.Popen(YAPF_BINARY + ['--in-place', filepath]) p.wait() with io.open(filepath, mode='r', encoding='utf-8', newline='') as fd: @@ -408,8 +409,8 @@ def testInPlaceReformattingBlank(self): def testInPlaceReformattingEmpty(self): unformatted_code = u'' expected_formatted_code = u'' - with TempFileContents( - self.test_tmpdir, unformatted_code, suffix=".py") as filepath: + with utils.TempFileContents( + self.test_tmpdir, unformatted_code, suffix='.py') as filepath: p = subprocess.Popen(YAPF_BINARY + ['--in-place', filepath]) p.wait() with io.open(filepath, mode='r', encoding='utf-8', newline='') as fd: @@ -464,7 +465,7 @@ def foo(): # trail based_on_style = chromium SPACES_BEFORE_COMMENT = 4 ''') - with TempFileContents(self.test_tmpdir, style_file) as stylepath: + with utils.TempFileContents(self.test_tmpdir, style_file) as stylepath: self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -487,8 +488,9 @@ def f(): x = 37 """) - with NamedTempFile(suffix='.py', dir=self.test_tmpdir) as (out, out_path): - with TempFileContents( + with utils.NamedTempFile( + suffix='.py', dirname=self.test_tmpdir) as (out, _): + with utils.TempFileContents( self.test_tmpdir, unformatted_code, suffix='.py') as filepath: subprocess.check_call(YAPF_BINARY + ['--diff', filepath], stdout=out) @@ -985,7 +987,8 @@ def overly_long_function_name( """) # expected_formatted_pep8_code = textwrap.dedent("""\ # def overly_long_function_name( - # first_argument_on_the_same_line, second_argument_makes_the_line_too_long): + # first_argument_on_the_same_line, + # second_argument_makes_the_line_too_long): # pass # """) expected_formatted_fb_code = textwrap.dedent("""\ @@ -1017,7 +1020,7 @@ def testCoalesceBrackets(self): 'second_argument_of_the_thing': "some thing" }) """) - with NamedTempFile(dir=self.test_tmpdir, mode='w') as (f, f_name): + with utils.NamedTempFile(dirname=self.test_tmpdir, mode='w') as (f, name): f.write( textwrap.dedent(u'''\ [style] @@ -1029,7 +1032,7 @@ def testCoalesceBrackets(self): self.assertYapfReformats( unformatted_code, expected_formatted_code, - extra_options=['--style={0}'.format(f_name)]) + extra_options=['--style={0}'.format(name)]) def testPseudoParenSpaces(self): unformatted_code = textwrap.dedent("""\ @@ -1118,7 +1121,7 @@ def foo_function(): USE_TABS = true INDENT_WIDTH=1 ''') - with TempFileContents(self.test_tmpdir, style_contents) as stylepath: + with utils.TempFileContents(self.test_tmpdir, style_contents) as stylepath: self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -1134,13 +1137,14 @@ def foo_function(): pass """) - with NamedTempFile(dir=self.test_tmpdir) as (stylefile, stylepath): + with utils.NamedTempFile( + dirname=self.test_tmpdir) as (stylefile, stylepath): p = subprocess.Popen( - YAPF_BINARY + ["--style-help"], + YAPF_BINARY + ['--style-help'], stdout=stylefile, stdin=subprocess.PIPE, stderr=subprocess.PIPE) - reformatted_code, stderrdata = p.communicate() + _, stderrdata = p.communicate() self.assertEqual(stderrdata, b'') self.assertYapfReformats( unformatted_code, From 3cda7f863c2478048be804923da956e0662cd178 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 5 Feb 2017 20:24:46 -0800 Subject: [PATCH 100/719] Bump to v0.16.0 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ed619f147..6eb35257b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.16.0] UNRELEASED +## [0.16.0] 2017-02-05 ### Added - The `EACH_DICT_ENTRY_ON_SEPARATE_LINE` knob indicates that each dictionary entry should be in separate lines if the full dictionary isn't able to fit on diff --git a/yapf/__init__.py b/yapf/__init__.py index 304af1f2b..51265370b 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.15.2' +__version__ = '0.16.0' def main(argv): From 4e31ec2f0802da332ecccda465a358439002234e Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 6 Feb 2017 21:47:39 -0800 Subject: [PATCH 101/719] Ensure splitting of arguments if there's a named assign present. --- CHANGELOG | 4 ++++ yapf/yapflib/format_decision_state.py | 18 +++++------------ yapftests/reformatter_basic_test.py | 9 +++++---- yapftests/reformatter_buganizer_test.py | 27 +++++++++++++++++++++++++ yapftests/utils.py | 5 ++++- 5 files changed, 45 insertions(+), 18 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6eb35257b..27eea1832 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.16.1] UNRELEASED +### Fixed +- Ensure splitting of arguments if there's a named assign present. + ## [0.16.0] 2017-02-05 ### Added - The `EACH_DICT_ENTRY_ON_SEPARATE_LINE` knob indicates that each dictionary diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 65e4c8d9d..397cb7d08 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -125,9 +125,10 @@ def CanSplit(self, must_split): if current.is_pseudo_paren: return False - if (format_token.Subtype.DICTIONARY_KEY_PART in current.subtypes and + if (not must_split and + format_token.Subtype.DICTIONARY_KEY_PART in current.subtypes and format_token.Subtype.DICTIONARY_KEY not in current.subtypes and - not style.Get('ALLOW_MULTILINE_DICTIONARY_KEYS') and not must_split): + not style.Get('ALLOW_MULTILINE_DICTIONARY_KEYS')): # In some situations, a dictionary may be multiline, but pylint doesn't # like it. So don't allow it unless forced to. return False @@ -240,17 +241,8 @@ def MustSplit(self): # assigns. return False - func_start = previous.previous_token - while func_start and func_start.previous_token: - prev = func_start.previous_token - if not prev.is_name and prev.value != '.': - break - func_start = prev - - if func_start: - func_name_len = previous.total_length - func_start.total_length - func_name_len += len(func_start.value) - return func_name_len > style.Get('CONTINUATION_INDENT_WIDTH') + column = self.column - self.stack[-1].last_space + return column >= style.Get('CONTINUATION_INDENT_WIDTH') opening = _GetOpeningBracket(current) if opening: diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 18a6324fd..b0a2cfab5 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1292,10 +1292,11 @@ def fn(): def testIfExpressionWithFunctionCall(self): code = textwrap.dedent("""\ - if x or z.y(a, - c, - aaaaaaaaaaaaaaaaaaaaa=aaaaaaaaaaaaaaaaaa, - bbbbbbbbbbbbbbbbbbbbb=bbbbbbbbbbbbbbbbbb): + if x or z.y( + a, + c, + aaaaaaaaaaaaaaaaaaaaa=aaaaaaaaaaaaaaaaaa, + bbbbbbbbbbbbbbbbbbbbb=bbbbbbbbbbbbbbbbbb): pass """) uwlines = yapf_test_helper.ParseAndUnwrap(code) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 79d064170..f51782b55 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,33 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB35021894(self): + unformatted_code = textwrap.dedent("""\ + def _(): + labelacl = Env(qa={ + 'read': 'name/some-type-of-very-long-name-for-reading-perms', + 'modify': 'name/some-other-type-of-very-long-name-for-modifying' + }, + prod={ + 'read': 'name/some-type-of-very-long-name-for-reading-perms', + 'modify': 'name/some-other-type-of-very-long-name-for-modifying' + }) + """) + expected_formatted_code = textwrap.dedent("""\ + def _(): + labelacl = Env( + qa={ + 'read': 'name/some-type-of-very-long-name-for-reading-perms', + 'modify': 'name/some-other-type-of-very-long-name-for-modifying' + }, + prod={ + 'read': 'name/some-type-of-very-long-name-for-reading-perms', + 'modify': 'name/some-other-type-of-very-long-name-for-modifying' + }) + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB34682902(self): unformatted_code = textwrap.dedent("""\ logging.info("Mean angular velocity norm: %.3f", np.linalg.norm(np.mean(ang_vel_arr, axis=0))) diff --git a/yapftests/utils.py b/yapftests/utils.py index 0ffe8d265..0d4cbff0d 100644 --- a/yapftests/utils.py +++ b/yapftests/utils.py @@ -79,7 +79,10 @@ def TempFileContents(dirname, suffix=None): # Note: NamedTempFile properly handles unicode encoding when using mode='w' with NamedTempFile( - dirname=dirname, mode='w', encoding=encoding, newline=newline, + dirname=dirname, + mode='w', + encoding=encoding, + newline=newline, suffix=suffix) as (f, fname): f.write(contents) f.flush() From 0a7960d22088d40dc04ea785b2198a4e297f3820 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 6 Feb 2017 22:58:05 -0800 Subject: [PATCH 102/719] Prefer to coalesce opening brackets. --- CHANGELOG | 2 ++ yapf/yapflib/format_decision_state.py | 9 ++++++++- yapftests/reformatter_buganizer_test.py | 15 +++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 27eea1832..ca340a800 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,8 @@ ## [0.16.1] UNRELEASED ### Fixed - Ensure splitting of arguments if there's a named assign present. +- Prefer to coalesce opening brackets if it's not at the beginning of a + function call. ## [0.16.0] 2017-02-05 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 397cb7d08..98c1178fd 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -461,12 +461,19 @@ def _AddTokenOnNewline(self, dry_run, must_split): # Add a penalty for each increasing newline we add, but don't penalize for # splitting before an if-expression or list comprehension. - if not must_split and current.value not in {'if', 'for'}: + if current.value not in {'if', 'for'}: last = self.stack[-1] last.num_line_splits += 1 penalty += (style.Get('SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT') * last.num_line_splits) + if current.OpensScope() and previous.OpensScope(): + # Prefer to keep opening brackets coalesced (unless it's at the beginning + # of a function call). + pprev = previous.previous_token + if not pprev or not pprev.is_name: + penalty += 10 + return penalty + 10 def _GetNewlineColumn(self): diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index f51782b55..01b26e715 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,21 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB31063453(self): + unformatted_code = textwrap.dedent("""\ + def _(): + while ((not mpede_proc) or ((time_time() - last_modified) < FLAGS_boot_idle_timeout)): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def _(): + while ((not mpede_proc) or + ((time_time() - last_modified) < FLAGS_boot_idle_timeout)): + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB35021894(self): unformatted_code = textwrap.dedent("""\ def _(): From 05a3c8c4cb0009290f2825ef4fd77c1fffc2986b Mon Sep 17 00:00:00 2001 From: srinivasanramaraju Date: Tue, 14 Feb 2017 00:06:58 -0800 Subject: [PATCH 103/719] Import Typo in Example yapf_api is inside yapflib. It will throw import error on trying to import yapf.yapf_api. So, It should be yapf.yapflib.yapf_api --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index c15464db6..a05a072d8 100644 --- a/README.rst +++ b/README.rst @@ -219,7 +219,7 @@ share several arguments which are described below: .. code-block:: python - >>> from yapf.yapf_api import FormatCode # reformat a string of code + >>> from yapf.yapflib.yapf_api import FormatCode # reformat a string of code >>> FormatCode("f ( a = 1, b = 2 )") 'f(a=1, b=2)\n' @@ -262,7 +262,7 @@ the diff, the default is ````. .. code-block:: python - >>> from yapf.yapf_api import FormatFile # reformat a file + >>> from yapf.yapflib.yapf_api import FormatFile # reformat a file >>> print(open("foo.py").read()) # contents of file a==b From 9da9d959ecec69c0fbf986ad95da8b7d577a9143 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 14 Feb 2017 18:40:43 -0800 Subject: [PATCH 104/719] Improve performance of FormatDecisionState object copying --- CHANGELOG | 3 +++ yapf/yapflib/format_decision_state.py | 23 +++++++++++++++-------- yapf/yapflib/reformatter.py | 3 +++ yapftests/format_decision_state_test.py | 7 +++++-- 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ca340a800..71246f17f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,9 @@ # This project adheres to [Semantic Versioning](http://semver.org/). ## [0.16.1] UNRELEASED +### Changed +- Improved performance of cloning the format decision state object. This + improved the time in one *large* case from 273.485s to 234.652s. ### Fixed - Ensure splitting of arguments if there's a named assign present. - Prefer to coalesce opening brackets if it's not at the beginning of a diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 98c1178fd..2e84f61d4 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -26,8 +26,6 @@ FormatDecisionState: main class exported by this module. """ -import copy - from yapf.yapflib import format_token from yapf.yapflib import split_penalty from yapf.yapflib import style @@ -80,11 +78,20 @@ def __init__(self, line, first_indent): self.newline = False self.previous = None self.column_limit = style.Get('COLUMN_LIMIT') - self._MoveStateToNextToken() def Clone(self): - new = copy.copy(self) - new.stack = [copy.copy(state) for state in self.stack] + new = FormatDecisionState(self.line, self.first_indent) + new.next_token = self.next_token + new.column = self.column + new.line = self.line + new.paren_level = self.paren_level + new.start_of_line_level = self.start_of_line_level + new.lowest_level_on_line = self.lowest_level_on_line + new.ignore_stack_for_comparison = self.ignore_stack_for_comparison + new.first_indent = self.first_indent + new.newline = self.newline + new.previous = self.previous + new.stack = [state.Clone() for state in self.stack] return new def __eq__(self, other): @@ -379,7 +386,7 @@ def AddTokenToState(self, newline, dry_run, must_split=False): else: self._AddTokenOnCurrentLine(dry_run) - return self._MoveStateToNextToken() + penalty + return self.MoveStateToNextToken() + penalty def _AddTokenOnCurrentLine(self, dry_run): """Puts the token on the current line. @@ -515,7 +522,7 @@ def _GetNewlineColumn(self): return top_of_stack.indent - def _MoveStateToNextToken(self): + def MoveStateToNextToken(self): """Calculate format decision state information and move onto the next token. Before moving onto the next token, we first calculate the format decision @@ -717,7 +724,7 @@ def __init__(self, indent, last_space): self.split_before_closing_bracket = False self.num_line_splits = 0 - def __copy__(self): + def Clone(self): state = _ParenState(self.indent, self.last_space) state.closing_scope_indent = self.closing_scope_indent state.split_before_closing_bracket = self.split_before_closing_bracket diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 5fd9ca1cc..587db4f6d 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -22,6 +22,7 @@ from __future__ import unicode_literals import collections +import copy import heapq import re @@ -56,6 +57,7 @@ def Reformat(uwlines, verify=False): indent_amt = indent_width * uwline.depth state = format_decision_state.FormatDecisionState(uwline, indent_amt) + state.MoveStateToNextToken() if not uwline.disable: if uwline.first.is_comment: @@ -84,6 +86,7 @@ def Reformat(uwlines, verify=False): # Failsafe mode. If there isn't a solution to the line, then just emit # it as is. state = format_decision_state.FormatDecisionState(uwline, indent_amt) + state.MoveStateToNextToken() _RetainHorizontalSpacing(uwline) _RetainVerticalSpacing(uwline, prev_uwline) _EmitLineUnformatted(state) diff --git a/yapftests/format_decision_state_test.py b/yapftests/format_decision_state_test.py index 1afa32530..c925d1db3 100644 --- a/yapftests/format_decision_state_test.py +++ b/yapftests/format_decision_state_test.py @@ -13,6 +13,7 @@ # limitations under the License. """Tests for yapf.format_decision_state.""" +import copy import textwrap import unittest @@ -41,6 +42,7 @@ def f(a, b): # Add: 'f' state = format_decision_state.FormatDecisionState(uwline, 0) + state.MoveStateToNextToken() self.assertEqual('f', state.next_token.value) self.assertFalse(state.CanSplit(False)) @@ -80,7 +82,7 @@ def f(a, b): self.assertFalse(state.CanSplit(False)) self.assertFalse(state.MustSplit()) - clone = state.Clone() + clone = copy.copy(state) self.assertEqual(repr(state), repr(clone)) def testSimpleFunctionDefWithSplitting(self): @@ -94,6 +96,7 @@ def f(a, b): # Add: 'f' state = format_decision_state.FormatDecisionState(uwline, 0) + state.MoveStateToNextToken() self.assertEqual('f', state.next_token.value) self.assertFalse(state.CanSplit(False)) @@ -127,7 +130,7 @@ def f(a, b): self.assertEqual(':', state.next_token.value) self.assertFalse(state.CanSplit(False)) - clone = state.Clone() + clone = copy.copy(state) self.assertEqual(repr(state), repr(clone)) From 6605d2a973ae9c8d70c160b8c0bcc72ec942e8fd Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 15 Feb 2017 22:03:18 -0800 Subject: [PATCH 105/719] Relax the requirement that a named argument be on a single line. Going over the column limit is more a problem for pylint. --- CHANGELOG | 3 + yapf/yapflib/split_penalty.py | 166 ++++++++++++++-------------- yapftests/reformatter_basic_test.py | 3 +- 3 files changed, 90 insertions(+), 82 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 71246f17f..1c434c937 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,9 @@ ### Changed - Improved performance of cloning the format decision state object. This improved the time in one *large* case from 273.485s to 234.652s. +- Relax the requirement that a named argument needs to be on one line. Going + over the column limit is more of an issue to pylint than putting named args + on multiple lines. ### Fixed - Ensure splitting of arguments if there's a named assign present. - Prefer to coalesce opening brackets if it's not at the beginning of a diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 5ebdf7346..7fffeb182 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -67,12 +67,12 @@ def Visit_classdef(self, node): # pylint: disable=invalid-name # classdef ::= 'class' NAME ['(' [arglist] ')'] ':' suite # # NAME - self._SetUnbreakable(node.children[1]) + _SetUnbreakable(node.children[1]) if len(node.children) > 4: # opening '(' - self._SetUnbreakable(node.children[2]) + _SetUnbreakable(node.children[2]) # ':' - self._SetUnbreakable(node.children[-2]) + _SetUnbreakable(node.children[-2]) self.DefaultNodeVisit(node) def Visit_funcdef(self, node): # pylint: disable=invalid-name @@ -83,7 +83,7 @@ def Visit_funcdef(self, node): # pylint: disable=invalid-name colon_idx = 1 while pytree_utils.NodeName(node.children[colon_idx]) == 'simple_stmt': colon_idx += 1 - self._SetUnbreakable(node.children[colon_idx]) + _SetUnbreakable(node.children[colon_idx]) arrow_idx = -1 while colon_idx < len(node.children): if isinstance(node.children[colon_idx], pytree.Leaf): @@ -92,20 +92,20 @@ def Visit_funcdef(self, node): # pylint: disable=invalid-name if node.children[colon_idx].value == '->': arrow_idx = colon_idx colon_idx += 1 - self._SetUnbreakable(node.children[colon_idx]) + _SetUnbreakable(node.children[colon_idx]) self.DefaultNodeVisit(node) if arrow_idx > 0: pytree_utils.SetNodeAnnotation( _LastChildNode(node.children[arrow_idx - 1]), pytree_utils.Annotation.SPLIT_PENALTY, 0) - self._SetUnbreakable(node.children[arrow_idx]) - self._SetStronglyConnected(node.children[arrow_idx + 1]) + _SetUnbreakable(node.children[arrow_idx]) + _SetStronglyConnected(node.children[arrow_idx + 1]) def Visit_lambdef(self, node): # pylint: disable=invalid-name # lambdef ::= 'lambda' [varargslist] ':' test # Loop over the lambda up to and including the colon. if style.Get('ALLOW_MULTILINE_LAMBDAS'): - self._SetStronglyConnected(node) + _SetStronglyConnected(node) else: self._SetUnbreakableOnChildren(node) @@ -114,9 +114,9 @@ def Visit_parameters(self, node): # pylint: disable=invalid-name self.DefaultNodeVisit(node) # Can't break before the opening paren of a parameter list. - self._SetUnbreakable(node.children[0]) + _SetUnbreakable(node.children[0]) if not style.Get('DEDENT_CLOSING_BRACKETS'): - self._SetStronglyConnected(node.children[-1]) + _SetStronglyConnected(node.children[-1]) def Visit_argument(self, node): # pylint: disable=invalid-name # argument ::= test [comp_for] | test '=' test # Really [keyword '='] test @@ -126,8 +126,8 @@ def Visit_argument(self, node): # pylint: disable=invalid-name while index < len(node.children) - 1: next_child = node.children[index + 1] if isinstance(next_child, pytree.Leaf) and next_child.value == '=': - self._SetUnbreakable(_FirstChildNode(node.children[index + 1])) - self._SetUnbreakable(_FirstChildNode(node.children[index + 2])) + _SetStronglyConnected(_FirstChildNode(node.children[index + 1])) + _SetStronglyConnected(_FirstChildNode(node.children[index + 2])) index += 1 def Visit_dotted_name(self, node): # pylint: disable=invalid-name @@ -143,7 +143,7 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name if pytree_utils.NodeName(child) == 'COLON': # This is a key to a dictionary. We don't want to split the key if at # all possible. - self._SetStronglyConnected(child) + _SetStronglyConnected(child) def Visit_trailer(self, node): # pylint: disable=invalid-name # trailer ::= '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME @@ -162,14 +162,14 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name if name == 'power': if pytree_utils.NodeName(node.children[1].children[0]) != 'atom': # Don't split an argument list with one element if at all possible. - self._SetStronglyConnected(node.children[1], node.children[2]) + _SetStronglyConnected(node.children[1], node.children[2]) pytree_utils.SetNodeAnnotation( _FirstChildNode(node.children[1]), pytree_utils.Annotation.SPLIT_PENALTY, ONE_ELEMENT_ARGUMENT) elif (pytree_utils.NodeName(node.children[0]) == 'LSQB' and (name.endswith('_test') or name.endswith('_expr'))): - self._SetStronglyConnected(node.children[1].children[0]) - self._SetStronglyConnected(node.children[1].children[2]) + _SetStronglyConnected(node.children[1].children[0]) + _SetStronglyConnected(node.children[1].children[2]) # Still allow splitting around the operator. split_before = ((name.endswith('_test') and @@ -186,13 +186,13 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name pytree_utils.Annotation.SPLIT_PENALTY, 0) # Don't split the ending bracket of a subscript list. - self._SetVeryStronglyConnected(node.children[-1]) + _SetVeryStronglyConnected(node.children[-1]) elif name not in { 'arglist', 'argument', 'term', 'or_test', 'and_test', 'comparison', 'atom' }: # Don't split an argument list with one element if at all possible. - self._SetStronglyConnected(node.children[1], node.children[2]) + _SetStronglyConnected(node.children[1], node.children[2]) def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring # power ::= atom trailer* ['**' factor] @@ -204,7 +204,7 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring pytree_utils.NodeName(node.children[1]) == 'trailer'): # children[1] itself is a whole trailer: we don't want to # mark all of it as unbreakable, only its first token: (, [ or . - self._SetUnbreakable(node.children[1].children[0]) + _SetUnbreakable(node.children[1].children[0]) # A special case when there are more trailers in the sequence. Given: # atom tr1 tr2 @@ -224,8 +224,8 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring # atom tr1() tr2 # It may be necessary (though undesirable) to split up a previous # function call's parentheses to the next line. - self._SetStronglyConnected(prev_trailer.children[-1]) - self._SetStronglyConnected(cur_trailer.children[0]) + _SetStronglyConnected(prev_trailer.children[-1]) + _SetStronglyConnected(cur_trailer.children[0]) prev_trailer_idx = cur_trailer_idx else: break @@ -242,7 +242,7 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring subtypes = pytree_utils.GetNodeAnnotation( trailer.children[0], pytree_utils.Annotation.SUBTYPE) if subtypes and format_token.Subtype.SUBSCRIPT_BRACKET in subtypes: - self._SetStronglyConnected(_FirstChildNode(trailer.children[1])) + _SetStronglyConnected(_FirstChildNode(trailer.children[1])) last_child_node = _LastChildNode(trailer) if last_child_node.value.strip().startswith('#'): @@ -250,7 +250,7 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring if not style.Get('DEDENT_CLOSING_BRACKETS'): if _LastChildNode(last_child_node.prev_sibling).value != ',': if last_child_node.value == ']': - self._SetUnbreakable(last_child_node) + _SetUnbreakable(last_child_node) else: pytree_utils.SetNodeAnnotation( last_child_node, pytree_utils.Annotation.SPLIT_PENALTY, @@ -259,12 +259,12 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring if _FirstChildNode(trailer).lineno == last_child_node.lineno: # If the trailer was originally on one line, then try to keep it # like that. - self._SetExpressionPenalty(trailer, CONTIGUOUS_LIST) + _SetExpressionPenalty(trailer, CONTIGUOUS_LIST) else: # If the trailer's children are '()', then make it a strongly # connected region. It's sometimes necessary, though undesirable, to # split the two. - self._SetStronglyConnected(trailer.children[-1]) + _SetStronglyConnected(trailer.children[-1]) # If the original source has a "builder" style calls, then we should allow # the reformatter to retain that. @@ -272,14 +272,14 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring def Visit_subscript(self, node): # pylint: disable=invalid-name # subscript ::= test | [test] ':' [test] [sliceop] - self._SetStronglyConnected(*node.children) + _SetStronglyConnected(*node.children) self.DefaultNodeVisit(node) def Visit_comp_for(self, node): # pylint: disable=invalid-name # comp_for ::= 'for' exprlist 'in' testlist_safe [comp_iter] pytree_utils.SetNodeAnnotation( _FirstChildNode(node), pytree_utils.Annotation.SPLIT_PENALTY, 0) - self._SetStronglyConnected(*node.children[1:]) + _SetStronglyConnected(*node.children[1:]) self.DefaultNodeVisit(node) def Visit_comp_if(self, node): # pylint: disable=invalid-name @@ -287,13 +287,13 @@ def Visit_comp_if(self, node): # pylint: disable=invalid-name pytree_utils.SetNodeAnnotation(node.children[0], pytree_utils.Annotation.SPLIT_PENALTY, style.Get('SPLIT_PENALTY_BEFORE_IF_EXPR')) - self._SetStronglyConnected(*node.children[1:]) + _SetStronglyConnected(*node.children[1:]) self.DefaultNodeVisit(node) def Visit_not_test(self, node): # pylint: disable=invalid-name # not_test ::= 'not' not_test | comparison self.DefaultNodeVisit(node) - self._SetExpressionPenalty(node, NOT_TEST) + _SetExpressionPenalty(node, NOT_TEST) def Visit_comparison(self, node): # pylint: disable=invalid-name # comparison ::= expr (comp_op expr)* @@ -306,17 +306,17 @@ def Visit_comparison(self, node): # pylint: disable=invalid-name _FirstChildNode(node.children[2]), pytree_utils.Annotation.SPLIT_PENALTY, STRONGLY_CONNECTED) else: - self._SetExpressionPenalty(node, COMPARISON_EXPRESSION) + _SetExpressionPenalty(node, COMPARISON_EXPRESSION) def Visit_arith_expr(self, node): # pylint: disable=invalid-name # arith_expr ::= term (('+'|'-') term)* self.DefaultNodeVisit(node) - self._SetExpressionPenalty(node, ARITHMETIC_EXPRESSION) + _SetExpressionPenalty(node, ARITHMETIC_EXPRESSION) def Visit_term_expr(self, node): # pylint: disable=invalid-name # term ::= factor (('*'|'@'|'/'|'%'|'//') factor)* self.DefaultNodeVisit(node) - self._SetExpressionPenalty(node, TERM_EXPRESSION) + _SetExpressionPenalty(node, TERM_EXPRESSION) def Visit_atom(self, node): # pylint: disable=invalid-name # atom ::= ('(' [yield_expr|testlist_gexp] ')' @@ -325,7 +325,7 @@ def Visit_atom(self, node): # pylint: disable=invalid-name self.DefaultNodeVisit(node) if node.children[0].value == '(': if node.children[0].lineno == node.children[-1].lineno: - self._SetExpressionPenalty(node, CONTIGUOUS_LIST) + _SetExpressionPenalty(node, CONTIGUOUS_LIST) if node.children[-1].value == ')': if pytree_utils.NodeName(node.parent) == 'if_stmt': pytree_utils.SetNodeAnnotation(node.children[-1], @@ -340,59 +340,63 @@ def Visit_atom(self, node): # pylint: disable=invalid-name lbracket = node.children[0] rbracket = node.children[-1] if len(node.children) == 2: - self._SetUnbreakable(node.children[-1]) + _SetUnbreakable(node.children[-1]) elif (rbracket.value in ']}' and lbracket.get_lineno() == rbracket.get_lineno() and rbracket.column - lbracket.column < style.Get('COLUMN_LIMIT')): - self._SetStronglyConnected(*node.children[1:]) + _SetStronglyConnected(*node.children[1:]) ############################################################################ # Helper methods that set the annotations. - def _SetUnbreakable(self, node): - """Set an UNBREAKABLE penalty annotation for the given node.""" - _RecAnnotate(node, pytree_utils.Annotation.SPLIT_PENALTY, UNBREAKABLE) - - def _SetVeryStronglyConnected(self, *nodes): - """Set a STRONGLY_CONNECTED penalty annotation for the given nodes.""" - for node in nodes: - _RecAnnotate(node, pytree_utils.Annotation.SPLIT_PENALTY, - VERY_STRONGLY_CONNECTED) - - def _SetStronglyConnected(self, *nodes): - """Set a STRONGLY_CONNECTED penalty annotation for the given nodes.""" - for node in nodes: - _RecAnnotate(node, pytree_utils.Annotation.SPLIT_PENALTY, - STRONGLY_CONNECTED) - def _SetUnbreakableOnChildren(self, node): """Set an UNBREAKABLE penalty annotation on children of node.""" for child in node.children: self.Visit(child) start = 2 if hasattr(node.children[0], 'is_pseudo') else 1 for i in py3compat.range(start, len(node.children)): - self._SetUnbreakable(node.children[i]) + _SetUnbreakable(node.children[i]) - def _SetExpressionPenalty(self, node, penalty): - """Set a penalty annotation on children nodes.""" - def RecArithmeticExpression(node, first_child_leaf): - if node is first_child_leaf: - return +def _SetUnbreakable(node): + """Set an UNBREAKABLE penalty annotation for the given node.""" + _RecAnnotate(node, pytree_utils.Annotation.SPLIT_PENALTY, UNBREAKABLE) - if isinstance(node, pytree.Leaf): - if node.value in {'(', 'for', 'if'}: - return - penalty_annotation = pytree_utils.GetNodeAnnotation( - node, pytree_utils.Annotation.SPLIT_PENALTY, default=0) - if penalty_annotation < penalty: - pytree_utils.SetNodeAnnotation( - node, pytree_utils.Annotation.SPLIT_PENALTY, penalty) - else: - for child in node.children: - RecArithmeticExpression(child, first_child_leaf) - RecArithmeticExpression(node, _FirstChildNode(node)) +def _SetStronglyConnected(*nodes): + """Set a STRONGLY_CONNECTED penalty annotation for the given nodes.""" + for node in nodes: + _RecAnnotate(node, pytree_utils.Annotation.SPLIT_PENALTY, + STRONGLY_CONNECTED) + + +def _SetVeryStronglyConnected(*nodes): + """Set a VERY_STRONGLY_CONNECTED penalty annotation for the given nodes.""" + for node in nodes: + _RecAnnotate(node, pytree_utils.Annotation.SPLIT_PENALTY, + VERY_STRONGLY_CONNECTED) + + +def _SetExpressionPenalty(node, penalty): + """Set a penalty annotation on children nodes.""" + + def RecArithmeticExpression(node, first_child_leaf): + if node is first_child_leaf: + return + + if isinstance(node, pytree.Leaf): + if node.value in {'(', 'for', 'if'}: + return + penalty_annotation = pytree_utils.GetNodeAnnotation( + node, pytree_utils.Annotation.SPLIT_PENALTY, default=0) + if penalty_annotation < penalty: + pytree_utils.SetNodeAnnotation( + node, pytree_utils.Annotation.SPLIT_PENALTY, penalty) + else: + for child in node.children: + RecArithmeticExpression(child, first_child_leaf) + + RecArithmeticExpression(node, _FirstChildNode(node)) def _RecAnnotate(tree, annotate_name, annotate_value): @@ -415,6 +419,18 @@ def _RecAnnotate(tree, annotate_name, annotate_value): pytree_utils.SetNodeAnnotation(tree, annotate_name, annotate_value) +def _StronglyConnectedCompOp(op): + if (len(op.children[1].children) == 2 and + pytree_utils.NodeName(op.children[1]) == 'comp_op' and + _FirstChildNode(op.children[1]).value == 'not' and + _LastChildNode(op.children[1]).value == 'in'): + return True + if (isinstance(op.children[1], pytree.Leaf) and + op.children[1].value in {'==', 'in'}): + return True + return False + + def _AllowBuilderStyleCalls(node): """Allow splitting before '.' if it's a builder style function call.""" @@ -436,18 +452,6 @@ def RecGetLeaves(node): prev_child = child -def _StronglyConnectedCompOp(op): - if (len(op.children[1].children) == 2 and - pytree_utils.NodeName(op.children[1]) == 'comp_op' and - _FirstChildNode(op.children[1]).value == 'not' and - _LastChildNode(op.children[1]).value == 'in'): - return True - if (isinstance(op.children[1], pytree.Leaf) and - op.children[1].value in {'==', 'in'}): - return True - return False - - def _FirstChildNode(node): if isinstance(node, pytree.Leaf): return node diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index b0a2cfab5..54b558519 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1273,7 +1273,8 @@ def testEndingComment(self): code = textwrap.dedent("""\ a = f( a="something", - b="something requiring comment which is quite long", # comment about b (pushes line over 79) + b= + "something requiring comment which is quite long", # comment about b (pushes line over 79) c="something else, about which comment doesn't make sense") """) uwlines = yapf_test_helper.ParseAndUnwrap(code) From ce3e7538998706fcd14afe5232dc0d704e1e07f6 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 16 Feb 2017 23:35:09 -0800 Subject: [PATCH 106/719] Use property --- yapf/yapflib/reformatter.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 587db4f6d..9b791badb 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -222,8 +222,7 @@ def _CanPlaceOnSingleLine(uwline): indent_amt = style.Get('INDENT_WIDTH') * uwline.depth last = uwline.last last_index = -1 - if last.is_comment and re.search(r'^#+\s+pylint:', - last.value.strip(), re.IGNORECASE): + if last.is_pylint_comment: last = last.previous_token last_index = -2 if last is None: From 2f27f025e8b5b25d6cbc274e5f9013c595beec0e Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 17 Feb 2017 00:24:51 -0800 Subject: [PATCH 107/719] Don't use original formatting in decisions Using the original formatting makes yapf non-stable in many cases when formatting the exact same code. --- CHANGELOG | 3 ++ yapf/yapflib/split_penalty.py | 59 ++++++++++++++++++++----- yapftests/reformatter_basic_test.py | 10 ++--- yapftests/reformatter_buganizer_test.py | 5 ++- yapftests/split_penalty_test.py | 28 ++++++------ 5 files changed, 72 insertions(+), 33 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1c434c937..5450b8f27 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,9 @@ - Relax the requirement that a named argument needs to be on one line. Going over the column limit is more of an issue to pylint than putting named args on multiple lines. +- Don't make splitting penalty decisions based on the original formatting. This + can and does lead to non-stable formatting, where yapf will reformat the same + code in different ways. ### Fixed - Ensure splitting of arguments if there's a named assign present. - Prefer to coalesce opening brackets if it's not at the beginning of a diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 7fffeb182..8a9a64552 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -29,7 +29,9 @@ STRONGLY_CONNECTED = 2000 CONTIGUOUS_LIST = 500 -NOT_TEST = 50 +NOT_TEST = 1300 +AND_TEST = 1200 +OR_TEST = 1100 COMPARISON_EXPRESSION = 550 ARITHMETIC_EXPRESSION = 600 TERM_EXPRESSION = 650 @@ -255,11 +257,6 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring pytree_utils.SetNodeAnnotation( last_child_node, pytree_utils.Annotation.SPLIT_PENALTY, VERY_STRONGLY_CONNECTED) - - if _FirstChildNode(trailer).lineno == last_child_node.lineno: - # If the trailer was originally on one line, then try to keep it - # like that. - _SetExpressionPenalty(trailer, CONTIGUOUS_LIST) else: # If the trailer's children are '()', then make it a strongly # connected region. It's sometimes necessary, though undesirable, to @@ -290,6 +287,50 @@ def Visit_comp_if(self, node): # pylint: disable=invalid-name _SetStronglyConnected(*node.children[1:]) self.DefaultNodeVisit(node) + def Visit_or_test(self, node): # pylint: disable=invalid-name + # or_test ::= and_test ('or' and_test)* + self.DefaultNodeVisit(node) + _SetExpressionPenalty(node, OR_TEST) + index = 1 + while index + 1 < len(node.children): + if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'): + pytree_utils.SetNodeAnnotation( + _FirstChildNode(node.children[index]), + pytree_utils.Annotation.SPLIT_PENALTY, 0) + pytree_utils.SetNodeAnnotation( + _FirstChildNode(node.children[index + 1]), + pytree_utils.Annotation.SPLIT_PENALTY, STRONGLY_CONNECTED) + else: + pytree_utils.SetNodeAnnotation( + _FirstChildNode(node.children[index]), + pytree_utils.Annotation.SPLIT_PENALTY, STRONGLY_CONNECTED) + pytree_utils.SetNodeAnnotation( + _FirstChildNode(node.children[index + 1]), + pytree_utils.Annotation.SPLIT_PENALTY, 0) + index += 2 + + def Visit_and_test(self, node): # pylint: disable=invalid-name + # and_test ::= not_test ('and' not_test)* + self.DefaultNodeVisit(node) + _SetExpressionPenalty(node, AND_TEST) + index = 1 + while index + 1 < len(node.children): + if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'): + pytree_utils.SetNodeAnnotation( + _FirstChildNode(node.children[index]), + pytree_utils.Annotation.SPLIT_PENALTY, 0) + pytree_utils.SetNodeAnnotation( + _FirstChildNode(node.children[index + 1]), + pytree_utils.Annotation.SPLIT_PENALTY, STRONGLY_CONNECTED) + else: + pytree_utils.SetNodeAnnotation( + _FirstChildNode(node.children[index]), + pytree_utils.Annotation.SPLIT_PENALTY, STRONGLY_CONNECTED) + pytree_utils.SetNodeAnnotation( + _FirstChildNode(node.children[index + 1]), + pytree_utils.Annotation.SPLIT_PENALTY, 0) + index += 2 + def Visit_not_test(self, node): # pylint: disable=invalid-name # not_test ::= 'not' not_test | comparison self.DefaultNodeVisit(node) @@ -324,8 +365,6 @@ def Visit_atom(self, node): # pylint: disable=invalid-name # '{' [dictsetmaker] '}') self.DefaultNodeVisit(node) if node.children[0].value == '(': - if node.children[0].lineno == node.children[-1].lineno: - _SetExpressionPenalty(node, CONTIGUOUS_LIST) if node.children[-1].value == ')': if pytree_utils.NodeName(node.parent) == 'if_stmt': pytree_utils.SetNodeAnnotation(node.children[-1], @@ -341,10 +380,6 @@ def Visit_atom(self, node): # pylint: disable=invalid-name rbracket = node.children[-1] if len(node.children) == 2: _SetUnbreakable(node.children[-1]) - elif (rbracket.value in ']}' and - lbracket.get_lineno() == rbracket.get_lineno() and - rbracket.column - lbracket.column < style.Get('COLUMN_LIMIT')): - _SetStronglyConnected(*node.children[1:]) ############################################################################ # Helper methods that set the annotations. diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 54b558519..c6182cce3 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1673,8 +1673,8 @@ def _(): if True: if True: if True: - boxes[id_] = np.concatenate( - (points.min(axis=0), qoints.max(axis=0))) + boxes[id_] = np.concatenate((points.min(axis=0), + qoints.max(axis=0))) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1954,9 +1954,9 @@ def testDictionaryElementsOnOneLine(self): code = textwrap.dedent("""\ class _(): - @mock.patch.dict( - os.environ, - {'HTTP_' + xsrf._XSRF_TOKEN_HEADER.replace('-', '_'): 'atoken'}) + @mock.patch.dict(os.environ, { + 'HTTP_' + xsrf._XSRF_TOKEN_HEADER.replace('-', '_'): 'atoken' + }) def _(): pass diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 01b26e715..2eb2f9977 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -140,8 +140,9 @@ def testB32931780(self): 'who': 'allin', # This is an entry that has a dictionary in it. It's ugly 'something': { - 'page': - ['this-is-a-page@xxxxxxxx.com', 'something-for-eml@xxxxxx.com'], + 'page': [ + 'this-is-a-page@xxxxxxxx.com', 'something-for-eml@xxxxxx.com' + ], 'bug': ['bugs-go-here5300@xxxxxx.com'], 'email': ['sometypeof-email@xxxxxx.com'], }, diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index 00a870e6f..9f57e1512 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -191,18 +191,18 @@ def testStronglyConnected(self): tree = self._ParseAndComputePenalties(code) self._CheckPenalties(tree, [ ('[', None), - ('a', STRONGLY_CONNECTED), - ('for', STRONGLY_CONNECTED), + ('a', None), + ('for', 0), ('a', STRONGLY_CONNECTED), ('in', STRONGLY_CONNECTED), ('foo', STRONGLY_CONNECTED), - ('if', STRONGLY_CONNECTED), + ('if', 0), ('a', STRONGLY_CONNECTED), ('.', UNBREAKABLE), ('x', DOTTED_NAME), ('==', STRONGLY_CONNECTED), ('37', STRONGLY_CONNECTED), - (']', STRONGLY_CONNECTED), + (']', None), ]) def testFuncCalls(self): @@ -211,11 +211,11 @@ def testFuncCalls(self): self._CheckPenalties(tree, [ ('foo', None), ('(', UNBREAKABLE), - ('1', CONTIGUOUS_LIST), - (',', CONTIGUOUS_LIST), - ('2', CONTIGUOUS_LIST), - (',', CONTIGUOUS_LIST), - ('3', CONTIGUOUS_LIST), + ('1', None), + (',', None), + ('2', None), + (',', None), + ('3', None), (')', VERY_STRONGLY_CONNECTED), ]) @@ -229,11 +229,11 @@ def testFuncCalls(self): ('.', STRONGLY_CONNECTED), ('baz', DOTTED_NAME), ('(', STRONGLY_CONNECTED), - ('1', CONTIGUOUS_LIST), - (',', CONTIGUOUS_LIST), - ('2', CONTIGUOUS_LIST), - (',', CONTIGUOUS_LIST), - ('3', CONTIGUOUS_LIST), + ('1', None), + (',', None), + ('2', None), + (',', None), + ('3', None), (')', VERY_STRONGLY_CONNECTED), ]) From b90a7ff9931c420aeb4e0ced6902e0f02c01c2c6 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 17 Feb 2017 01:56:45 -0800 Subject: [PATCH 108/719] Don't squish all the args to the RHS It looks bad when they're all aligned over to the right when there's all this whitespace being wasted. --- CHANGELOG | 2 ++ yapf/yapflib/format_decision_state.py | 11 +++++++--- yapf/yapflib/reformatter.py | 5 ++--- yapf/yapflib/split_penalty.py | 7 ++----- yapf/yapflib/subtype_assigner.py | 6 ++++-- yapf/yapflib/unwrapped_line.py | 4 ++-- yapf/yapflib/yapf_api.py | 14 ++++++------- yapftests/file_resources_test.py | 8 +++++--- yapftests/format_decision_state_test.py | 5 ++--- yapftests/reformatter_basic_test.py | 27 +++++++++++++++++++++++++ yapftests/subtype_assigner_test.py | 22 +++++++++++--------- yapftests/yapf_test.py | 4 ++-- 12 files changed, 74 insertions(+), 41 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5450b8f27..3f8a6fe4b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,8 @@ - Ensure splitting of arguments if there's a named assign present. - Prefer to coalesce opening brackets if it's not at the beginning of a function call. +- Prefer not to squish all of the elements in a function call over to the + right-hand side. Split the arguments instead. ## [0.16.0] 2017-02-05 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 2e84f61d4..8bbe8f7a0 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -80,6 +80,7 @@ def __init__(self, line, first_indent): self.column_limit = style.Get('COLUMN_LIMIT') def Clone(self): + """Clones a FormatDecisionState object.""" new = FormatDecisionState(self.line, self.first_indent) new.next_token = self.next_token new.column = self.column @@ -102,9 +103,9 @@ def __eq__(self, other): self.column == other.column and self.paren_level == other.paren_level and self.start_of_line_level == other.start_of_line_level and - self.lowest_level_on_line == other.lowest_level_on_line and ( - self.ignore_stack_for_comparison or - other.ignore_stack_for_comparison or self.stack == other.stack)) + self.lowest_level_on_line == other.lowest_level_on_line and + (self.ignore_stack_for_comparison or + other.ignore_stack_for_comparison or self.stack == other.stack)) def __ne__(self, other): return not self == other @@ -323,6 +324,10 @@ def MustSplit(self): # line and it's not a function call. if self._FitsOnLine(previous, previous.matching_bracket): return False + elif not self._FitsOnLine(previous, previous.matching_bracket): + if (self.column_limit - self.column) / float(self.column_limit) < 0.3: + # Try not to squish all of the arguments off to the right. + return current.next_token != previous.matching_bracket else: # Split after the opening of a container if it doesn't fit on the # current line or if it has a comment. diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 9b791badb..fd8f3178a 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -22,7 +22,6 @@ from __future__ import unicode_literals import collections -import copy import heapq import re @@ -273,8 +272,8 @@ def __init__(self, state, newline, previous): self.previous = previous def __repr__(self): # pragma: no cover - return 'StateNode(state=[\n{0}\n], newline={1})'.format(self.state, - self.newline) + return 'StateNode(state=[\n{0}\n], newline={1})'.format( + self.state, self.newline) # A tuple of (penalty, count) that is used to prioritize the BFS. In case of diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 8a9a64552..a18eb02ff 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -374,12 +374,9 @@ def Visit_atom(self, node): # pylint: disable=invalid-name pytree_utils.SetNodeAnnotation(node.children[-1], pytree_utils.Annotation.SPLIT_PENALTY, COMPARISON_EXPRESSION) - elif node.children[0].value in '[{': + elif node.children[0].value in '[{' and len(node.children) == 2: # Keep empty containers together if we can. - lbracket = node.children[0] - rbracket = node.children[-1] - if len(node.children) == 2: - _SetUnbreakable(node.children[-1]) + _SetUnbreakable(node.children[-1]) ############################################################################ # Helper methods that set the annotations. diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 3e27fbfe5..646cdc8a4 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -91,8 +91,10 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name else: _AppendFirstLeafTokenSubtype( child, format_token.Subtype.DICTIONARY_VALUE) - elif (child is not None and (isinstance(child, pytree.Node) or ( - not child.value.startswith('#') and child.value not in '{:,'))): + elif ( + child is not None and + (isinstance(child, pytree.Node) or + (not child.value.startswith('#') and child.value not in '{:,'))): # Mark the first leaf of a key entry as a DICTIONARY_KEY. We # normally want to split before them if the dictionary cannot exist # on a single line. diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 8e0d3d138..77b2f1e2e 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -145,8 +145,8 @@ def __str__(self): # pragma: no cover def __repr__(self): # pragma: no cover tokens_repr = ','.join( ['{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens]) - return 'UnwrappedLine(depth={0}, tokens=[{1}])'.format(self.depth, - tokens_repr) + return 'UnwrappedLine(depth={0}, tokens=[{1}])'.format( + self.depth, tokens_repr) ############################################################################ # Properties # diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 3a5031998..dd91849ea 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -260,17 +260,15 @@ def _MarkLinesToFormat(uwlines, lines): def _DisableYAPF(line): - return (re.search(DISABLE_PATTERN, line.split('\n')[0].strip(), - re.IGNORECASE) or re.search(DISABLE_PATTERN, - line.split('\n')[-1].strip(), - re.IGNORECASE)) + return ( + re.search(DISABLE_PATTERN, line.split('\n')[0].strip(), re.IGNORECASE) or + re.search(DISABLE_PATTERN, line.split('\n')[-1].strip(), re.IGNORECASE)) def _EnableYAPF(line): - return (re.search(ENABLE_PATTERN, line.split('\n')[0].strip(), - re.IGNORECASE) or re.search(ENABLE_PATTERN, - line.split('\n')[-1].strip(), - re.IGNORECASE)) + return ( + re.search(ENABLE_PATTERN, line.split('\n')[0].strip(), re.IGNORECASE) or + re.search(ENABLE_PATTERN, line.split('\n')[-1].strip(), re.IGNORECASE)) def _GetUnifiedDiff(before, after, filename='code'): diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 67e373b4b..adfdae769 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -105,7 +105,8 @@ def test_recursive_find_in_dir(self): tdir3 = self._make_test_dir('test3/foo/bar/bas/xxx') files = [ os.path.join(tdir1, 'testfile1.py'), - os.path.join(tdir2, 'testfile2.py'), os.path.join(tdir3, 'testfile3.py') + os.path.join(tdir2, 'testfile2.py'), + os.path.join(tdir3, 'testfile3.py'), ] _touch_files(files) @@ -121,7 +122,8 @@ def test_recursive_find_in_dir_with_exclude(self): tdir3 = self._make_test_dir('test3/foo/bar/bas/xxx') files = [ os.path.join(tdir1, 'testfile1.py'), - os.path.join(tdir2, 'testfile2.py'), os.path.join(tdir3, 'testfile3.py') + os.path.join(tdir2, 'testfile2.py'), + os.path.join(tdir3, 'testfile3.py'), ] _touch_files(files) @@ -131,7 +133,7 @@ def test_recursive_find_in_dir_with_exclude(self): [self.test_tmpdir], recursive=True, exclude=['*test*3.py'])), sorted([ os.path.join(tdir1, 'testfile1.py'), - os.path.join(tdir2, 'testfile2.py') + os.path.join(tdir2, 'testfile2.py'), ])) diff --git a/yapftests/format_decision_state_test.py b/yapftests/format_decision_state_test.py index c925d1db3..0c31b6882 100644 --- a/yapftests/format_decision_state_test.py +++ b/yapftests/format_decision_state_test.py @@ -13,7 +13,6 @@ # limitations under the License. """Tests for yapf.format_decision_state.""" -import copy import textwrap import unittest @@ -82,7 +81,7 @@ def f(a, b): self.assertFalse(state.CanSplit(False)) self.assertFalse(state.MustSplit()) - clone = copy.copy(state) + clone = state.Clone() self.assertEqual(repr(state), repr(clone)) def testSimpleFunctionDefWithSplitting(self): @@ -130,7 +129,7 @@ def f(a, b): self.assertEqual(':', state.next_token.value) self.assertFalse(state.CanSplit(False)) - clone = copy.copy(state) + clone = state.Clone() self.assertEqual(repr(state), repr(clone)) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index c6182cce3..c530ffc09 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1573,6 +1573,33 @@ def method(self): finally: style.SetGlobalStyle(style.CreateChromiumStyle()) + def testStableInlinedDictionaryFormatting(self): + try: + style.SetGlobalStyle(style.CreatePEP8Style()) + unformatted_code = textwrap.dedent("""\ + def _(): + url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( + value, urllib.urlencode({'action': 'update', 'parameter': value})) + """) + expected_formatted_code = textwrap.dedent("""\ + def _(): + url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( + value, urllib.urlencode({ + 'action': 'update', + 'parameter': value + })) + """) + + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + reformatted_code = reformatter.Reformat(uwlines) + self.assertCodeEqual(expected_formatted_code, reformatted_code) + + uwlines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + reformatted_code = reformatter.Reformat(uwlines) + self.assertCodeEqual(expected_formatted_code, reformatted_code) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + def testDontSplitKeywordValueArguments(self): unformatted_code = textwrap.dedent("""\ def mark_game_scored(gid): diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index 72cb6a278..db0e17d10 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -158,7 +158,7 @@ def testBitwiseOperators(self): ('3', [format_token.Subtype.NONE]), (')', [format_token.Subtype.NONE]), ('>>', {format_token.Subtype.BINARY_OPERATOR}), - ('1', [format_token.Subtype.NONE])], + ('1', [format_token.Subtype.NONE]),], ]) # yapf: disable def testSubscriptColon(self): @@ -167,14 +167,16 @@ def testSubscriptColon(self): """) uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ - [('x', [format_token.Subtype.NONE]), - ('[', {format_token.Subtype.SUBSCRIPT_BRACKET}), - ('0', [format_token.Subtype.NONE]), - (':', {format_token.Subtype.SUBSCRIPT_COLON}), - ('42', [format_token.Subtype.NONE]), - (':', {format_token.Subtype.SUBSCRIPT_COLON}), - ('1', [format_token.Subtype.NONE]), - (']', {format_token.Subtype.SUBSCRIPT_BRACKET})], + [ + ('x', [format_token.Subtype.NONE]), + ('[', {format_token.Subtype.SUBSCRIPT_BRACKET}), + ('0', [format_token.Subtype.NONE]), + (':', {format_token.Subtype.SUBSCRIPT_COLON}), + ('42', [format_token.Subtype.NONE]), + (':', {format_token.Subtype.SUBSCRIPT_COLON}), + ('1', [format_token.Subtype.NONE]), + (']', {format_token.Subtype.SUBSCRIPT_BRACKET}), + ], ]) def testFunctionCallWithStarExpression(self): @@ -188,7 +190,7 @@ def testFunctionCallWithStarExpression(self): (',', [format_token.Subtype.NONE]), ('*', {format_token.Subtype.UNARY_OPERATOR}), ('b', [format_token.Subtype.NONE]), - (']', [format_token.Subtype.NONE])] + (']', [format_token.Subtype.NONE]),], ]) # yapf: disable diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index ed94810c8..fdd4fb98a 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1137,8 +1137,8 @@ def foo_function(): pass """) - with utils.NamedTempFile( - dirname=self.test_tmpdir) as (stylefile, stylepath): + with utils.NamedTempFile(dirname=self.test_tmpdir) as (stylefile, + stylepath): p = subprocess.Popen( YAPF_BINARY + ['--style-help'], stdout=stylefile, From 48bc4614b26afbd81b0f88dd2a02316f725a3d85 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 19 Feb 2017 14:21:06 -0800 Subject: [PATCH 109/719] Use split penalties for all expressions. --- yapf/yapflib/split_penalty.py | 67 ++++++++++++------------- yapftests/reformatter_buganizer_test.py | 5 +- 2 files changed, 35 insertions(+), 37 deletions(-) diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index a18eb02ff..102750e48 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -29,13 +29,15 @@ STRONGLY_CONNECTED = 2000 CONTIGUOUS_LIST = 500 -NOT_TEST = 1300 -AND_TEST = 1200 OR_TEST = 1100 -COMPARISON_EXPRESSION = 550 -ARITHMETIC_EXPRESSION = 600 -TERM_EXPRESSION = 650 -ONE_ELEMENT_ARGUMENT = 650 +AND_TEST = 1200 +NOT_TEST = 1300 +COMPARISON_EXPRESSION = 1400 +ARITH_EXPR = 1500 +TERM_EXPR = 1600 +FACTOR = 1700 +POWER = 1800 +ONE_ELEMENT_ARGUMENT = 1900 def ComputeSplitPenalties(tree): @@ -294,19 +296,10 @@ def Visit_or_test(self, node): # pylint: disable=invalid-name index = 1 while index + 1 < len(node.children): if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'): - pytree_utils.SetNodeAnnotation( - _FirstChildNode(node.children[index]), - pytree_utils.Annotation.SPLIT_PENALTY, 0) - pytree_utils.SetNodeAnnotation( - _FirstChildNode(node.children[index + 1]), - pytree_utils.Annotation.SPLIT_PENALTY, STRONGLY_CONNECTED) + _DecrementSplitPenalty(_FirstChildNode(node.children[index]), OR_TEST) else: - pytree_utils.SetNodeAnnotation( - _FirstChildNode(node.children[index]), - pytree_utils.Annotation.SPLIT_PENALTY, STRONGLY_CONNECTED) - pytree_utils.SetNodeAnnotation( - _FirstChildNode(node.children[index + 1]), - pytree_utils.Annotation.SPLIT_PENALTY, 0) + _DecrementSplitPenalty( + _FirstChildNode(node.children[index + 1]), OR_TEST) index += 2 def Visit_and_test(self, node): # pylint: disable=invalid-name @@ -316,19 +309,10 @@ def Visit_and_test(self, node): # pylint: disable=invalid-name index = 1 while index + 1 < len(node.children): if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'): - pytree_utils.SetNodeAnnotation( - _FirstChildNode(node.children[index]), - pytree_utils.Annotation.SPLIT_PENALTY, 0) - pytree_utils.SetNodeAnnotation( - _FirstChildNode(node.children[index + 1]), - pytree_utils.Annotation.SPLIT_PENALTY, STRONGLY_CONNECTED) + _DecrementSplitPenalty(_FirstChildNode(node.children[index]), AND_TEST) else: - pytree_utils.SetNodeAnnotation( - _FirstChildNode(node.children[index]), - pytree_utils.Annotation.SPLIT_PENALTY, STRONGLY_CONNECTED) - pytree_utils.SetNodeAnnotation( - _FirstChildNode(node.children[index + 1]), - pytree_utils.Annotation.SPLIT_PENALTY, 0) + _DecrementSplitPenalty( + _FirstChildNode(node.children[index + 1]), AND_TEST) index += 2 def Visit_not_test(self, node): # pylint: disable=invalid-name @@ -352,12 +336,17 @@ def Visit_comparison(self, node): # pylint: disable=invalid-name def Visit_arith_expr(self, node): # pylint: disable=invalid-name # arith_expr ::= term (('+'|'-') term)* self.DefaultNodeVisit(node) - _SetExpressionPenalty(node, ARITHMETIC_EXPRESSION) + _SetExpressionPenalty(node, ARITH_EXPR) def Visit_term_expr(self, node): # pylint: disable=invalid-name # term ::= factor (('*'|'@'|'/'|'%'|'//') factor)* self.DefaultNodeVisit(node) - _SetExpressionPenalty(node, TERM_EXPRESSION) + _SetExpressionPenalty(node, TERM_EXPR) + + def Visit_factor(self, node): # pyline: disable=invalid-name + # factor ::= ('+'|'-'|'~') factor | power + self.DefaultNodeVisit(node) + _SetExpressionPenalty(node, FACTOR) def Visit_atom(self, node): # pylint: disable=invalid-name # atom ::= ('(' [yield_expr|testlist_gexp] ')' @@ -412,7 +401,7 @@ def _SetVeryStronglyConnected(*nodes): def _SetExpressionPenalty(node, penalty): """Set a penalty annotation on children nodes.""" - def RecArithmeticExpression(node, first_child_leaf): + def RecExpression(node, first_child_leaf): if node is first_child_leaf: return @@ -426,9 +415,9 @@ def RecArithmeticExpression(node, first_child_leaf): node, pytree_utils.Annotation.SPLIT_PENALTY, penalty) else: for child in node.children: - RecArithmeticExpression(child, first_child_leaf) + RecExpression(child, first_child_leaf) - RecArithmeticExpression(node, _FirstChildNode(node)) + RecExpression(node, _FirstChildNode(node)) def _RecAnnotate(tree, annotate_name, annotate_value): @@ -463,6 +452,14 @@ def _StronglyConnectedCompOp(op): return False +def _DecrementSplitPenalty(node, amt): + penalty = pytree_utils.GetNodeAnnotation( + node, pytree_utils.Annotation.SPLIT_PENALTY, default=amt) + penalty = penalty - amt if amt < penalty else 0 + pytree_utils.SetNodeAnnotation(node, pytree_utils.Annotation.SPLIT_PENALTY, + penalty) + + def _AllowBuilderStyleCalls(node): """Allow splitting before '.' if it's a builder style function call.""" diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 2eb2f9977..1dc692a9e 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -1253,8 +1253,9 @@ def main(unused_argv): an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A]) a_long_name_slicing = an_array_with_an_exceedingly_long_name[: ARBITRARY_CONSTANT_A] - bad_slice = ("I am a crazy, no good, string whats too long, etc." + - " no really ")[:ARBITRARY_CONSTANT_A] + bad_slice = ( + "I am a crazy, no good, string whats too long, etc." + " no really " + )[:ARBITRARY_CONSTANT_A] """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) From 5e23e0eea4305abca3578043ff6f73b506a6b62b Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 19 Feb 2017 18:10:44 -0800 Subject: [PATCH 110/719] Use a helper function to set split penalty --- yapf/yapflib/split_penalty.py | 66 +++++++++++---------------------- yapftests/split_penalty_test.py | 1 - 2 files changed, 22 insertions(+), 45 deletions(-) diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 102750e48..f9af43ced 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -62,9 +62,7 @@ def Visit_import_as_names(self, node): # pyline: disable=invalid-name for child in node.children: if (prev_child and isinstance(prev_child, pytree.Leaf) and prev_child.value == ','): - pytree_utils.SetNodeAnnotation(child, - pytree_utils.Annotation.SPLIT_PENALTY, - style.Get('SPLIT_PENALTY_IMPORT_NAMES')) + _SetSplitPenalty(child, style.Get('SPLIT_PENALTY_IMPORT_NAMES')) prev_child = child def Visit_classdef(self, node): # pylint: disable=invalid-name @@ -99,9 +97,7 @@ def Visit_funcdef(self, node): # pylint: disable=invalid-name _SetUnbreakable(node.children[colon_idx]) self.DefaultNodeVisit(node) if arrow_idx > 0: - pytree_utils.SetNodeAnnotation( - _LastChildNode(node.children[arrow_idx - 1]), - pytree_utils.Annotation.SPLIT_PENALTY, 0) + _SetSplitPenalty(_LastChildNode(node.children[arrow_idx - 1]), 0) _SetUnbreakable(node.children[arrow_idx]) _SetStronglyConnected(node.children[arrow_idx + 1]) @@ -154,22 +150,18 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name self.DefaultNodeVisit(node) if node.children[0].value == '.': self._SetUnbreakableOnChildren(node) - pytree_utils.SetNodeAnnotation( - node.children[1], pytree_utils.Annotation.SPLIT_PENALTY, DOTTED_NAME) + _SetSplitPenalty(node.children[1], DOTTED_NAME) elif len(node.children) == 2: # Don't split an empty argument list if at all possible. - pytree_utils.SetNodeAnnotation(node.children[1], - pytree_utils.Annotation.SPLIT_PENALTY, - VERY_STRONGLY_CONNECTED) + _SetSplitPenalty(node.children[1], VERY_STRONGLY_CONNECTED) elif len(node.children) == 3: name = pytree_utils.NodeName(node.children[1]) if name == 'power': if pytree_utils.NodeName(node.children[1].children[0]) != 'atom': # Don't split an argument list with one element if at all possible. _SetStronglyConnected(node.children[1], node.children[2]) - pytree_utils.SetNodeAnnotation( - _FirstChildNode(node.children[1]), - pytree_utils.Annotation.SPLIT_PENALTY, ONE_ELEMENT_ARGUMENT) + _SetSplitPenalty(_FirstChildNode(node.children[1]), + ONE_ELEMENT_ARGUMENT) elif (pytree_utils.NodeName(node.children[0]) == 'LSQB' and (name.endswith('_test') or name.endswith('_expr'))): _SetStronglyConnected(node.children[1].children[0]) @@ -181,13 +173,9 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name (name.endswith('_expr') and style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'))) if split_before: - pytree_utils.SetNodeAnnotation( - _LastChildNode(node.children[1].children[1]), - pytree_utils.Annotation.SPLIT_PENALTY, 0) + _SetSplitPenalty(_LastChildNode(node.children[1].children[1]), 0) else: - pytree_utils.SetNodeAnnotation( - _FirstChildNode(node.children[1].children[2]), - pytree_utils.Annotation.SPLIT_PENALTY, 0) + _SetSplitPenalty(_FirstChildNode(node.children[1].children[2]), 0) # Don't split the ending bracket of a subscript list. _SetVeryStronglyConnected(node.children[-1]) @@ -256,9 +244,7 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring if last_child_node.value == ']': _SetUnbreakable(last_child_node) else: - pytree_utils.SetNodeAnnotation( - last_child_node, pytree_utils.Annotation.SPLIT_PENALTY, - VERY_STRONGLY_CONNECTED) + _SetSplitPenalty(last_child_node, VERY_STRONGLY_CONNECTED) else: # If the trailer's children are '()', then make it a strongly # connected region. It's sometimes necessary, though undesirable, to @@ -276,16 +262,14 @@ def Visit_subscript(self, node): # pylint: disable=invalid-name def Visit_comp_for(self, node): # pylint: disable=invalid-name # comp_for ::= 'for' exprlist 'in' testlist_safe [comp_iter] - pytree_utils.SetNodeAnnotation( - _FirstChildNode(node), pytree_utils.Annotation.SPLIT_PENALTY, 0) + _SetSplitPenalty(_FirstChildNode(node), 0) _SetStronglyConnected(*node.children[1:]) self.DefaultNodeVisit(node) def Visit_comp_if(self, node): # pylint: disable=invalid-name # comp_if ::= 'if' old_test [comp_iter] - pytree_utils.SetNodeAnnotation(node.children[0], - pytree_utils.Annotation.SPLIT_PENALTY, - style.Get('SPLIT_PENALTY_BEFORE_IF_EXPR')) + _SetSplitPenalty(node.children[0], + style.Get('SPLIT_PENALTY_BEFORE_IF_EXPR')) _SetStronglyConnected(*node.children[1:]) self.DefaultNodeVisit(node) @@ -324,12 +308,8 @@ def Visit_comparison(self, node): # pylint: disable=invalid-name # comparison ::= expr (comp_op expr)* self.DefaultNodeVisit(node) if len(node.children) == 3 and _StronglyConnectedCompOp(node): - pytree_utils.SetNodeAnnotation( - _FirstChildNode(node.children[1]), - pytree_utils.Annotation.SPLIT_PENALTY, STRONGLY_CONNECTED) - pytree_utils.SetNodeAnnotation( - _FirstChildNode(node.children[2]), - pytree_utils.Annotation.SPLIT_PENALTY, STRONGLY_CONNECTED) + _SetSplitPenalty(_FirstChildNode(node.children[1]), STRONGLY_CONNECTED) + _SetSplitPenalty(_FirstChildNode(node.children[2]), STRONGLY_CONNECTED) else: _SetExpressionPenalty(node, COMPARISON_EXPRESSION) @@ -356,13 +336,9 @@ def Visit_atom(self, node): # pylint: disable=invalid-name if node.children[0].value == '(': if node.children[-1].value == ')': if pytree_utils.NodeName(node.parent) == 'if_stmt': - pytree_utils.SetNodeAnnotation(node.children[-1], - pytree_utils.Annotation.SPLIT_PENALTY, - UNBREAKABLE) + _SetSplitPenalty(node.children[-1], UNBREAKABLE) else: - pytree_utils.SetNodeAnnotation(node.children[-1], - pytree_utils.Annotation.SPLIT_PENALTY, - COMPARISON_EXPRESSION) + _SetSplitPenalty(node.children[-1], COMPARISON_EXPRESSION) elif node.children[0].value in '[{' and len(node.children) == 2: # Keep empty containers together if we can. _SetUnbreakable(node.children[-1]) @@ -411,8 +387,7 @@ def RecExpression(node, first_child_leaf): penalty_annotation = pytree_utils.GetNodeAnnotation( node, pytree_utils.Annotation.SPLIT_PENALTY, default=0) if penalty_annotation < penalty: - pytree_utils.SetNodeAnnotation( - node, pytree_utils.Annotation.SPLIT_PENALTY, penalty) + _SetSplitPenalty(node, penalty) else: for child in node.children: RecExpression(child, first_child_leaf) @@ -456,6 +431,10 @@ def _DecrementSplitPenalty(node, amt): penalty = pytree_utils.GetNodeAnnotation( node, pytree_utils.Annotation.SPLIT_PENALTY, default=amt) penalty = penalty - amt if amt < penalty else 0 + _SetSplitPenalty(node, penalty) + + +def _SetSplitPenalty(node, penalty): pytree_utils.SetNodeAnnotation(node, pytree_utils.Annotation.SPLIT_PENALTY, penalty) @@ -476,8 +455,7 @@ def RecGetLeaves(node): for child in list_of_children: if child.value == '.': if prev_child.lineno != child.lineno: - pytree_utils.SetNodeAnnotation(child, - pytree_utils.Annotation.SPLIT_PENALTY, 0) + _SetSplitPenalty(child, 0) prev_child = child diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index 9f57e1512..83fe94b7e 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -27,7 +27,6 @@ VERY_STRONGLY_CONNECTED = split_penalty.VERY_STRONGLY_CONNECTED DOTTED_NAME = split_penalty.DOTTED_NAME STRONGLY_CONNECTED = split_penalty.STRONGLY_CONNECTED -CONTIGUOUS_LIST = split_penalty.CONTIGUOUS_LIST class SplitPenaltyTest(unittest.TestCase): From 3b2050762dad3430299a91d64f2281d77ba3942c Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 19 Feb 2017 18:14:46 -0800 Subject: [PATCH 111/719] Add and improve split penalties. --- yapf/yapflib/split_penalty.py | 40 +++++++++++++++++++---------------- yapf/yapflib/style.py | 2 +- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index f9af43ced..939606123 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -24,20 +24,24 @@ # TODO(morbo): Document the annotations in a centralized place. E.g., the # README file. UNBREAKABLE = 1000 * 1000 -VERY_STRONGLY_CONNECTED = 3000 -DOTTED_NAME = 2500 -STRONGLY_CONNECTED = 2000 -CONTIGUOUS_LIST = 500 - -OR_TEST = 1100 -AND_TEST = 1200 -NOT_TEST = 1300 -COMPARISON_EXPRESSION = 1400 -ARITH_EXPR = 1500 -TERM_EXPR = 1600 -FACTOR = 1700 -POWER = 1800 -ONE_ELEMENT_ARGUMENT = 1900 +DOTTED_NAME = 4000 +VERY_STRONGLY_CONNECTED = 3500 +STRONGLY_CONNECTED = 3000 + +OR_TEST = 1000 +AND_TEST = 1100 +NOT_TEST = 1200 +COMPARISON = 1300 +STAR_EXPR = 1300 +EXPR = 1400 +XOR_EXPR = 1500 +AND_EXPR = 1700 +SHIFT_EXPR = 1800 +ARITH_EXPR = 1900 +TERM_EXPR = 2000 +FACTOR = 2100 +POWER = 2200 +ONE_ELEMENT_ARGUMENT = 2500 def ComputeSplitPenalties(tree): @@ -46,10 +50,10 @@ def ComputeSplitPenalties(tree): Arguments: tree: the top-level pytree node to annotate with penalties. """ - _TreePenaltyAssigner().Visit(tree) + _SplitPenaltyAssigner().Visit(tree) -class _TreePenaltyAssigner(pytree_visitor.PyTreeVisitor): +class _SplitPenaltyAssigner(pytree_visitor.PyTreeVisitor): """Assigns split penalties to tokens, based on parse tree structure. Split penalties are attached as annotations to tokens. @@ -311,7 +315,7 @@ def Visit_comparison(self, node): # pylint: disable=invalid-name _SetSplitPenalty(_FirstChildNode(node.children[1]), STRONGLY_CONNECTED) _SetSplitPenalty(_FirstChildNode(node.children[2]), STRONGLY_CONNECTED) else: - _SetExpressionPenalty(node, COMPARISON_EXPRESSION) + _SetExpressionPenalty(node, COMPARISON) def Visit_arith_expr(self, node): # pylint: disable=invalid-name # arith_expr ::= term (('+'|'-') term)* @@ -338,7 +342,7 @@ def Visit_atom(self, node): # pylint: disable=invalid-name if pytree_utils.NodeName(node.parent) == 'if_stmt': _SetSplitPenalty(node.children[-1], UNBREAKABLE) else: - _SetSplitPenalty(node.children[-1], COMPARISON_EXPRESSION) + _SetSplitPenalty(node.children[-1], COMPARISON) elif node.children[0].value in '[{' and len(node.children) == 2: # Keep empty containers together if we can. _SetUnbreakable(node.children[-1]) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 63d110a4b..0d4ee04f1 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -228,7 +228,7 @@ def CreatePEP8Style(): SPLIT_PENALTY_AFTER_UNARY_OPERATOR=10000, SPLIT_PENALTY_BEFORE_IF_EXPR=0, SPLIT_PENALTY_BITWISE_OPERATOR=300, - SPLIT_PENALTY_EXCESS_CHARACTER=2600, + SPLIT_PENALTY_EXCESS_CHARACTER=3500, SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=30, SPLIT_PENALTY_IMPORT_NAMES=0, SPLIT_PENALTY_LOGICAL_OPERATOR=300, From 5f29b295a5218bee3696ce0a32fe88665d62ac76 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 19 Feb 2017 21:23:38 -0800 Subject: [PATCH 112/719] Improve the split penalty computation. --- yapf/yapflib/split_penalty.py | 111 ++++++++++++++++++++---- yapftests/reformatter_basic_test.py | 4 +- yapftests/reformatter_buganizer_test.py | 5 +- yapftests/split_penalty_test.py | 8 +- 4 files changed, 103 insertions(+), 25 deletions(-) diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 939606123..14c7a2c79 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -38,9 +38,10 @@ AND_EXPR = 1700 SHIFT_EXPR = 1800 ARITH_EXPR = 1900 -TERM_EXPR = 2000 +TERM = 2000 FACTOR = 2100 POWER = 2200 +ATOM = 2300 ONE_ELEMENT_ARGUMENT = 2500 @@ -122,16 +123,26 @@ def Visit_parameters(self, node): # pylint: disable=invalid-name if not style.Get('DEDENT_CLOSING_BRACKETS'): _SetStronglyConnected(node.children[-1]) + def Visit_arglist(self, node): # pylint: disable=invalid-name + # arglist ::= argument (',' argument)* [','] + self.DefaultNodeVisit(node) + index = 1 + while index < len(node.children): + child = node.children[index] + if isinstance(child, pytree.Leaf) and child.value == ',': + _SetUnbreakable(child) + index += 1 + def Visit_argument(self, node): # pylint: disable=invalid-name # argument ::= test [comp_for] | test '=' test # Really [keyword '='] test self.DefaultNodeVisit(node) - index = 0 + index = 1 while index < len(node.children) - 1: - next_child = node.children[index + 1] - if isinstance(next_child, pytree.Leaf) and next_child.value == '=': + child = node.children[index] + if isinstance(child, pytree.Leaf) and child.value == '=': + _SetStronglyConnected(_FirstChildNode(node.children[index])) _SetStronglyConnected(_FirstChildNode(node.children[index + 1])) - _SetStronglyConnected(_FirstChildNode(node.children[index + 2])) index += 1 def Visit_dotted_name(self, node): # pylint: disable=invalid-name @@ -164,8 +175,8 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name if pytree_utils.NodeName(node.children[1].children[0]) != 'atom': # Don't split an argument list with one element if at all possible. _SetStronglyConnected(node.children[1], node.children[2]) - _SetSplitPenalty(_FirstChildNode(node.children[1]), - ONE_ELEMENT_ARGUMENT) + _SetSplitPenalty( + _FirstChildNode(node.children[1]), ONE_ELEMENT_ARGUMENT) elif (pytree_utils.NodeName(node.children[0]) == 'LSQB' and (name.endswith('_test') or name.endswith('_expr'))): _SetStronglyConnected(node.children[1].children[0]) @@ -280,7 +291,7 @@ def Visit_comp_if(self, node): # pylint: disable=invalid-name def Visit_or_test(self, node): # pylint: disable=invalid-name # or_test ::= and_test ('or' and_test)* self.DefaultNodeVisit(node) - _SetExpressionPenalty(node, OR_TEST) + _IncreasePenalty(node, OR_TEST) index = 1 while index + 1 < len(node.children): if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'): @@ -293,7 +304,7 @@ def Visit_or_test(self, node): # pylint: disable=invalid-name def Visit_and_test(self, node): # pylint: disable=invalid-name # and_test ::= not_test ('and' not_test)* self.DefaultNodeVisit(node) - _SetExpressionPenalty(node, AND_TEST) + _IncreasePenalty(node, AND_TEST) index = 1 while index + 1 < len(node.children): if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'): @@ -306,7 +317,7 @@ def Visit_and_test(self, node): # pylint: disable=invalid-name def Visit_not_test(self, node): # pylint: disable=invalid-name # not_test ::= 'not' not_test | comparison self.DefaultNodeVisit(node) - _SetExpressionPenalty(node, NOT_TEST) + _IncreasePenalty(node, NOT_TEST) def Visit_comparison(self, node): # pylint: disable=invalid-name # comparison ::= expr (comp_op expr)* @@ -315,22 +326,58 @@ def Visit_comparison(self, node): # pylint: disable=invalid-name _SetSplitPenalty(_FirstChildNode(node.children[1]), STRONGLY_CONNECTED) _SetSplitPenalty(_FirstChildNode(node.children[2]), STRONGLY_CONNECTED) else: - _SetExpressionPenalty(node, COMPARISON) + _IncreasePenalty(node, COMPARISON) + + def Visit_star_expr(self, node): # pylint: disable-invalid-name + # star_expr ::= '*' expr + self.DefaultNodeVisit(node) + _IncreasePenalty(node, STAR_EXPR) + + def Visit_expr(self, node): # pylint: disable-invalid-name + # expr ::= xor_expr ('|' xor_expr)* + self.DefaultNodeVisit(node) + _IncreasePenalty(node, EXPR) + index = 1 + while index < len(node.children) - 1: + child = node.children[index] + if isinstance(child, pytree.Leaf) and child.value == '|': + if style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'): + _SetSplitPenalty(child, style.Get('SPLIT_PENALTY_BITWISE_OPERATOR')) + else: + _SetSplitPenalty( + _FirstChildNode(node.children[index + 1]), + style.Get('SPLIT_PENALTY_BITWISE_OPERATOR')) + index += 1 + + def Visit_xor_expr(self, node): # pylint: disable=invalid-name + # xor_expr ::= and_expr ('^' and_expr)* + self.DefaultNodeVisit(node) + _IncreasePenalty(node, XOR_EXPR) + + def Visit_and_expr(self, node): # pylint: disable=invalid-name + # and_expr ::= shift_expr ('&' shift_expr)* + self.DefaultNodeVisit(node) + _IncreasePenalty(node, AND_EXPR) + + def Visit_shift_expr(self, node): # pylint: disable=invalid-name + # shift_expr ::= arith_expr (('<<'|'>>') arith_expr)* + self.DefaultNodeVisit(node) + _IncreasePenalty(node, SHIFT_EXPR) def Visit_arith_expr(self, node): # pylint: disable=invalid-name # arith_expr ::= term (('+'|'-') term)* self.DefaultNodeVisit(node) - _SetExpressionPenalty(node, ARITH_EXPR) + _IncreasePenalty(node, ARITH_EXPR) - def Visit_term_expr(self, node): # pylint: disable=invalid-name + def Visit_term(self, node): # pylint: disable=invalid-name # term ::= factor (('*'|'@'|'/'|'%'|'//') factor)* + _IncreasePenalty(node, TERM) self.DefaultNodeVisit(node) - _SetExpressionPenalty(node, TERM_EXPR) def Visit_factor(self, node): # pyline: disable=invalid-name # factor ::= ('+'|'-'|'~') factor | power self.DefaultNodeVisit(node) - _SetExpressionPenalty(node, FACTOR) + _IncreasePenalty(node, FACTOR) def Visit_atom(self, node): # pylint: disable=invalid-name # atom ::= ('(' [yield_expr|testlist_gexp] ')' @@ -342,11 +389,23 @@ def Visit_atom(self, node): # pylint: disable=invalid-name if pytree_utils.NodeName(node.parent) == 'if_stmt': _SetSplitPenalty(node.children[-1], UNBREAKABLE) else: - _SetSplitPenalty(node.children[-1], COMPARISON) + _SetSplitPenalty(node.children[-1], ATOM) elif node.children[0].value in '[{' and len(node.children) == 2: # Keep empty containers together if we can. _SetUnbreakable(node.children[-1]) + def Visit_testlist_gexp(self, node): # pylint: disable=invalid-name + self.DefaultNodeVisit(node) + prev_was_comma = False + for child in node.children: + if isinstance(child, pytree.Leaf) and child.value == ',': + _SetUnbreakable(child) + prev_was_comma = True + else: + if prev_was_comma: + _SetSplitPenalty(_FirstChildNode(child), 0) + prev_was_comma = False + ############################################################################ # Helper methods that set the annotations. @@ -399,6 +458,26 @@ def RecExpression(node, first_child_leaf): RecExpression(node, _FirstChildNode(node)) +def _IncreasePenalty(node, amt): + """Increase a penalty annotation on children nodes.""" + + def RecExpression(node, first_child_leaf): + if node is first_child_leaf: + return + + if isinstance(node, pytree.Leaf): + if node.value in {'(', 'for', 'if'}: + return + penalty = pytree_utils.GetNodeAnnotation( + node, pytree_utils.Annotation.SPLIT_PENALTY, default=0) + _SetSplitPenalty(node, penalty + amt) + else: + for child in node.children: + RecExpression(child, first_child_leaf) + + RecExpression(node, _FirstChildNode(node)) + + def _RecAnnotate(tree, annotate_name, annotate_value): """Recursively set the given annotation on all leafs of the subtree. diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index c530ffc09..2033755fa 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1206,8 +1206,8 @@ def f(self, aaaaaaaaa, bbbbbbbbbbbbb, row): if True: if True: if row[4] is None or row[5] is None: - bbbbbbbbbbbbb['..............'] = row[5] if row[ - 5] is not None else 5 + bbbbbbbbbbbbb['..............'] = row[ + 5] if row[5] is not None else 5 """) uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 1dc692a9e..2eb2f9977 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -1253,9 +1253,8 @@ def main(unused_argv): an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A]) a_long_name_slicing = an_array_with_an_exceedingly_long_name[: ARBITRARY_CONSTANT_A] - bad_slice = ( - "I am a crazy, no good, string whats too long, etc." + " no really " - )[:ARBITRARY_CONSTANT_A] + bad_slice = ("I am a crazy, no good, string whats too long, etc." + + " no really ")[:ARBITRARY_CONSTANT_A] """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index 83fe94b7e..e57386480 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -211,9 +211,9 @@ def testFuncCalls(self): ('foo', None), ('(', UNBREAKABLE), ('1', None), - (',', None), + (',', UNBREAKABLE), ('2', None), - (',', None), + (',', UNBREAKABLE), ('3', None), (')', VERY_STRONGLY_CONNECTED), ]) @@ -229,9 +229,9 @@ def testFuncCalls(self): ('baz', DOTTED_NAME), ('(', STRONGLY_CONNECTED), ('1', None), - (',', None), + (',', UNBREAKABLE), ('2', None), - (',', None), + (',', UNBREAKABLE), ('3', None), (')', VERY_STRONGLY_CONNECTED), ]) From 3c93c158c2d424566ea2f5d06d6e251d2a58bbb1 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 20 Feb 2017 15:32:29 -0800 Subject: [PATCH 113/719] Don't force a split before a comment here. We already force a split before a comment elsewhere. --- CHANGELOG | 2 ++ yapf/yapflib/format_decision_state.py | 3 ++- yapftests/reformatter_buganizer_test.py | 22 ++++++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 3f8a6fe4b..83c2cec28 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -18,6 +18,8 @@ function call. - Prefer not to squish all of the elements in a function call over to the right-hand side. Split the arguments instead. +- We need to split a dictionary value if the first element is a comment anyway, + so don't force the split here. It's forced elsewhere. ## [0.16.0] 2017-02-05 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 8bbe8f7a0..a4c0310f4 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -210,7 +210,8 @@ def MustSplit(self): return True if (format_token.Subtype.DICTIONARY_VALUE in current.subtypes or - (previous.is_pseudo_paren and previous.value == '(')): + (previous.is_pseudo_paren and previous.value == '(' and + not current.is_comment)): # Split before the dictionary value if we can't fit every dictionary # entry on its own line. if not current.OpensScope(): diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 2eb2f9977..70fab37e7 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,28 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB35212469(self): + unformatted_code = textwrap.dedent("""\ + def _(): + X = { + 'retain': { + 'loadtest': # This is a comment in the middle of a dictionary entry + ('/some/path/to/a/file/that/is/needed/by/this/process') + } + } + """) + expected_formatted_code = textwrap.dedent("""\ + def _(): + X = { + 'retain': { + 'loadtest': # This is a comment in the middle of a dictionary entry + ('/some/path/to/a/file/that/is/needed/by/this/process') + } + } + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB31063453(self): unformatted_code = textwrap.dedent("""\ def _(): From 38b8b358f4df6b0c8871525522b7fdddba37dac5 Mon Sep 17 00:00:00 2001 From: CaselIT Date: Tue, 21 Feb 2017 13:45:13 +0100 Subject: [PATCH 114/719] Fix USE_TABS=True is ignored for continued indentation Fixes https://github.com/google/yapf/issues/328 --- CHANGELOG | 1 + yapf/yapflib/format_token.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 83c2cec28..b51517585 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -20,6 +20,7 @@ right-hand side. Split the arguments instead. - We need to split a dictionary value if the first element is a comment anyway, so don't force the split here. It's forced elsewhere. +- Ensure tabs are used for continued indentation when USE_TABS is True. ## [0.16.0] 2017-02-05 ### Added diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index ec9f0e466..a396a05c6 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -120,8 +120,9 @@ def AddWhitespacePrefix(self, newlines_before, spaces=0, indent_level=0): indent_level: (int) The indentation level. """ indent_char = '\t' if style.Get('USE_TABS') else ' ' + token_indent_char = indent_char if newlines_before > 0 else ' ' indent_before = ( - indent_char * indent_level * style.Get('INDENT_WIDTH') + ' ' * spaces) + indent_char * indent_level * style.Get('INDENT_WIDTH') + token_indent_char * spaces) if self.is_comment: comment_lines = [s.lstrip() for s in self.value.splitlines()] From 2814aca37ef94dc057551020dcc92db6b6605ee5 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 22 Mar 2017 11:41:07 -0700 Subject: [PATCH 115/719] Bump to v0.16.1 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b51517585..aa2c16bf9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.16.1] UNRELEASED +## [0.16.1] 2017-03-22 ### Changed - Improved performance of cloning the format decision state object. This improved the time in one *large* case from 273.485s to 234.652s. diff --git a/yapf/__init__.py b/yapf/__init__.py index 51265370b..10675f198 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.16.0' +__version__ = '0.16.1' def main(argv): From 14208e1289ff6f5a3b3d6bc0f7b7509b21affe12 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 28 Mar 2017 00:16:36 -0700 Subject: [PATCH 116/719] Include argument expansion operator similarly to function calls. --- setup.py | 3 ++- yapf/yapflib/format_decision_state.py | 9 ++++++--- yapftests/reformatter_buganizer_test.py | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index c73016b7a..30ea2508b 100644 --- a/setup.py +++ b/setup.py @@ -14,9 +14,10 @@ # limitations under the License. import codecs +import sys import unittest + from setuptools import setup, Command -import sys import yapf diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index a4c0310f4..ace829427 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -268,20 +268,23 @@ def MustSplit(self): if opening.matching_bracket.previous_token.value == ',': return True - if current.is_name and previous.value == ',': + if ((current.is_name or current.value in {'*', '**'}) and + previous.value == ','): # If we have a function call within an argument list and it won't fit on # the remaining line, but it will fit on a line by itself, then go ahead # and split before the call. opening = _GetOpeningBracket(current) if (opening and opening.value == '(' and opening.previous_token and - opening.previous_token.is_name): + (opening.previous_token.is_name or + opening.previous_token.value in {'*', '**'})): is_func_call = False token = current while token: if token.value == '(': is_func_call = True break - if not token.is_name and token.value != '.': + if (not (token.is_name or token.value in {'*', '**'}) and + token.value != '.'): break token = token.next_token diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 70fab37e7..1bdac2514 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,20 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB36215507(self): + code = textwrap.dedent("""\ + class X(): + + def _(): + aaaaaaaaaaaaa._bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb( + mmmmmmmmmmmmm, nnnnn, ooooooooo, + _(ppppppppppppppppppppppppppppppppppppp), + *(qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq), + **(qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq)) + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB35212469(self): unformatted_code = textwrap.dedent("""\ def _(): From 1641cbcc912de66debe2cfa178e2b24683525cb4 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 28 Mar 2017 00:41:18 -0700 Subject: [PATCH 117/719] Try to avoid splitting right after the start of a tuple. --- CHANGELOG | 6 ++++++ yapf/yapflib/split_penalty.py | 2 ++ yapftests/reformatter_basic_test.py | 15 +++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index aa2c16bf9..ed71b5794 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,12 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.16.2] UNRELEASED +### Fixed +- Treat expansion operators ('*', '**') in a similar way to function calls to + avoid splitting directly after the opening parenthesis. +- Increase the penalty for splitting after the start of a tuple. + ## [0.16.1] 2017-03-22 ### Changed - Improved performance of cloning the format decision state object. This diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 14c7a2c79..57b21a5cd 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -389,6 +389,8 @@ def Visit_atom(self, node): # pylint: disable=invalid-name if pytree_utils.NodeName(node.parent) == 'if_stmt': _SetSplitPenalty(node.children[-1], UNBREAKABLE) else: + if len(node.children) > 2: + _SetSplitPenalty(_FirstChildNode(node.children[1]), EXPR) _SetSplitPenalty(node.children[-1], ATOM) elif node.children[0].value in '[{' and len(node.children) == 2: # Keep empty containers together if we can. diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 2033755fa..36c03e9e5 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2084,6 +2084,21 @@ def __init__(self): finally: style.SetGlobalStyle(style.CreateChromiumStyle()) + def testTupleCohesion(self): + unformatted_code = textwrap.dedent("""\ + def f(): + this_is_a_very_long_function_name(an_extremely_long_variable_name, ( + 'a string that may be too long %s' % 'M15')) + """) + expected_code = textwrap.dedent("""\ + def f(): + this_is_a_very_long_function_name( + an_extremely_long_variable_name, + ('a string that may be too long %s' % 'M15')) + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From b9f7b56f55937d852a664aba164dbee138ca3fb1 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 31 Mar 2017 00:43:00 -0700 Subject: [PATCH 118/719] Increase penalty for excess characters --- CHANGELOG | 1 + yapf/yapflib/style.py | 2 +- yapftests/reformatter_basic_test.py | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index ed71b5794..a76f7d065 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,7 @@ - Treat expansion operators ('*', '**') in a similar way to function calls to avoid splitting directly after the opening parenthesis. - Increase the penalty for splitting after the start of a tuple. +- Increase penalty for excess characters. ## [0.16.1] 2017-03-22 ### Changed diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 0d4ee04f1..a84f2bce7 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -228,7 +228,7 @@ def CreatePEP8Style(): SPLIT_PENALTY_AFTER_UNARY_OPERATOR=10000, SPLIT_PENALTY_BEFORE_IF_EXPR=0, SPLIT_PENALTY_BITWISE_OPERATOR=300, - SPLIT_PENALTY_EXCESS_CHARACTER=3500, + SPLIT_PENALTY_EXCESS_CHARACTER=4500, SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=30, SPLIT_PENALTY_IMPORT_NAMES=0, SPLIT_PENALTY_LOGICAL_OPERATOR=300, diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 36c03e9e5..569f46581 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1163,6 +1163,24 @@ def bar(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + unformatted_code = textwrap.dedent("""\ + def _(): + if True: + if True: + if contract == allow_contract and attr_dict.get(if_attribute) == has_value: + return True + """) + expected_code = textwrap.dedent("""\ + def _(): + if True: + if True: + if contract == allow_contract and attr_dict.get( + if_attribute) == has_value: + return True + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + def testDictSetGenerator(self): code = textwrap.dedent("""\ foo = { From 7d55ea6e346d6d92ac607a11610bf8a7a301e215 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 2 Apr 2017 19:52:49 -0700 Subject: [PATCH 119/719] Check that the trailer has enough children. Closes #388 --- CHANGELOG | 1 + yapf/yapflib/split_penalty.py | 1 + yapf/yapflib/style.py | 1 + yapftests/reformatter_basic_test.py | 7 +++++++ 4 files changed, 10 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index a76f7d065..4c6ef8d09 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,7 @@ avoid splitting directly after the opening parenthesis. - Increase the penalty for splitting after the start of a tuple. - Increase penalty for excess characters. +- Check that we have enough children before trying to access them all. ## [0.16.1] 2017-03-22 ### Changed diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 57b21a5cd..d44bec502 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -178,6 +178,7 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name _SetSplitPenalty( _FirstChildNode(node.children[1]), ONE_ELEMENT_ARGUMENT) elif (pytree_utils.NodeName(node.children[0]) == 'LSQB' and + len(node.children[1].children) > 2 and (name.endswith('_test') or name.endswith('_expr'))): _SetStronglyConnected(node.children[1].children[0]) _SetStronglyConnected(node.children[1].children[2]) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index a84f2bce7..14be59e71 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -249,6 +249,7 @@ def CreateGoogleStyle(): def CreateChromiumStyle(): style = CreateGoogleStyle() + style['ALLOW_MULTILINE_DICTIONARY_KEYS'] = True style['INDENT_DICTIONARY_VALUE'] = True style['INDENT_WIDTH'] = 2 style['JOIN_MULTIPLE_LINES'] = False diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 569f46581..d22676684 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2117,6 +2117,13 @@ def f(): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + def testSubscriptExpression(self): + code = textwrap.dedent("""\ + foo = d[not a] + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From b017b86545941d4b51d958d9ce68f3b3c54582b5 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 13 Apr 2017 00:32:09 -0700 Subject: [PATCH 120/719] Remove trailing whitespaces from comments. --- CHANGELOG | 1 + yapf/yapflib/comment_splicer.py | 6 +++--- yapftests/reformatter_basic_test.py | 12 ++++++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4c6ef8d09..5507ba0e3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,7 @@ - Increase the penalty for splitting after the start of a tuple. - Increase penalty for excess characters. - Check that we have enough children before trying to access them all. +- Remove trailing whitespaces from comments. ## [0.16.1] 2017-03-22 ### Changed diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index a7b37a804..7c79e805d 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -229,13 +229,13 @@ def _CreateCommentsFromPrefix(comment_prefix, while index < len(lines): comment_block = [] while index < len(lines) and lines[index].lstrip().startswith('#'): - comment_block.append(lines[index]) + comment_block.append(lines[index].strip()) index += 1 if comment_block: new_lineno = comment_lineno + index - 1 - comment_block[0] = comment_block[0].lstrip() - comment_block[-1] = comment_block[-1].rstrip('\n') + comment_block[0] = comment_block[0].strip() + comment_block[-1] = comment_block[-1].strip() comment_leaf = pytree.Leaf( type=token.COMMENT, value='\n'.join(comment_block), diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index d22676684..5a2a9beb3 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -215,6 +215,18 @@ def testSingleComment(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testCommentsWithTrailingSpaces(self): + unformatted_code = textwrap.dedent("""\ + # Thing 1 + # Thing 2 + """) + expected_formatted_code = textwrap.dedent("""\ + # Thing 1 + # Thing 2 + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testCommentsInDataLiteral(self): code = textwrap.dedent("""\ def f(): From 4eb3e441f791eec7c60e664925983103ea6312f5 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 16 Apr 2017 18:29:47 -0700 Subject: [PATCH 121/719] Don't split if cont-indent is equal to open bracket. --- yapf/yapflib/format_decision_state.py | 2 +- yapftests/reformatter_basic_test.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index ace829427..3281940ba 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -251,7 +251,7 @@ def MustSplit(self): return False column = self.column - self.stack[-1].last_space - return column >= style.Get('CONTINUATION_INDENT_WIDTH') + return column > style.Get('CONTINUATION_INDENT_WIDTH') opening = _GetOpeningBracket(current) if opening: diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 5a2a9beb3..f06d44db2 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1495,6 +1495,17 @@ def testArgsAndKwargsFormatting(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + code = textwrap.dedent("""\ + def foo(): + return [ + Bar(xxx='some string', + yyy='another long string', + zzz='a third long string') + ] + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testCommentColumnLimitOverflow(self): code = textwrap.dedent("""\ def f(): From 10b691afdb57f6b9d0df5c1a1beb713e576fe93c Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 16 Apr 2017 18:51:53 -0700 Subject: [PATCH 122/719] Split before function call in list If the whole list cannot fit on a single line, then split before a function call. This prevents things like this: def foo(): return [ Bar( xxx='some string', yyy='another long string', zzz='a third long string'), Bar( xxx='some string', yyy='another long string', zzz='a third long string') ] --- CHANGELOG | 2 ++ yapf/yapflib/format_decision_state.py | 32 ++++++++++++++++++++ yapf/yapflib/format_token.py | 4 +-- yapf/yapflib/unwrapped_line.py | 8 ++--- yapftests/reformatter_basic_test.py | 27 +++++++++++++++++ yapftests/reformatter_buganizer_test.py | 39 +++++++++++++++++++++++++ 6 files changed, 106 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5507ba0e3..4db4addef 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,8 @@ - Increase penalty for excess characters. - Check that we have enough children before trying to access them all. - Remove trailing whitespaces from comments. +- Split before a function call in a list if the full list isn't able to fit on + a single line. ## [0.16.1] 2017-03-22 ### Changed diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 3281940ba..b5b040983 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -189,6 +189,38 @@ def MustSplit(self): # Split before and dedent the closing bracket. return self.stack[-1].split_before_closing_bracket + if (current.is_name or current.is_string) and previous.value == ',': + # If the list has function calls in it and the full list itself cannot + # fit on the line, then we want to split. Otherwise, we'll get something + # like this: + # + # X = [ + # Bar(xxx='some string', + # yyy='another long string', + # zzz='a third long string'), Bar( + # xxx='some string', + # yyy='another long string', + # zzz='a third long string') + # ] + # + # or when a string formatting syntax. + func_call_or_string_format = False + if current.is_name: + tok = current.next_token + while tok and (tok.is_name or tok.value == '.'): + tok = tok.next_token + func_call_or_string_format = tok.value == '(' + elif current.is_string: + tok = current.next_token + while tok and tok.is_string: + tok = tok.next_token + func_call_or_string_format = tok.value == '%' + if func_call_or_string_format: + open_bracket = unwrapped_line.IsSurroundedByBrackets(current) + if open_bracket and open_bracket.value in '[{': + if not self._FitsOnLine(open_bracket, open_bracket.matching_bracket): + return True + ########################################################################### # Dict/Set Splitting if (style.Get('EACH_DICT_ENTRY_ON_SEPARATE_LINE') and diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index a396a05c6..de270cf58 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -121,8 +121,8 @@ def AddWhitespacePrefix(self, newlines_before, spaces=0, indent_level=0): """ indent_char = '\t' if style.Get('USE_TABS') else ' ' token_indent_char = indent_char if newlines_before > 0 else ' ' - indent_before = ( - indent_char * indent_level * style.Get('INDENT_WIDTH') + token_indent_char * spaces) + indent_before = (indent_char * indent_level * style.Get('INDENT_WIDTH') + + token_indent_char * spaces) if self.is_comment: comment_lines = [s.lstrip() for s in self.value.splitlines()] diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 77b2f1e2e..3b3210d77 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -397,19 +397,19 @@ def IsSurroundedByBrackets(tok): if previous_token.value == '(': if paren_count == 0: - return True + return previous_token paren_count += 1 elif previous_token.value == '{': if brace_count == 0: - return True + return previous_token brace_count += 1 elif previous_token.value == '[': if sq_bracket_count == 0: - return True + return previous_token sq_bracket_count += 1 previous_token = previous_token.previous_token - return False + return None _LOGICAL_OPERATORS = frozenset({'and', 'or'}) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index f06d44db2..fe5d21ea6 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2147,6 +2147,33 @@ def testSubscriptExpression(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testListWithFunctionCalls(self): + unformatted_code = textwrap.dedent("""\ + def foo(): + return [ + Bar( + xxx='some string', + yyy='another long string', + zzz='a third long string'), Bar( + xxx='some string', + yyy='another long string', + zzz='a third long string') + ] + """) + expected_code = textwrap.dedent("""\ + def foo(): + return [ + Bar(xxx='some string', + yyy='another long string', + zzz='a third long string'), + Bar(xxx='some string', + yyy='another long string', + zzz='a third long string') + ] + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 1bdac2514..8eed74b3f 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,45 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB36806207(self): + unformatted_code = textwrap.dedent("""\ + def _(): + linearity_data = [[row] for row in [ + "%.1f mm" % (np.mean(linearity_values["pos_error"]) * 1000.0), + "%.1f mm" % (np.max(linearity_values["pos_error"]) * 1000.0), + "%.1f mm" % (np.mean(linearity_values["pos_error_chunk_mean"]) * 1000.0), + "%.1f mm" % (np.max(linearity_values["pos_error_chunk_max"]) * 1000.0), + "%.1f deg" % math.degrees(np.mean(linearity_values["rot_noise"])), + "%.1f deg" % math.degrees(np.max(linearity_values["rot_noise"])), + "%.1f deg" % math.degrees(np.mean(linearity_values["rot_drift"])), + "%.1f deg" % math.degrees(np.max(linearity_values["rot_drift"])), + "%.1f%%" % (np.max(linearity_values["pos_discontinuity"]) * 100.0), + "%.1f%%" % (np.max(linearity_values["rot_discontinuity"]) * 100.0) + ]] + """) + expected_code = textwrap.dedent("""\ + def _(): + linearity_data = [ + [row] + for row in [ + "%.1f mm" % (np.mean(linearity_values["pos_error"]) * 1000.0), + "%.1f mm" % (np.max(linearity_values["pos_error"]) * 1000.0), + "%.1f mm" % ( + np.mean(linearity_values["pos_error_chunk_mean"]) * 1000.0), + "%.1f mm" % ( + np.max(linearity_values["pos_error_chunk_max"]) * 1000.0), + "%.1f deg" % math.degrees(np.mean(linearity_values["rot_noise"])), + "%.1f deg" % math.degrees(np.max(linearity_values["rot_noise"])), + "%.1f deg" % math.degrees(np.mean(linearity_values["rot_drift"])), + "%.1f deg" % math.degrees(np.max(linearity_values["rot_drift"])), + "%.1f%%" % (np.max(linearity_values["pos_discontinuity"]) * 100.0), + "%.1f%%" % (np.max(linearity_values["rot_discontinuity"]) * 100.0) + ] + ] + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + def testB36215507(self): code = textwrap.dedent("""\ class X(): From 672e1e2dedd6f230fa5860ebe0890bceac20863f Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 17 Apr 2017 19:38:28 -0700 Subject: [PATCH 123/719] Try not to split around the '=' in a named assign. Closes #394 --- CHANGELOG | 1 + yapf/yapflib/split_penalty.py | 6 ++++-- yapftests/reformatter_pep8_test.py | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4db4addef..95aa19afe 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,7 @@ - Remove trailing whitespaces from comments. - Split before a function call in a list if the full list isn't able to fit on a single line. +- Trying not to split around the '=' of a named assign. ## [0.16.1] 2017-03-22 ### Changed diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index d44bec502..b5c1a6593 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -24,6 +24,7 @@ # TODO(morbo): Document the annotations in a centralized place. E.g., the # README file. UNBREAKABLE = 1000 * 1000 +NAMED_ASSIGN = 8500 DOTTED_NAME = 4000 VERY_STRONGLY_CONNECTED = 3500 STRONGLY_CONNECTED = 3000 @@ -141,8 +142,9 @@ def Visit_argument(self, node): # pylint: disable=invalid-name while index < len(node.children) - 1: child = node.children[index] if isinstance(child, pytree.Leaf) and child.value == '=': - _SetStronglyConnected(_FirstChildNode(node.children[index])) - _SetStronglyConnected(_FirstChildNode(node.children[index + 1])) + _SetSplitPenalty(_FirstChildNode(node.children[index]), NAMED_ASSIGN) + _SetSplitPenalty( + _FirstChildNode(node.children[index + 1]), NAMED_ASSIGN) index += 1 def Visit_dotted_name(self, node): # pylint: disable=invalid-name diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 49f084173..20fe6b563 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -329,6 +329,22 @@ def testSplitListsAndDictSetMakersIfCommaTerminated(self): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testSplitAroundNamedAssigns(self): + unformatted_code = textwrap.dedent("""\ + class a(): + def a(): return a( + aaaaaaaaaa=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) + """) + expected_formatted_code = textwrap.dedent("""\ + class a(): + def a(): + return a( + aaaaaaaaaa=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ) + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From 362bcb4c2bb730434e928d01e6598329f1fbea0a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 17 Apr 2017 19:48:43 -0700 Subject: [PATCH 124/719] Require a space between an equal and dot. --- yapf/yapflib/unwrapped_line.py | 3 +++ yapftests/reformatter_basic_test.py | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 3b3210d77..dc782a91b 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -226,6 +226,9 @@ def _SpaceRequiredBetween(left, right): if lval == '.' and rval == 'import': # Space after the '.' in an import statement. return True + if lval == '=' and rval == '.': + # Space between equal and '.' as in "X = ...". + return True if ((right.is_keyword or right.is_name) and (left.is_keyword or left.is_name)): # Don't merge two keywords/identifiers. diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index fe5d21ea6..6ad5ed787 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2174,6 +2174,16 @@ def foo(): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + def testEllipses(self): + unformatted_code = textwrap.dedent("""\ + X=... + """) + expected_code = textwrap.dedent("""\ + X = ... + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From 8ed2a5cf32b77cd81802f8be8e673ff106f344bf Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 18 Apr 2017 11:25:15 -0700 Subject: [PATCH 125/719] Check for None before accessing variable. --- yapf/yapflib/format_decision_state.py | 2 +- yapf/yapflib/split_penalty.py | 4 ++-- yapftests/reformatter_buganizer_test.py | 8 ++++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index b5b040983..562290576 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -214,7 +214,7 @@ def MustSplit(self): tok = current.next_token while tok and tok.is_string: tok = tok.next_token - func_call_or_string_format = tok.value == '%' + func_call_or_string_format = tok and tok.value == '%' if func_call_or_string_format: open_bracket = unwrapped_line.IsSurroundedByBrackets(current) if open_bracket and open_bracket.value in '[{': diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index b5c1a6593..3ef4d8c20 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -331,12 +331,12 @@ def Visit_comparison(self, node): # pylint: disable=invalid-name else: _IncreasePenalty(node, COMPARISON) - def Visit_star_expr(self, node): # pylint: disable-invalid-name + def Visit_star_expr(self, node): # pylint: disable=invalid-name # star_expr ::= '*' expr self.DefaultNodeVisit(node) _IncreasePenalty(node, STAR_EXPR) - def Visit_expr(self, node): # pylint: disable-invalid-name + def Visit_expr(self, node): # pylint: disable=invalid-name # expr ::= xor_expr ('|' xor_expr)* self.DefaultNodeVisit(node) _IncreasePenalty(node, EXPR) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 8eed74b3f..2d0cf9fb0 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,14 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB37460004(self): + code = textwrap.dedent("""\ + assert all(s not in (_SENTINEL, None) for s in + nested_schemas), 'Nested schemas should never contain None/_SENTINEL' + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB36806207(self): unformatted_code = textwrap.dedent("""\ def _(): From 49834238631974f0cf7f124b2021fa57466e57d8 Mon Sep 17 00:00:00 2001 From: Joachim Metz Date: Fri, 21 Apr 2017 07:56:11 +0200 Subject: [PATCH 126/719] Changes to prevent yapf splitting before the first argument in compound statements. --- yapf/yapflib/format_decision_state.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 562290576..1e27bb166 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -161,6 +161,11 @@ def MustSplit(self): # Split before the closing bracket if we can. return current.node_split_penalty != split_penalty.UNBREAKABLE + # Prevent yapf splitting before the first argument in compound statements. + if (style.Get('SPLIT_BEFORE_FIRST_ARGUMENT') and + self.line.first.value in _COMPOUND_STMTS): + return False + ########################################################################### # List Splitting if (style.Get('DEDENT_CLOSING_BRACKETS') or From 9b11bc3b655cae43eb92999d4c9a7f8601ff95c9 Mon Sep 17 00:00:00 2001 From: Joachim Metz Date: Fri, 21 Apr 2017 08:48:45 +0200 Subject: [PATCH 127/719] Added tests for split_before_first_argument changes --- yapftests/reformatter_basic_test.py | 44 +++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 6ad5ed787..5b326dc50 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2184,6 +2184,50 @@ def testEllipses(self): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + def testSplittingBeforeFirstArgumentOnFunctionCall(self): + """Tests split_before_first_argument on a function call.""" + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: chromium, split_before_first_argument: True}')) + unformatted_code = textwrap.dedent("""\ + a_very_long_function_name("long string with formatting {0:s}".format( + "mystring")) + """) + expected_formatted_code = textwrap.dedent("""\ + a_very_long_function_name( + "long string with formatting {0:s}".format("mystring")) + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + + def testSplittingBeforeFirstArgumentOnCompoundStatement(self): + """Tests split_before_first_argument on a compound statement.""" + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: chromium, split_before_first_argument: True}')) + unformatted_code = textwrap.dedent("""\ + if (long_argument_name_1 == 1 or + long_argument_name_2 == 2 or + long_argument_name_3 == 3 or + long_argument_name_4 == 4): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + if (long_argument_name_1 == 1 or long_argument_name_2 == 2 or + long_argument_name_3 == 3 or long_argument_name_4 == 4): + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + if __name__ == '__main__': unittest.main() From 28d594005dcf9655c4cb8375fd937cbeb730882c Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 25 Apr 2017 22:01:01 -0700 Subject: [PATCH 128/719] Check for None before accessing 'tok' --- yapf/yapflib/format_decision_state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 1e27bb166..c258cfdd3 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -214,7 +214,7 @@ def MustSplit(self): tok = current.next_token while tok and (tok.is_name or tok.value == '.'): tok = tok.next_token - func_call_or_string_format = tok.value == '(' + func_call_or_string_format = tok and tok.value == '(' elif current.is_string: tok = current.next_token while tok and tok.is_string: From 83e5ed02eaeb2da7f9e2b64db8129d2ad62604f3 Mon Sep 17 00:00:00 2001 From: Jimmy Zelinskie Date: Wed, 3 May 2017 15:40:27 -0400 Subject: [PATCH 129/719] Move vim plugin inside a rtp By moving the vim plugin into a directory structure that matches the vim runtime path, vim plugin managers can reference this repository directly for updates. Fixes #391. --- plugins/README.rst | 12 +++++++++++- plugins/{ => vim/autoload}/yapf.vim | 0 2 files changed, 11 insertions(+), 1 deletion(-) rename plugins/{ => vim/autoload}/yapf.vim (100%) diff --git a/plugins/README.rst b/plugins/README.rst index a9f63dd40..6d458f762 100644 --- a/plugins/README.rst +++ b/plugins/README.rst @@ -12,7 +12,17 @@ VIM === The ``vim`` plugin allows you to reformat a range of code. Place it into the -``.vim/autoload`` directory. You can add key bindings in the ``.vimrc`` file: +``.vim/autoload`` directory or use a plugin manager like Plug or Vundle: + +.. code-block:: vim + " Plug + Plug 'google/yapf', { 'rtp': 'plugins/vim', 'for': 'python' } + + " Vundle + Plugin 'google/yapf', { 'rtp': 'plugins/vim' } + + +You can add key bindings in the ``.vimrc`` file: .. code-block:: vim diff --git a/plugins/yapf.vim b/plugins/vim/autoload/yapf.vim similarity index 100% rename from plugins/yapf.vim rename to plugins/vim/autoload/yapf.vim From 17f98e21d63a14da2a6a78aeb745331024dfcd10 Mon Sep 17 00:00:00 2001 From: Joachim Metz Date: Sat, 22 Apr 2017 12:59:07 +0200 Subject: [PATCH 130/719] Changes to split before the first argument in function declarations. --- yapf/yapflib/format_decision_state.py | 4 +++- yapftests/reformatter_basic_test.py | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index c258cfdd3..0d89a2bb9 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -161,8 +161,10 @@ def MustSplit(self): # Split before the closing bracket if we can. return current.node_split_penalty != split_penalty.UNBREAKABLE - # Prevent yapf splitting before the first argument in compound statements. + # Prevent splitting before the first argument in compound statements + # with the exception of function declarations. if (style.Get('SPLIT_BEFORE_FIRST_ARGUMENT') and + self.line.first.value != 'def' and self.line.first.value in _COMPOUND_STMTS): return False diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 5b326dc50..c564f7ba1 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2204,6 +2204,28 @@ def testSplittingBeforeFirstArgumentOnFunctionCall(self): finally: style.SetGlobalStyle(style.CreateChromiumStyle()) + def testSplittingBeforeFirstArgumentOnFunctionDefinition(self): + """Tests split_before_first_argument on a function definition.""" + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: chromium, split_before_first_argument: True}')) + unformatted_code = textwrap.dedent("""\ + def _GetNumberOfSecondsFromElements(year, month, day, hours, + minutes, seconds, microseconds): + return + """) + expected_formatted_code = textwrap.dedent("""\ + def _GetNumberOfSecondsFromElements( + year, month, day, hours, minutes, seconds, microseconds): + return + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + def testSplittingBeforeFirstArgumentOnCompoundStatement(self): """Tests split_before_first_argument on a compound statement.""" try: From bab134d71a551cc137ff0d36abefe5a08b8641b4 Mon Sep 17 00:00:00 2001 From: Joachim Metz Date: Fri, 5 May 2017 06:50:13 +0200 Subject: [PATCH 131/719] Updated CHANGELOG --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 95aa19afe..c29b4d4f0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,8 @@ - Split before a function call in a list if the full list isn't able to fit on a single line. - Trying not to split around the '=' of a named assign. +- Changed split before the first argument behavior to ignore compound + statements like if and while, but not function declarations. ## [0.16.1] 2017-03-22 ### Changed From 998c4903983449d1f25dbc54d38bb12c678327a1 Mon Sep 17 00:00:00 2001 From: Joachim Metz Date: Sat, 22 Apr 2017 12:39:27 +0200 Subject: [PATCH 132/719] Changes to coalesce brackets not to line split before closing bracket --- yapf/yapflib/format_decision_state.py | 7 +++++- yapftests/reformatter_basic_test.py | 31 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index c258cfdd3..6ce24fc8c 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -499,7 +499,12 @@ def _AddTokenOnNewline(self, dry_run, must_split): previous.previous_token.OpensScope())): self.stack[-1].closing_scope_indent = max( 0, self.stack[-1].indent - style.Get('CONTINUATION_INDENT_WIDTH')) - self.stack[-1].split_before_closing_bracket = True + + split_before_closing_bracket = True + if style.Get('COALESCE_BRACKETS'): + split_before_closing_bracket = False + + self.stack[-1].split_before_closing_bracket = split_before_closing_bracket # Calculate the split penalty. penalty = current.split_penalty diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 5b326dc50..b1acde9bc 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2228,6 +2228,37 @@ def testSplittingBeforeFirstArgumentOnCompoundStatement(self): finally: style.SetGlobalStyle(style.CreateChromiumStyle()) + def testCoalesceBracketsOnDict(self): + """Tests coalesce_brackets on a dictionary.""" + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: chromium, coalesce_brackets: True}')) + unformatted_code = textwrap.dedent("""\ + date_time_values = { + u'year': year, + u'month': month, + u'day_of_month': day_of_month, + u'hours': hours, + u'minutes': minutes, + u'seconds': seconds + } + """) + expected_formatted_code = textwrap.dedent("""\ + date_time_values = { + u'year': year, + u'month': month, + u'day_of_month': day_of_month, + u'hours': hours, + u'minutes': minutes, + u'seconds': seconds} + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + if __name__ == '__main__': unittest.main() From 0e3b78bd2b1e05afe5107c661dac75c38ca4bc29 Mon Sep 17 00:00:00 2001 From: Joachim Metz Date: Fri, 5 May 2017 06:57:08 +0200 Subject: [PATCH 133/719] Updated CHANGELOG and changes to tests --- CHANGELOG | 1 + yapftests/yapf_test.py | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 95aa19afe..f54f29787 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,7 @@ - Split before a function call in a list if the full list isn't able to fit on a single line. - Trying not to split around the '=' of a named assign. +- Changed coalesce brackets not to line split before closing bracket. ## [0.16.1] 2017-03-22 ### Changed diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index fdd4fb98a..c9caa0358 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1017,8 +1017,7 @@ def testCoalesceBrackets(self): expected_formatted_code = textwrap.dedent("""\ some_long_function_name_foo({ 'first_argument_of_the_thing': id, - 'second_argument_of_the_thing': "some thing" - }) + 'second_argument_of_the_thing': "some thing"}) """) with utils.NamedTempFile(dirname=self.test_tmpdir, mode='w') as (f, name): f.write( From d30b5650d99dc0ae930a04bd06e76cbc1976a65e Mon Sep 17 00:00:00 2001 From: mpacer Date: Wed, 10 May 2017 10:02:33 -0700 Subject: [PATCH 134/719] Add ability to specify style via dict with string values --- yapf/yapflib/style.py | 27 ++++++++++++++++++--------- yapftests/style_test.py | 24 ++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 14be59e71..fb056c7f8 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -375,17 +375,26 @@ def GlobalStyles(): if not def_style: return _style return _GLOBAL_STYLE_FACTORY() - style_factory = _STYLE_NAME_TO_FACTORY.get(style_config.lower()) - if style_factory is not None: - return style_factory() - if style_config.startswith('{'): - # Most likely a style specification from the command line. - config = _CreateConfigParserFromConfigString(style_config) - else: - # Unknown config name: assume it's a file name then. - config = _CreateConfigParserFromConfigFile(style_config) + if isinstance(style_config, dict): + config = _CreateConfigParserFromConfigDict(style_config) + elif isinstance(style_config, str): + style_factory = _STYLE_NAME_TO_FACTORY.get(style_config.lower()) + if style_factory is not None: + return style_factory() + if style_config.startswith('{'): + # Most likely a style specification from the command line. + config = _CreateConfigParserFromConfigString(style_config) + else: + # Unknown config name: assume it's a file name then. + config = _CreateConfigParserFromConfigFile(style_config) return _CreateStyleFromConfigParser(config) +def _CreateConfigParserFromConfigDict(config_dict): + config = py3compat.ConfigParser() + config.add_section('style') + for key, value in config_dict.items(): + config.set('style',key, value) + return config def _CreateConfigParserFromConfigString(config_string): """Given a config string from the command line, return a config parser.""" diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 2bbbd508d..b412ddf43 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -207,6 +207,30 @@ def testErrorUnknownStyleOption(self): style.CreateStyleFromConfig(filepath) +class StyleFromDict(unittest.TestCase): + + @classmethod + def setUpClass(cls): + style.SetGlobalStyle(style.CreatePEP8Style()) + + def testDefaultBasedOnStyle(self): + config_dict = { + 'based_on_style':'pep8', + 'indent_width': '2', + 'blank_line_before_nested_class_or_def': 'True' + } + cfg = style.CreateStyleFromConfig(config_dict) + self.assertTrue(_LooksLikeChromiumStyle(cfg)) + self.assertEqual(cfg['INDENT_WIDTH'], 2) + + def testDefaultBasedOnStyleBadDict(self): + self.assertRaisesRegexp(style.StyleConfigError, 'Unknown style option', + style.CreateStyleFromConfig, + {'based_on_styl': 'pep8'}) + self.assertRaisesRegexp(style.StyleConfigError, 'not a valid', + style.CreateStyleFromConfig, {'INDENT_WIDTH': 'FOUR'}) + + class StyleFromCommandLine(unittest.TestCase): @classmethod From d6ebbdb1b07ce9add2bd2d4dc43a592f7fbc7734 Mon Sep 17 00:00:00 2001 From: mpacer Date: Wed, 10 May 2017 10:08:23 -0700 Subject: [PATCH 135/719] run yapf on style --- yapf/yapflib/style.py | 14 ++++++++------ yapftests/style_test.py | 13 +++++++------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index fb056c7f8..1c7b17f98 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -376,7 +376,7 @@ def GlobalStyles(): return _style return _GLOBAL_STYLE_FACTORY() if isinstance(style_config, dict): - config = _CreateConfigParserFromConfigDict(style_config) + config = _CreateConfigParserFromConfigDict(style_config) elif isinstance(style_config, str): style_factory = _STYLE_NAME_TO_FACTORY.get(style_config.lower()) if style_factory is not None: @@ -389,12 +389,14 @@ def GlobalStyles(): config = _CreateConfigParserFromConfigFile(style_config) return _CreateStyleFromConfigParser(config) + def _CreateConfigParserFromConfigDict(config_dict): - config = py3compat.ConfigParser() - config.add_section('style') - for key, value in config_dict.items(): - config.set('style',key, value) - return config + config = py3compat.ConfigParser() + config.add_section('style') + for key, value in config_dict.items(): + config.set('style', key, value) + return config + def _CreateConfigParserFromConfigString(config_string): """Given a config string from the command line, return a config parser.""" diff --git a/yapftests/style_test.py b/yapftests/style_test.py index b412ddf43..62af59b03 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -215,20 +215,21 @@ def setUpClass(cls): def testDefaultBasedOnStyle(self): config_dict = { - 'based_on_style':'pep8', - 'indent_width': '2', - 'blank_line_before_nested_class_or_def': 'True' - } + 'based_on_style': 'pep8', + 'indent_width': '2', + 'blank_line_before_nested_class_or_def': 'True' + } cfg = style.CreateStyleFromConfig(config_dict) self.assertTrue(_LooksLikeChromiumStyle(cfg)) self.assertEqual(cfg['INDENT_WIDTH'], 2) def testDefaultBasedOnStyleBadDict(self): self.assertRaisesRegexp(style.StyleConfigError, 'Unknown style option', - style.CreateStyleFromConfig, + style.CreateStyleFromConfig, {'based_on_styl': 'pep8'}) self.assertRaisesRegexp(style.StyleConfigError, 'not a valid', - style.CreateStyleFromConfig, {'INDENT_WIDTH': 'FOUR'}) + style.CreateStyleFromConfig, + {'INDENT_WIDTH': 'FOUR'}) class StyleFromCommandLine(unittest.TestCase): From 883108dc1f7c4302de286b4015b6eb68f8fe3943 Mon Sep 17 00:00:00 2001 From: mpacer Date: Fri, 12 May 2017 12:08:06 -0700 Subject: [PATCH 136/719] allow nonstring valuesvia coercion --- yapf/yapflib/style.py | 2 +- yapftests/style_test.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 1c7b17f98..a3d59ed11 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -394,7 +394,7 @@ def _CreateConfigParserFromConfigDict(config_dict): config = py3compat.ConfigParser() config.add_section('style') for key, value in config_dict.items(): - config.set('style', key, value) + config.set('style', key, str(value)) return config diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 62af59b03..02ecbae7e 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -216,8 +216,8 @@ def setUpClass(cls): def testDefaultBasedOnStyle(self): config_dict = { 'based_on_style': 'pep8', - 'indent_width': '2', - 'blank_line_before_nested_class_or_def': 'True' + 'indent_width': 2, + 'blank_line_before_nested_class_or_def': True } cfg = style.CreateStyleFromConfig(config_dict) self.assertTrue(_LooksLikeChromiumStyle(cfg)) From 2a33f94b0ee2f449a89d7542481c1a6e67f93395 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 19 May 2017 14:53:29 -0700 Subject: [PATCH 137/719] Bump version to v0.16.2 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 81673b8f2..a7f5b5669 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.16.2] UNRELEASED +## [0.16.2] 2017-05-19 ### Fixed - Treat expansion operators ('*', '**') in a similar way to function calls to avoid splitting directly after the opening parenthesis. diff --git a/yapf/__init__.py b/yapf/__init__.py index 10675f198..92580523c 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.16.1' +__version__ = '0.16.2' def main(argv): From bf6dd97e31b371671128dec358cb945751f51e32 Mon Sep 17 00:00:00 2001 From: "Nathaniel J. Smith" Date: Wed, 14 Jun 2017 19:29:25 -0700 Subject: [PATCH 138/719] Update PEP 8 style to match modern PEP 8 PEP 8 was updated last year to prefer that line splits come before binary operators, rather than after: https://www.python.org/dev/peps/pep-0008/#should-a-line-break-before-or-after-a-binary-operator https://github.com/python/peps/commit/c59c4376ad233a62ca4b3a6060c81368bd21e85b Really there should be a way to do this for other binary operations... for example, even with this setting, YAPF wants to do: ``` orig_extracted = ( - extract_tb(orig.__traceback__) - + extract_tb(orig.exceptions[0].__traceback__) - + extract_tb(orig.exceptions[0].exceptions[1].__traceback__)) + extract_tb(orig.__traceback__) + + extract_tb(orig.exceptions[0].__traceback__) + + extract_tb(orig.exceptions[0].exceptions[1].__traceback__)) ``` which is exactly what the example in PEP 8 says not to do. But this patch brings YAPF's PEP 8 style closer to what PEP 8 says. --- yapf/yapflib/style.py | 8 ++++++-- yapftests/reformatter_pep8_test.py | 12 ++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index a3d59ed11..762b05a42 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -219,10 +219,10 @@ def CreatePEP8Style(): SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=False, SPACES_BEFORE_COMMENT=2, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False, - SPLIT_BEFORE_BITWISE_OPERATOR=False, + SPLIT_BEFORE_BITWISE_OPERATOR=True, SPLIT_BEFORE_DICT_SET_GENERATOR=True, SPLIT_BEFORE_FIRST_ARGUMENT=False, - SPLIT_BEFORE_LOGICAL_OPERATOR=False, + SPLIT_BEFORE_LOGICAL_OPERATOR=True, SPLIT_BEFORE_NAMED_ASSIGNS=True, SPLIT_PENALTY_AFTER_OPENING_BRACKET=30, SPLIT_PENALTY_AFTER_UNARY_OPERATOR=10000, @@ -244,6 +244,8 @@ def CreateGoogleStyle(): style['I18N_COMMENT'] = r'#\..*' style['I18N_FUNCTION_CALL'] = ['N_', '_'] style['SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET'] = False + style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False + style['SPLIT_BEFORE_BITWISE_OPERATOR'] = False return style @@ -267,6 +269,8 @@ def CreateFacebookStyle(): style['SPLIT_PENALTY_AFTER_OPENING_BRACKET'] = 0 style['SPLIT_PENALTY_BEFORE_IF_EXPR'] = 30 style['SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT'] = 30 + style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False + style['SPLIT_BEFORE_BITWISE_OPERATOR'] = False return style diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 20fe6b563..431ff9952 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -168,8 +168,8 @@ def g(): expected_formatted_code = textwrap.dedent("""\ def f(): def g(): - while (xxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz]) == 'aaaaaaaaaaa' and - xxxxxxxxxxxxxxxxxxxx( + while (xxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz]) == 'aaaaaaaaaaa' + and xxxxxxxxxxxxxxxxxxxx( yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): pass """) @@ -205,8 +205,8 @@ def h(): dosomething(connection) """) expected_formatted_code = textwrap.dedent("""\ - if (aaaaaaaaaaaaaa + bbbbbbbbbbbbbbbb == ccccccccccccccccc and xxxxxxxxxxxxx or - yyyyyyyyyyyyyyyyy): + if (aaaaaaaaaaaaaa + bbbbbbbbbbbbbbbb == ccccccccccccccccc and xxxxxxxxxxxxx + or yyyyyyyyyyyyyyyyy): pass elif (xxxxxxxxxxxxxxx( aaaaaaaaaaa, bbbbbbbbbbbbbb, cccccccccccc, dddddddddd=None)): @@ -303,8 +303,8 @@ def foo(): """) expected_formatted_code = textwrap.dedent("""\ def foo(): - df = df[(df['campaign_status'] == 'LIVE') & - (df['action_status'] == 'LIVE')] + df = df[(df['campaign_status'] == 'LIVE') + & (df['action_status'] == 'LIVE')] """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) From 7cab6d1064ed4865deabc70a3ca0c52ebe612032 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 12 Jul 2017 23:46:43 -0700 Subject: [PATCH 139/719] Account for multiple continuation markers. Closes #411 --- CHANGELOG | 4 ++++ yapf/yapflib/reformatter.py | 3 +++ yapftests/reformatter_basic_test.py | 9 +++++++++ 3 files changed, 16 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 95aa19afe..bbed4ac41 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,10 @@ - Split before a function call in a list if the full list isn't able to fit on a single line. - Trying not to split around the '=' of a named assign. +- A token that ends in a continuation marker may have more than one newline in + it, thus changing its "lineno" value. This can happen if multiple + continuation markers are used with no intervening tokens. Adjust the line + number to account for the lines covered by those markers. ## [0.16.1] 2017-03-22 ### Changed diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index fd8f3178a..1235abd83 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -130,6 +130,9 @@ def _RetainVerticalSpacingBetweenTokens(cur_tok, prev_tok): else: cur_lineno = cur_tok.lineno + if prev_tok.value.endswith('\\'): + prev_lineno = prev_lineno + prev_tok.value.count('\n') + cur_tok.AdjustNewlinesBefore(cur_lineno - prev_lineno) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 5b326dc50..87a97c028 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1091,6 +1091,15 @@ def fn(arg): uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testMultipleContinuationMarkers(self): + code = textwrap.dedent("""\ + xyz = \\ + \\ + some_thing() + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testEmptyContainers(self): code = textwrap.dedent("""\ flags.DEFINE_list( From b07883693c153e9a42f2f1f313cb4c2f182b87d1 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 12 Jul 2017 23:58:17 -0700 Subject: [PATCH 140/719] Add filename information to ParseError exception. Closes #413 --- CHANGELOG | 11 +++++------ yapf/yapflib/yapf_api.py | 7 ++++++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9440470de..73bd2e550 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,8 @@ # This project adheres to [Semantic Versioning](http://semver.org/). ## [0.16.2] 2017-05-19 +### Changed +- Add filename information to a ParseError excetion. ### Fixed - Treat expansion operators ('*', '**') in a similar way to function calls to avoid splitting directly after the opening parenthesis. @@ -13,16 +15,13 @@ - Split before a function call in a list if the full list isn't able to fit on a single line. - Trying not to split around the '=' of a named assign. -<<<<<<< HEAD +- Changed split before the first argument behavior to ignore compound + statements like if and while, but not function declarations. +- Changed coalesce brackets not to line split before closing bracket. - A token that ends in a continuation marker may have more than one newline in it, thus changing its "lineno" value. This can happen if multiple continuation markers are used with no intervening tokens. Adjust the line number to account for the lines covered by those markers. -======= -- Changed split before the first argument behavior to ignore compound - statements like if and while, but not function declarations. -- Changed coalesce brackets not to line split before closing bracket. ->>>>>>> 5683a4c62c710faedcf65142f3636712eaa608e8 ## [0.16.1] 2017-03-22 ### Changed diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index dd91849ea..f0922c25b 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -36,6 +36,7 @@ import re import sys +from lib2to3.pgen2 import parse from lib2to3.pgen2 import tokenize from yapf.yapflib import blank_line_calculator @@ -123,7 +124,11 @@ def FormatCode(unformatted_source, style.SetGlobalStyle(style.CreateStyleFromConfig(style_config)) if not unformatted_source.endswith('\n'): unformatted_source += '\n' - tree = pytree_utils.ParseCodeToTree(unformatted_source) + + try: + tree = pytree_utils.ParseCodeToTree(unformatted_source) + except parse.ParseError as e: + raise parse.ParseError(filename + ': ' + e.message) # Run passes on the tree, modifying it in place. comment_splicer.SpliceComments(tree) From a19d72e6d8580bb0ed512fe394d0d39075a29f87 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 13 Jul 2017 00:19:11 -0700 Subject: [PATCH 141/719] Take pseudo-parens into account when splitting after a comment --- CHANGELOG | 1 + yapf/yapflib/unwrapped_line.py | 4 +++- yapftests/reformatter_basic_test.py | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 73bd2e550..93791e873 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -22,6 +22,7 @@ it, thus changing its "lineno" value. This can happen if multiple continuation markers are used with no intervening tokens. Adjust the line number to account for the lines covered by those markers. +- Make sure to split after a comment even for "pseudo" parentheses. ## [0.16.1] 2017-03-22 ### Changed diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index dc782a91b..e68f48e8c 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -331,7 +331,9 @@ def _SpaceRequiredBetween(left, right): def _MustBreakBefore(prev_token, cur_token): """Return True if a line break is required before the current token.""" - if prev_token.is_comment: + if prev_token.is_comment or ( + prev_token.previous_token and prev_token.is_pseudo_paren and + prev_token.previous_token.is_comment): # Must break if the previous token was a comment. return True if (cur_token.is_string and prev_token.is_string and diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 25486ebc0..1361219ef 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2290,6 +2290,25 @@ def testCoalesceBracketsOnDict(self): finally: style.SetGlobalStyle(style.CreateChromiumStyle()) + def testSplitAfterComment(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: chromium, coalesce_brackets: True, ' + 'dedent_closing_brackets: true}')) + code = textwrap.dedent("""\ + if __name__ == "__main__": + with another_resource: + account = { + "validUntil": + int(time() + (6 * 7 * 24 * 60 * 60)) # in 6 weeks time + } + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + if __name__ == '__main__': unittest.main() From 55c05584e222479dd4e3e0a0bc4260290569a945 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 13 Jul 2017 00:45:39 -0700 Subject: [PATCH 142/719] Bump version to 0.16.3 --- CHANGELOG | 15 +++++++++------ yapf/__init__.py | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 93791e873..f54ccfda9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,10 +2,18 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.16.2] 2017-05-19 +## [0.16.3] 2017-07-13 ### Changed - Add filename information to a ParseError excetion. ### Fixed +- A token that ends in a continuation marker may have more than one newline in + it, thus changing its "lineno" value. This can happen if multiple + continuation markers are used with no intervening tokens. Adjust the line + number to account for the lines covered by those markers. +- Make sure to split after a comment even for "pseudo" parentheses. + +## [0.16.2] 2017-05-19 +### Fixed - Treat expansion operators ('*', '**') in a similar way to function calls to avoid splitting directly after the opening parenthesis. - Increase the penalty for splitting after the start of a tuple. @@ -18,11 +26,6 @@ - Changed split before the first argument behavior to ignore compound statements like if and while, but not function declarations. - Changed coalesce brackets not to line split before closing bracket. -- A token that ends in a continuation marker may have more than one newline in - it, thus changing its "lineno" value. This can happen if multiple - continuation markers are used with no intervening tokens. Adjust the line - number to account for the lines covered by those markers. -- Make sure to split after a comment even for "pseudo" parentheses. ## [0.16.1] 2017-03-22 ### Changed diff --git a/yapf/__init__.py b/yapf/__init__.py index 92580523c..a89582f2c 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.16.2' +__version__ = '0.16.3' def main(argv): From bc90bebf18ea5e15bfa1e8e6183f70fe72900032 Mon Sep 17 00:00:00 2001 From: Kevin Cox Date: Fri, 21 Jul 2017 13:50:47 +0100 Subject: [PATCH 143/719] Make yapf put the correct number of blank lines at --lines boundaries. This allows YAPF to have the correct line counts in most cases. Namely lines can be deleted only if they are in the range, but if either side of a range needs correcting of blank lines more lines can be inserted to get to the correct number. --- CHANGELOG | 4 ++ yapf/yapflib/reformatter.py | 30 +++++++--- yapf/yapflib/yapf_api.py | 48 ++++++---------- yapftests/blank_line_calculator_test.py | 74 +++++++++++++++++++++++++ yapftests/yapf_test.py | 7 ++- 5 files changed, 122 insertions(+), 41 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f54ccfda9..3a3ba8fcf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.16.4] Unreleased +### Changed +- Adjust blank lines on formatting boundaries when using the `--lines` option. + ## [0.16.3] 2017-07-13 ### Changed - Add filename information to a ParseError excetion. diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 1235abd83..2f0cc43d7 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -36,12 +36,14 @@ from yapf.yapflib import verifier -def Reformat(uwlines, verify=False): +def Reformat(uwlines, verify=False, lines=None): """Reformat the unwrapped lines. Arguments: uwlines: (list of unwrapped_line.UnwrappedLine) Lines we want to format. verify: (bool) True if reformatted code should be verified for syntax. + lines: (set of int) The lines which can be modified or None if there is no + line range restriction. Returns: A string representing the reformatted code. @@ -66,14 +68,15 @@ def Reformat(uwlines, verify=False): if prev_uwline and prev_uwline.disable: # Keep the vertical spacing between a disabled and enabled formatting # region. - _RetainVerticalSpacingBetweenTokens(uwline.first, prev_uwline.last) + _RetainRequiredVerticalSpacingBetweenTokens( + uwline.first, prev_uwline.last, lines) if any(tok.is_comment for tok in uwline.tokens): _RetainVerticalSpacingBeforeComments(uwline) if (_LineContainsI18n(uwline) or uwline.disable or _LineHasContinuationMarkers(uwline)): _RetainHorizontalSpacing(uwline) - _RetainVerticalSpacing(uwline, prev_uwline) + _RetainRequiredVerticalSpacing(uwline, prev_uwline, lines) _EmitLineUnformatted(state) elif _CanPlaceOnSingleLine(uwline) and not any(tok.must_split for tok in uwline.tokens): @@ -87,7 +90,7 @@ def Reformat(uwlines, verify=False): state = format_decision_state.FormatDecisionState(uwline, indent_amt) state.MoveStateToNextToken() _RetainHorizontalSpacing(uwline) - _RetainVerticalSpacing(uwline, prev_uwline) + _RetainRequiredVerticalSpacing(uwline, prev_uwline, None) _EmitLineUnformatted(state) final_lines.append(uwline) @@ -101,17 +104,17 @@ def _RetainHorizontalSpacing(uwline): tok.RetainHorizontalSpacing(uwline.first.column, uwline.depth) -def _RetainVerticalSpacing(cur_uwline, prev_uwline): +def _RetainRequiredVerticalSpacing(cur_uwline, prev_uwline, lines): prev_tok = None if prev_uwline is not None: prev_tok = prev_uwline.last for cur_tok in cur_uwline.tokens: - _RetainVerticalSpacingBetweenTokens(cur_tok, prev_tok) + _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines) prev_tok = cur_tok -def _RetainVerticalSpacingBetweenTokens(cur_tok, prev_tok): - """Retain vertical spacing between two tokens.""" +def _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines): + """Retain vertical spacing between two tokens if not in editable range.""" if prev_tok is None: return @@ -133,7 +136,16 @@ def _RetainVerticalSpacingBetweenTokens(cur_tok, prev_tok): if prev_tok.value.endswith('\\'): prev_lineno = prev_lineno + prev_tok.value.count('\n') - cur_tok.AdjustNewlinesBefore(cur_lineno - prev_lineno) + required_newlines = cur_lineno - prev_lineno + + if lines and (cur_lineno in lines or prev_lineno in lines): + desired_newlines = cur_tok.whitespace_prefix.count('\n') + whitespace_lines = range(prev_lineno + 1, cur_lineno) + deletable_lines = len(lines.intersection(whitespace_lines)) + required_newlines = max(required_newlines - deletable_lines, + desired_newlines) + + cur_tok.AdjustNewlinesBefore(required_newlines) def _RetainVerticalSpacingBeforeComments(uwline): diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index f0922c25b..cb10e8bff 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -141,8 +141,9 @@ def FormatCode(unformatted_source, for uwl in uwlines: uwl.CalculateFormattingInformation() + lines = _LineRangesToSet(lines) _MarkLinesToFormat(uwlines, lines) - reformatted_source = reformatter.Reformat(uwlines, verify) + reformatted_source = reformatter.Reformat(uwlines, verify, lines) if unformatted_source == reformatted_source: return '' if print_diff else reformatted_source, False @@ -210,40 +211,25 @@ def ReadFile(filename, logger=None): ENABLE_PATTERN = r'^#.*\byapf:\s*enable\b' +def _LineRangesToSet(line_ranges): + """Return a set of lines in the range.""" + + if line_ranges is None: + return None + + line_set = set() + for low, high in sorted(line_ranges): + line_set.update(range(low, high + 1)) + + return line_set + + def _MarkLinesToFormat(uwlines, lines): """Skip sections of code that we shouldn't reformat.""" if lines: for uwline in uwlines: - uwline.disable = True - - # Sort and combine overlapping ranges. - lines = sorted(lines) - line_ranges = [lines[0]] if len(lines[0]) else [] - index = 1 - while index < len(lines): - current = line_ranges[-1] - if lines[index][0] <= current[1]: - # The ranges overlap, so combine them. - line_ranges[-1] = (current[0], max(lines[index][1], current[1])) - else: - line_ranges.append(lines[index]) - index += 1 - - # Mark lines to format as not being disabled. - index = 0 - for start, end in sorted(line_ranges): - while index < len(uwlines) and uwlines[index].last.lineno < start: - index += 1 - if index >= len(uwlines): - break - - while index < len(uwlines): - if uwlines[index].lineno > end: - break - if (uwlines[index].lineno >= start or - uwlines[index].last.lineno >= start): - uwlines[index].disable = False - index += 1 + uwline.disable = not ( + lines.intersection(range(uwline.lineno, uwline.last.lineno + 1))) # Now go through the lines and disable any lines explicitly marked as # disabled. diff --git a/yapftests/blank_line_calculator_test.py b/yapftests/blank_line_calculator_test.py index 07710ea07..3bdff94b3 100644 --- a/yapftests/blank_line_calculator_test.py +++ b/yapftests/blank_line_calculator_test.py @@ -18,6 +18,7 @@ from yapf.yapflib import reformatter from yapf.yapflib import style +from yapf.yapflib import yapf_api from yapftests import yapf_test_helper @@ -276,6 +277,79 @@ class DeployAPIHTTPError(Error): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testLinesOnRangeBoundary(self): + unformatted_code = textwrap.dedent(u"""\ + def A(): + pass + + def B(): # 4 + pass # 5 + + def C(): + pass + def D(): # 9 + pass # 10 + def E(): + pass + """) + expected_formatted_code = textwrap.dedent(u"""\ + def A(): + pass + + + def B(): # 4 + pass # 5 + + + def C(): + pass + + + def D(): # 9 + pass # 10 + + + def E(): + pass + """) + code, changed = yapf_api.FormatCode( + unformatted_code, lines=[(4, 5), (9, 10)]) + self.assertCodeEqual(expected_formatted_code, code) + self.assertTrue(changed) + + def testLinesRangeBoundaryNotOutside(self): + unformatted_code = textwrap.dedent(u"""\ + def A(): + pass + + + + def B(): # 6 + pass # 7 + + + + def C(): + pass + """) + expected_formatted_code = textwrap.dedent(u"""\ + def A(): + pass + + + + def B(): # 6 + pass # 7 + + + + def C(): + pass + """) + code, changed = yapf_api.FormatCode(unformatted_code, lines=[(6, 7)]) + self.assertCodeEqual(expected_formatted_code, code) + self.assertFalse(changed) + if __name__ == '__main__': unittest.main() diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index c9caa0358..0ec093a58 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -365,7 +365,7 @@ def assertYapfReformats(self, unformatted, expected, extra_options=None): stderr=subprocess.PIPE) reformatted_code, stderrdata = p.communicate(unformatted.encode('utf-8')) self.assertEqual(stderrdata, b'') - self.assertEqual(reformatted_code.decode('utf-8'), expected) + self.assertMultiLineEqual(reformatted_code.decode('utf-8'), expected) def testUnicodeEncodingPipedToFile(self): unformatted_code = textwrap.dedent(u"""\ @@ -775,6 +775,8 @@ def f(): """) expected_formatted_code = textwrap.dedent("""\ a = line_to_format + + def f(): x = y + 42; z = n * 42 if True: a += 1 ; b += 1 ; c += 1 @@ -797,6 +799,8 @@ def f(): ''') expected_formatted_code = textwrap.dedent('''\ foo = 42 + + def f(): email_text += """This is a really long docstring that goes over the column limit and is multi-line.

Czar: """+despot["Nicholas"]+"""
@@ -1041,6 +1045,7 @@ def bar(): """) expected_formatted_code = textwrap.dedent("""\ def foo(): + def bar(): return {msg_id: author for author, msg_id in reader} """) From 031428e39e19ff2889c9884815407a5a1c80977a Mon Sep 17 00:00:00 2001 From: Jesse Kinkead Date: Fri, 28 Jul 2017 15:23:21 -0700 Subject: [PATCH 144/719] Add a git pre-commit hook. --- plugins/README.rst | 16 ++++++++++++ plugins/pre-commit.sh | 58 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 plugins/pre-commit.sh diff --git a/plugins/README.rst b/plugins/README.rst index 6d458f762..157875412 100644 --- a/plugins/README.rst +++ b/plugins/README.rst @@ -38,3 +38,19 @@ It is compatible with both Sublime Text 2 and 3. The plugin can be easily installed by using *Sublime Package Control*. Check the project page of the plugin for more information: https://github.com/jason-kane/PyYapf + +=================== +git Pre-Commit Hook +=================== + +The ``git`` pre-commit hook automatically formats your Python files before they +are committed to your local repository. Any changes ``yapf`` makes to the files +will stay unstaged so that you can diff them manually. + +To install, simply download the raw file and copy it into your git hooks directory: + +.. code-block:: bash + + # From the root of your git project. + curl -o https://raw.githubusercontent.com/google/yapf/master/plugins/pre-commit.sh + mv pre-commit.sh .git/hooks/pre-commit diff --git a/plugins/pre-commit.sh b/plugins/pre-commit.sh new file mode 100644 index 000000000..24976b51f --- /dev/null +++ b/plugins/pre-commit.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +# Git pre-commit hook to check staged Python files for formatting issues with yapf. +# +# INSTALLING: Copy this script into `.git/hooks/pre-commit`, and mark it as executable. +# +# This requires that yapf is installed and runnable in the environment running the pre-commit hook. +# +# When running, this first checks for unstaged changes to staged files, and if there are any, it +# will exit with an error. Files with unstaged changes will be printed. +# +# If all staged files have no unstaged changes, it will run yapf against them, leaving the +# formatting changes unstaged. Changed files will be printed. +# +# BUGS: This does not leave staged changes alone when used with the -a flag to git commit, due to +# the fact that git stages ALL unstaged files when that flag is used. + +# Find all staged Python files, and exit early if there aren't any. +PYTHON_FILES=(`git diff --name-only --cached --diff-filter=AM | grep --color=never '.py$'`) +if [ ! "$PYTHON_FILES" ]; then + exit 0 +fi + +# Verify that yapf is installed; if not, warn and exit. +if [ -z $(which yapf) ]; then + echo 'yapf not on path; can not format. Please install yapf:' + echo ' pip install yapf' + exit 2 +fi + +# Check for unstaged changes to files in the index. +CHANGED_FILES=(`git diff --name-only ${PYTHON_FILES[@]}`) +if [ "$CHANGED_FILES" ]; then + echo 'You have unstaged changes to some files in your commit; skipping auto-format.' + echo 'Please stage, stash, or revert these changes.' + echo 'You may find `git stash -k` helpful here.' + echo + echo 'Files with unstaged changes:' + for file in ${CHANGED_FILES[@]}; do + echo " $file" + done + exit 1 +fi +# Format all staged files, then exit with an error code if any have uncommitted changes. +echo 'Formatting staged Python files . . .' +yapf -i -r ${PYTHON_FILES[@]} +CHANGED_FILES=(`git diff --name-only ${PYTHON_FILES[@]}`) +if [ "$CHANGED_FILES" ]; then + echo 'Some staged files were reformatted. Please review the changes and stage them.' + echo + echo 'Files updated:' + for file in ${CHANGED_FILES[@]}; do + echo " $file" + done + exit 1 +else + exit 0 +fi From c9341846faf8aae0d016fa1a48cbb3e36b9798b9 Mon Sep 17 00:00:00 2001 From: Jesse Kinkead Date: Fri, 28 Jul 2017 15:27:00 -0700 Subject: [PATCH 145/719] Fix formatting of vim code block. --- plugins/README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/README.rst b/plugins/README.rst index 6d458f762..7f24a9bfd 100644 --- a/plugins/README.rst +++ b/plugins/README.rst @@ -15,6 +15,7 @@ The ``vim`` plugin allows you to reformat a range of code. Place it into the ``.vim/autoload`` directory or use a plugin manager like Plug or Vundle: .. code-block:: vim + " Plug Plug 'google/yapf', { 'rtp': 'plugins/vim', 'for': 'python' } From 8d00324a3fe5727cca557da706b2d30a31ce2633 Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Tue, 1 Aug 2017 08:31:47 +0100 Subject: [PATCH 146/719] Add quiet flag and return value if quiet --- yapf/__init__.py | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index a89582f2c..549d522e5 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -72,6 +72,11 @@ def main(argv): '--in-place', action='store_true', help='make changes to files in place') + diff_inplace_group.add_argument( + '-q', + '--quiet', + action='store_true', + help='output nothing and set return value') lines_recursive_group = parser.add_mutually_exclusive_group() lines_recursive_group.add_argument( @@ -177,15 +182,20 @@ def main(argv): if not files: raise errors.YapfError('Input filenames did not match any python files') - FormatFiles( - files, - lines, - style_config=args.style, - no_local_style=args.no_local_style, - in_place=args.in_place, - print_diff=args.diff, - verify=args.verify, - parallel=args.parallel) + changed = FormatFiles( + files, + lines, + style_config=args.style, + no_local_style=args.no_local_style, + in_place=args.in_place, + print_diff=args.diff, + verify=args.verify, + parallel=args.parallel, + quiet=args.quiet) + + if args.quiet and changed: + return 1 + return 0 @@ -196,7 +206,8 @@ def FormatFiles(filenames, in_place=False, print_diff=False, verify=True, - parallel=False): + parallel=False, + quiet=False): """Format a list of files. Arguments: @@ -213,6 +224,7 @@ def FormatFiles(filenames, diff that turns the formatted source into reformatter source. verify: (bool) True if reformatted code should be verified for syntax. parallel: (bool) True if should format multiple files in parallel. + quiet: (bool) True if should output nothing. Returns: True if the source code changed in any of the files being formatted. @@ -225,7 +237,8 @@ def FormatFiles(filenames, with concurrent.futures.ProcessPoolExecutor(workers) as executor: future_formats = [ executor.submit(_FormatFile, filename, lines, style_config, - no_local_style, in_place, print_diff, verify) + no_local_style, in_place, print_diff, verify, + quiet) for filename in filenames ] for future in concurrent.futures.as_completed(future_formats): @@ -233,7 +246,7 @@ def FormatFiles(filenames, else: for filename in filenames: changed |= _FormatFile(filename, lines, style_config, no_local_style, - in_place, print_diff, verify) + in_place, print_diff, verify, quiet) return changed @@ -243,7 +256,8 @@ def _FormatFile(filename, no_local_style=False, in_place=False, print_diff=False, - verify=True): + verify=True, + quiet=False): logging.info('Reformatting %s', filename) if style_config is None and not no_local_style: style_config = ( @@ -257,7 +271,7 @@ def _FormatFile(filename, print_diff=print_diff, verify=verify, logger=logging.warning) - if not in_place and reformatted_code: + if not in_place and not quiet and reformatted_code: file_resources.WriteReformattedCode(filename, reformatted_code, in_place, encoding) return has_change From 6354704dd1e6ffd34f7970e78d5355fa315587fb Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 1 Aug 2017 13:38:54 -0700 Subject: [PATCH 147/719] Return 1 if --diff changed the code. This is how GNU diff acts. --- CHANGELOG | 1 + yapf/__init__.py | 4 ++-- yapf/yapflib/reformatter.py | 6 +++--- yapf/yapflib/unwrapped_line.py | 6 +++--- yapf/yapflib/yapf_api.py | 2 +- yapftests/yapf_test.py | 5 ++++- 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 3a3ba8fcf..37910d2d9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,7 @@ ## [0.16.4] Unreleased ### Changed - Adjust blank lines on formatting boundaries when using the `--lines` option. +- Return 1 if a diff changed the code. This is in line with how GNU diff acts. ## [0.16.3] 2017-07-13 ### Changed diff --git a/yapf/__init__.py b/yapf/__init__.py index a89582f2c..8d74b18af 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -177,7 +177,7 @@ def main(argv): if not files: raise errors.YapfError('Input filenames did not match any python files') - FormatFiles( + changed = FormatFiles( files, lines, style_config=args.style, @@ -186,7 +186,7 @@ def main(argv): print_diff=args.diff, verify=args.verify, parallel=args.parallel) - return 0 + return 1 if changed and args.diff else 0 def FormatFiles(filenames, diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 2f0cc43d7..990b9e4cb 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -68,8 +68,8 @@ def Reformat(uwlines, verify=False, lines=None): if prev_uwline and prev_uwline.disable: # Keep the vertical spacing between a disabled and enabled formatting # region. - _RetainRequiredVerticalSpacingBetweenTokens( - uwline.first, prev_uwline.last, lines) + _RetainRequiredVerticalSpacingBetweenTokens(uwline.first, + prev_uwline.last, lines) if any(tok.is_comment for tok in uwline.tokens): _RetainVerticalSpacingBeforeComments(uwline) @@ -134,7 +134,7 @@ def _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines): cur_lineno = cur_tok.lineno if prev_tok.value.endswith('\\'): - prev_lineno = prev_lineno + prev_tok.value.count('\n') + prev_lineno += prev_tok.value.count('\n') required_newlines = cur_lineno - prev_lineno diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index e68f48e8c..75898c84d 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -331,9 +331,9 @@ def _SpaceRequiredBetween(left, right): def _MustBreakBefore(prev_token, cur_token): """Return True if a line break is required before the current token.""" - if prev_token.is_comment or ( - prev_token.previous_token and prev_token.is_pseudo_paren and - prev_token.previous_token.is_comment): + if prev_token.is_comment or (prev_token.previous_token and + prev_token.is_pseudo_paren and + prev_token.previous_token.is_comment): # Must break if the previous token was a comment. return True if (cur_token.is_string and prev_token.is_string and diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index cb10e8bff..e96d057ea 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -152,7 +152,7 @@ def FormatCode(unformatted_source, unformatted_source, reformatted_source, filename=filename) if print_diff: - return code_diff, code_diff != '' + return code_diff, code_diff return reformatted_source, True diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 0ec093a58..92b9b4da0 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -492,7 +492,10 @@ def f(): suffix='.py', dirname=self.test_tmpdir) as (out, _): with utils.TempFileContents( self.test_tmpdir, unformatted_code, suffix='.py') as filepath: - subprocess.check_call(YAPF_BINARY + ['--diff', filepath], stdout=out) + try: + subprocess.check_call(YAPF_BINARY + ['--diff', filepath], stdout=out) + except subprocess.CalledProcessError as e: + self.assertEqual(e.returncode, 1) # Indicates the text changed. def testReformattingSpecificLines(self): unformatted_code = textwrap.dedent("""\ From b094414d918ebc574ffee943828af34ff019782b Mon Sep 17 00:00:00 2001 From: Bouwe Andela Date: Thu, 3 Aug 2017 21:59:13 +0200 Subject: [PATCH 148/719] Fix #204 and fix #339 Improve the handling of subsequent comments at decreasing levels of indentation. --- yapf/yapflib/comment_splicer.py | 99 +++++++++++++++------------------ 1 file changed, 44 insertions(+), 55 deletions(-) diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index 7c79e805d..dd60f860b 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -71,8 +71,7 @@ def _VisitNodeRec(node): # We can't just insert it before the NEWLINE node, because as a # result of the way pytrees are organized, this node can be under # an inappropriate parent. - comment_column -= len(comment_prefix) - comment_column += len(comment_prefix) - len(comment_prefix.lstrip()) + comment_column -= len(comment_prefix.lstrip()) pytree_utils.InsertNodesAfter( _CreateCommentsFromPrefix( comment_prefix, @@ -83,63 +82,53 @@ def _VisitNodeRec(node): # Comment prefixes on DEDENT nodes also deserve special treatment, # because their final placement depends on their prefix. # We'll look for an ancestor of this child with a matching - # indentation, and insert the comment after it. - ancestor_at_indent = _FindAncestorAtIndent(child, prefix_indent) - if ancestor_at_indent.type == token.DEDENT: - comments = comment_prefix.split('\n') - - # lib2to3 places comments that should be separated into the same - # DEDENT node. For example, "comment 1" and "comment 2" will be - # combined. - # - # def _(): - # for x in y: - # pass - # # comment 1 - # - # # comment 2 - # pass - # - # In this case, we need to split them up ourselves. - before = [] - after = [] - after_lineno = comment_lineno - - index = 0 - while index < len(comments): - cmt = comments[index] - if not cmt.strip() or cmt.startswith(prefix_indent + '#'): - before.append(cmt) - else: - after_lineno += index - after.extend(comments[index:]) - break - index += 1 - - # Special case where the comment is inserted in the same - # indentation level as the DEDENT it was originally attached to. - pytree_utils.InsertNodesBefore( - _CreateCommentsFromPrefix( - '\n'.join(before) + '\n', - comment_lineno, - comment_column, - standalone=True), ancestor_at_indent) - if after: - after_column = len(after[0]) - len(after[0].lstrip()) - comment_column -= comment_column - after_column - pytree_utils.InsertNodesAfter( - _CreateCommentsFromPrefix( - '\n'.join(after) + '\n', - after_lineno, - comment_column, - standalone=True), _FindNextAncestor(ancestor_at_indent)) - else: - pytree_utils.InsertNodesAfter( + # indentation, and insert the comment before it if the ancestor is + # on a DEDENT node and after it otherwise. + # + # lib2to3 places comments that should be separated into the same + # DEDENT node. For example, "comment 1" and "comment 2" will be + # combined. + # + # def _(): + # for x in y: + # pass + # # comment 1 + # + # # comment 2 + # pass + # + # In this case, we need to split them up ourselves. + + # Split into groups of comments at decreasing levels of indentation + comment_groups = [] + comment_column = None + for cmt in comment_prefix.split('\n'): + col = cmt.find('#') + if col < 0: + if comment_column is None: + # Skip empty lines at the top of the first comment group + comment_lineno += 1 + continue + elif comment_column is None or col < comment_column: + comment_column = col + comment_indent = cmt[:comment_column] + comment_groups.append((comment_column, comment_indent, [])) + comment_groups[-1][-1].append(cmt) + + # Insert a node for each group + for comment_column, comment_indent, comment_group in comment_groups: + ancestor_at_indent = _FindAncestorAtIndent(child, comment_indent) + if ancestor_at_indent.type == token.DEDENT: + InsertNodes = pytree_utils.InsertNodesBefore + else: + InsertNodes = pytree_utils.InsertNodesAfter + InsertNodes( _CreateCommentsFromPrefix( - comment_prefix, + '\n'.join(comment_group) + '\n', comment_lineno, comment_column, standalone=True), ancestor_at_indent) + comment_lineno += len(comment_group) else: # Otherwise there are two cases. # From 2fd4ee292a7ad9860792661d4adf231f804da88e Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Fri, 4 Aug 2017 15:08:40 +0100 Subject: [PATCH 149/719] Make COALESCE_BRACKETS and DEDENT_CLOSING_BRACKETS work together * Update tests to to reflect the COALESCE_BRACKETS behaviour. * Always add newline before the closing (coalesced) brackets. Fixes: #436 --- CHANGELOG | 2 ++ yapf/yapflib/format_decision_state.py | 6 +----- yapftests/reformatter_basic_test.py | 23 +++++++++++++---------- yapftests/yapf_test.py | 14 ++++++++------ 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 37910d2d9..7b24eb22c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,8 @@ ### Changed - Adjust blank lines on formatting boundaries when using the `--lines` option. - Return 1 if a diff changed the code. This is in line with how GNU diff acts. +### Fixed +- Corrected how `DEDENT_CLOSING_BRACKETS` and `COALESCE_BRACKETS` interacted. ## [0.16.3] 2017-07-13 ### Changed diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 3c17dc4a2..b7b599705 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -502,11 +502,7 @@ def _AddTokenOnNewline(self, dry_run, must_split): self.stack[-1].closing_scope_indent = max( 0, self.stack[-1].indent - style.Get('CONTINUATION_INDENT_WIDTH')) - split_before_closing_bracket = True - if style.Get('COALESCE_BRACKETS'): - split_before_closing_bracket = False - - self.stack[-1].split_before_closing_bracket = split_before_closing_bracket + self.stack[-1].split_before_closing_bracket = True # Calculate the split penalty. penalty = current.split_penalty diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 1361219ef..0ce8da8fc 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2266,23 +2266,26 @@ def testCoalesceBracketsOnDict(self): style.CreateStyleFromConfig( '{based_on_style: chromium, coalesce_brackets: True}')) unformatted_code = textwrap.dedent("""\ - date_time_values = { - u'year': year, - u'month': month, - u'day_of_month': day_of_month, - u'hours': hours, - u'minutes': minutes, - u'seconds': seconds - } + date_time_values = ( + { + u'year': year, + u'month': month, + u'day_of_month': day_of_month, + u'hours': hours, + u'minutes': minutes, + u'seconds': seconds + } + ) """) expected_formatted_code = textwrap.dedent("""\ - date_time_values = { + date_time_values = ({ u'year': year, u'month': month, u'day_of_month': day_of_month, u'hours': hours, u'minutes': minutes, - u'seconds': seconds} + u'seconds': seconds + }) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 92b9b4da0..7fe7e90cf 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1017,20 +1017,22 @@ def overly_long_function_name( def testCoalesceBrackets(self): unformatted_code = textwrap.dedent("""\ - some_long_function_name_foo({ - 'first_argument_of_the_thing': id, - 'second_argument_of_the_thing': "some thing"} - )""") + some_long_function_name_foo( + { + 'first_argument_of_the_thing': id, + 'second_argument_of_the_thing': "some thing" + } + )""") expected_formatted_code = textwrap.dedent("""\ some_long_function_name_foo({ 'first_argument_of_the_thing': id, - 'second_argument_of_the_thing': "some thing"}) + 'second_argument_of_the_thing': "some thing" + }) """) with utils.NamedTempFile(dirname=self.test_tmpdir, mode='w') as (f, name): f.write( textwrap.dedent(u'''\ [style] - based_on_style = facebook column_limit=82 coalesce_brackets = True ''')) From 41bae77ac7ddd85b279040754d1eec9ef874dd09 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 12 Aug 2017 15:21:12 -0700 Subject: [PATCH 150/719] Return a boolean instead of string. --- CHANGELOG | 1 + yapf/yapflib/yapf_api.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 7b24eb22c..62ca8a471 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,7 @@ - Return 1 if a diff changed the code. This is in line with how GNU diff acts. ### Fixed - Corrected how `DEDENT_CLOSING_BRACKETS` and `COALESCE_BRACKETS` interacted. +- Fix return value to return a boolean. ## [0.16.3] 2017-07-13 ### Changed diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index e96d057ea..47e790ebe 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -152,7 +152,7 @@ def FormatCode(unformatted_source, unformatted_source, reformatted_source, filename=filename) if print_diff: - return code_diff, code_diff + return code_diff, code_diff.strip() != '' return reformatted_source, True From 7aa52072f2d1a64881aa8e0d9f25ae4020246ff2 Mon Sep 17 00:00:00 2001 From: Anton Yuzhaninov Date: Wed, 19 Jul 2017 22:43:51 -0400 Subject: [PATCH 151/719] Vim plugin: use systemlist (if available) We need yapf output as list, so use the systemlist() vim function, which was added in vim 7.4.248. --- plugins/vim/autoload/yapf.vim | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/vim/autoload/yapf.vim b/plugins/vim/autoload/yapf.vim index 82f999176..1ade68565 100644 --- a/plugins/vim/autoload/yapf.vim +++ b/plugins/vim/autoload/yapf.vim @@ -33,11 +33,16 @@ function! yapf#YAPF() range let l:cmd = 'yapf --lines=' . l:line_ranges " Call YAPF with the current buffer - let l:formatted_text = system(l:cmd, join(getline(1, '$'), "\n") . "\n") + if exists('*systemlist') + let l:formatted_text = systemlist(l:cmd, join(getline(1, '$'), "\n") . "\n") + else + let l:formatted_text = + \ split(system(l:cmd, join(getline(1, '$'), "\n") . "\n"), "\n") + endif " Update the buffer. execute '1,' . string(line('$')) . 'delete' - call setline(1, split(l:formatted_text, "\n")) + call setline(1, l:formatted_text) " Reset cursor to first line of the formatted range. call cursor(a:firstline, 1) From 6164aff5398156b048a16914e3d5eb67d8f11347 Mon Sep 17 00:00:00 2001 From: Anton Yuzhaninov Date: Wed, 19 Jul 2017 22:45:45 -0400 Subject: [PATCH 152/719] Vim plugin: don't clobber text if yapf command returned error Check yapf command exit code. If there was an error, show error message with the last line of output and don't change text in a buffer. --- CHANGELOG | 1 + plugins/vim/autoload/yapf.vim | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 62ca8a471..cf46f2908 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,7 @@ ### Fixed - Corrected how `DEDENT_CLOSING_BRACKETS` and `COALESCE_BRACKETS` interacted. - Fix return value to return a boolean. +- Correct vim plugin not to clobber edited code if yapf returns an error. ## [0.16.3] 2017-07-13 ### Changed diff --git a/plugins/vim/autoload/yapf.vim b/plugins/vim/autoload/yapf.vim index 1ade68565..b5e94dc41 100644 --- a/plugins/vim/autoload/yapf.vim +++ b/plugins/vim/autoload/yapf.vim @@ -40,6 +40,13 @@ function! yapf#YAPF() range \ split(system(l:cmd, join(getline(1, '$'), "\n") . "\n"), "\n") endif + if v:shell_error + echohl ErrorMsg + echomsg printf('"%s" returned error: %s', l:cmd, l:formatted_text[-1]) + echohl None + return + endif + " Update the buffer. execute '1,' . string(line('$')) . 'delete' call setline(1, l:formatted_text) From ad80a3b8b574e4f80eb3dd51a749f6d42288db31 Mon Sep 17 00:00:00 2001 From: Jiri Kuncar Date: Fri, 21 Jul 2017 09:45:31 +0200 Subject: [PATCH 153/719] Configurable spaces around binary operators --- CHANGELOG | 5 ++++- README.rst | 13 +++++++++++++ yapf/yapflib/style.py | 17 +++++++++++++++++ yapf/yapflib/unwrapped_line.py | 5 +++-- yapftests/reformatter_style_config_test.py | 20 ++++++++++++++++++++ 5 files changed, 57 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index cf46f2908..d7a465c7b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.16.4] Unreleased +## [0.17.0] Unreleased +### Added +- Option `NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS` prevents adding spaces + around selected binary operators, in accordance with the current style guide. ### Changed - Adjust blank lines on formatting boundaries when using the `--lines` option. - Return 1 if a diff changed the code. This is in line with how GNU diff acts. diff --git a/README.rst b/README.rst index a05a072d8..3ccf98996 100644 --- a/README.rst +++ b/README.rst @@ -399,6 +399,19 @@ Knobs ``SPACES_AROUND_POWER_OPERATOR`` Set to ``True`` to prefer using spaces around ``**``. +``NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS`` + Do not include spaces around selected binary operators. For example: + + .. code-block:: python + + 1 + 2 * 3 - 4 / 5 + + will be formatted as follows when configured with a value ``"*,/"``: + + .. code-block:: python + + 1 + 2*3 - 4/5 + ``SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN`` Set to ``True`` to prefer spaces around the assignment operator for default or keyword arguments. diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 762b05a42..e8840e408 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -136,6 +136,16 @@ def method(): etc."""), SPACES_AROUND_POWER_OPERATOR=textwrap.dedent("""\ Use spaces around the power operator."""), + NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=textwrap.dedent("""\ + Do not include spaces around selected binary operators. For example: + + 1 + 2 * 3 - 4 / 5 + + will be formatted as follows when configured with a value "*,/": + + 1 + 2*3 - 4/5 + + """), SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=textwrap.dedent("""\ Use spaces around default or named assigns."""), SPACES_BEFORE_COMMENT=textwrap.dedent("""\ @@ -216,6 +226,7 @@ def CreatePEP8Style(): JOIN_MULTIPLE_LINES=True, SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=True, SPACES_AROUND_POWER_OPERATOR=False, + NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=set(), SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=False, SPACES_BEFORE_COMMENT=2, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False, @@ -300,6 +311,11 @@ def _StringListConverter(s): return [part.strip() for part in s.split(',')] +def _StringSetConverter(s): + """Option value converter for a comma-separated set of strings.""" + return set(part.strip() for part in s.split(',')) + + def _BoolConverter(s): """Option value converter for a boolean.""" return py3compat.CONFIGPARSER_BOOLEAN_STATES[s.lower()] @@ -329,6 +345,7 @@ def _BoolConverter(s): INDENT_WIDTH=int, JOIN_MULTIPLE_LINES=_BoolConverter, SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=_BoolConverter, + NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=_StringSetConverter, SPACES_AROUND_POWER_OPERATOR=_BoolConverter, SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=_BoolConverter, SPACES_BEFORE_COMMENT=int, diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 75898c84d..3124cd5b7 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -253,8 +253,9 @@ def _SpaceRequiredBetween(left, right): if lval == '**' or rval == '**': # Space around the "power" operator. return style.Get('SPACES_AROUND_POWER_OPERATOR') - # Enforce spaces around binary operators. - return True + # Enforce spaces around binary operators except the blacklisted ones. + blacklist = style.Get('NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS') + return lval not in blacklist and rval not in blacklist if (_IsUnaryOperator(left) and lval != 'not' and (right.is_name or right.is_number or rval == '(')): # The previous token was a unary op. No space is desired between it and diff --git a/yapftests/reformatter_style_config_test.py b/yapftests/reformatter_style_config_test.py index 5a04930d3..dae8e465e 100644 --- a/yapftests/reformatter_style_config_test.py +++ b/yapftests/reformatter_style_config_test.py @@ -57,5 +57,25 @@ def testSetGlobalStyle(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testOperatorStyle(self): + try: + sympy_style = style.CreatePEP8Style() + sympy_style['NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS'] = \ + style._StringSetConverter('*,/') + style.SetGlobalStyle(sympy_style) + unformatted_code = textwrap.dedent("""\ + a = 1+2 * 3 - 4 / 5 + """) + expected_formatted_code = textwrap.dedent("""\ + a = 1 + 2*3 - 4/5 + """) + + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreatePEP8Style()) + style.DEFAULT_STYLE = self.current_style + + if __name__ == '__main__': unittest.main() From 429dba3733b3881d67fcbb682a50aef65a5604dd Mon Sep 17 00:00:00 2001 From: Arturo Fernandez Date: Thu, 3 Aug 2017 15:19:45 -0700 Subject: [PATCH 154/719] Adding plugin for Textmate2 editor --- plugins/README.rst | 42 ++++++++++++++++++++++ yapftests/reformatter_style_config_test.py | 4 +-- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/plugins/README.rst b/plugins/README.rst index 7f24a9bfd..b6a3e0cd8 100644 --- a/plugins/README.rst +++ b/plugins/README.rst @@ -39,3 +39,45 @@ It is compatible with both Sublime Text 2 and 3. The plugin can be easily installed by using *Sublime Package Control*. Check the project page of the plugin for more information: https://github.com/jason-kane/PyYapf + + +Textmate 2 +========== + +Plugin for ``Textmate 2`` requires ``yapf`` Python package installed on your system: + +.. code-block:: shell + + pip install yapf + +Also, you will need to activate ``Python`` bundle from ``Preferences >> Bundles``. + +Finally, create a ``~/Library/Application Support/TextMate/Bundles/Python.tmbundle/Commands/YAPF.tmCommand`` +file with the following content: + +.. code-block:: xml + + + + + + beforeRunningCommand + saveActiveFile + command + #!/bin/bash + + TPY=${TM_PYTHON:-python} + + "$TPY" "/usr/local/bin/yapf" "$TM_FILEPATH" + input + document + name + YAPF + scope + source.python + uuid + 297D5A82-2616-4950-9905-BD2D1C94D2D4 + + + +You will see a new menu item ``Bundles > Python > YAPF``. diff --git a/yapftests/reformatter_style_config_test.py b/yapftests/reformatter_style_config_test.py index dae8e465e..8cf3fb055 100644 --- a/yapftests/reformatter_style_config_test.py +++ b/yapftests/reformatter_style_config_test.py @@ -56,7 +56,6 @@ def testSetGlobalStyle(self): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - def testOperatorStyle(self): try: sympy_style = style.CreatePEP8Style() @@ -71,7 +70,8 @@ def testOperatorStyle(self): """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) style.DEFAULT_STYLE = self.current_style From e6a46814327ce33292a2c4ae28cbfee514c50574 Mon Sep 17 00:00:00 2001 From: Justin Huang Date: Sun, 6 Aug 2017 19:44:38 -0700 Subject: [PATCH 155/719] Attempt to fix #359 --- yapf/yapflib/pytree_unwrapper.py | 8 ++++++-- yapftests/reformatter_basic_test.py | 9 ++++++++- yapftests/reformatter_facebook_test.py | 25 ++++++++++++++++++++++--- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index c67c1c6ea..dcf902576 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -258,8 +258,7 @@ def Visit_import_as_names(self, node): # pylint: disable=invalid-name self.DefaultNodeVisit(node) def Visit_testlist_gexp(self, node): # pylint: disable=invalid-name - if _ContainsComments(node): - _DetermineMustSplitAnnotation(node) + _DetermineMustSplitAnnotation(node) self.DefaultNodeVisit(node) def Visit_arglist(self, node): # pylint: disable=invalid-name @@ -336,6 +335,11 @@ def _AdjustSplitPenalty(uwline): def _DetermineMustSplitAnnotation(node): """Enforce a split in the list if the list ends with a comma.""" if not _ContainsComments(node): + token = node.parent.leaves().next() + if token.value == '(': + if sum(1 for ch in node.children + if pytree_utils.NodeName(ch) == 'COMMA') < 2: + return if (not isinstance(node.children[-1], pytree.Leaf) or node.children[-1].value != ','): return diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 0ce8da8fc..c205f4790 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -459,10 +459,17 @@ def given(y): def testOpeningAndClosingBrackets(self): unformatted_code = textwrap.dedent("""\ + foo( (1, ) ) + foo( ( 1, 2, 3 ) ) foo( ( 1, 2, 3, ) ) """) expected_formatted_code = textwrap.dedent("""\ - foo((1, 2, 3,)) + foo((1,)) + foo((1, 2, 3)) + foo(( + 1, + 2, + 3,)) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_facebook_test.py b/yapftests/reformatter_facebook_test.py index 470678646..953d290aa 100644 --- a/yapftests/reformatter_facebook_test.py +++ b/yapftests/reformatter_facebook_test.py @@ -107,7 +107,7 @@ def testDedentImportAsNames(self): self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testDedentTestListGexp(self): - code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ try: pass except ( @@ -122,8 +122,27 @@ def testDedentTestListGexp(self): ) as exception: pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + expected_formatted_code = textwrap.dedent("""\ + try: + pass + except ( + IOError, OSError, LookupError, RuntimeError, OverflowError + ) as exception: + pass + + try: + pass + except ( + IOError, + OSError, + LookupError, + RuntimeError, + OverflowError, + ) as exception: + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testBrokenIdempotency(self): # TODO(ambv): The following behaviour should be fixed. From 65425a4f94caabd3c614ce613c82eae76aa0e6c0 Mon Sep 17 00:00:00 2001 From: Justin Huang Date: Sun, 6 Aug 2017 20:02:03 -0700 Subject: [PATCH 156/719] Use py3-compatible next() --- yapf/yapflib/pytree_unwrapper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index dcf902576..8dbbfe06c 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -335,7 +335,7 @@ def _AdjustSplitPenalty(uwline): def _DetermineMustSplitAnnotation(node): """Enforce a split in the list if the list ends with a comma.""" if not _ContainsComments(node): - token = node.parent.leaves().next() + token = next(node.parent.leaves()) if token.value == '(': if sum(1 for ch in node.children if pytree_utils.NodeName(ch) == 'COMMA') < 2: From b6c5308a76085bfb8b7654c9f32065eec5c98a23 Mon Sep 17 00:00:00 2001 From: Justin Huang Date: Sat, 12 Aug 2017 17:36:41 -0700 Subject: [PATCH 157/719] Modify changelog --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index d7a465c7b..b05a6f405 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,7 @@ - Corrected how `DEDENT_CLOSING_BRACKETS` and `COALESCE_BRACKETS` interacted. - Fix return value to return a boolean. - Correct vim plugin not to clobber edited code if yapf returns an error. +- Ensured comma-terminated tuples with multiple elements are split onto separate lines. ## [0.16.3] 2017-07-13 ### Changed From 918f2523b7bcac0d8420918b11e2609577783bc0 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 20 Aug 2017 22:03:12 -0700 Subject: [PATCH 158/719] Bump version to 0.17.0 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b05a6f405..cfcb0a795 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.17.0] Unreleased +## [0.17.0] 2017-08-20 ### Added - Option `NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS` prevents adding spaces around selected binary operators, in accordance with the current style guide. diff --git a/yapf/__init__.py b/yapf/__init__.py index 8d74b18af..91a50e3b1 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.16.3' +__version__ = '0.17.0' def main(argv): From 98f0a7cf5d2d4e936b01e3177697283a36fd4b79 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 21 Aug 2017 01:23:18 -0700 Subject: [PATCH 159/719] Allow semicolons if the line is disabled. Closes #447 --- CHANGELOG | 4 ++++ yapf/yapflib/pytree_unwrapper.py | 8 ++----- yapf/yapflib/unwrapped_line.py | 29 +++++++++++++++++++++++ yapf/yapflib/yapf_api.py | 10 +++++++- yapftests/reformatter_pep8_test.py | 18 --------------- yapftests/yapf_test.py | 37 ++++++++++++++++++++++++++++++ 6 files changed, 81 insertions(+), 25 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index cfcb0a795..270d30c5d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.17.1] UNRELEASED +### Fixed +- Allow semicolons if the line is disabled. + ## [0.17.0] 2017-08-20 ### Added - Option `NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS` prevents adding spaces diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index 8dbbfe06c..67be85ba1 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -280,12 +280,8 @@ def DefaultLeafVisit(self, leaf): if leaf.type in _WHITESPACE_TOKENS: self._StartNewLine() elif leaf.type != grammar_token.COMMENT or leaf.value.strip(): - if leaf.value == ';': - # Split up multiple statements on one line. - self._StartNewLine() - else: - # Add non-whitespace tokens and comments that aren't empty. - self._cur_unwrapped_line.AppendNode(leaf) + # Add non-whitespace tokens and comments that aren't empty. + self._cur_unwrapped_line.AppendNode(leaf) _BRACKET_MATCH = {')': '(', '}': '{', ']': '['} diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 3124cd5b7..242d31cf0 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -85,6 +85,31 @@ def CalculateFormattingInformation(self): prev_length = token.total_length prev_token = token + def Split(self): + """Split the line at semicolons.""" + if not self.has_semicolon or self.disable: + return [self] + + uwlines = [] + uwline = UnwrappedLine(self.depth) + for tok in self._tokens: + if tok.value == ';': + uwlines.append(uwline) + uwline = UnwrappedLine(self.depth) + else: + uwline.AppendToken(tok) + + if len(uwline.tokens): + uwlines.append(uwline) + + for uwline in uwlines: + pytree_utils.SetNodeAnnotation(uwline.first.node, + pytree_utils.Annotation.MUST_SPLIT, True) + uwline.first.previous_token = None + uwline.last.next_token = None + + return uwlines + ############################################################################ # Token Access and Manipulation Methods # ############################################################################ @@ -176,6 +201,10 @@ def lineno(self): def is_comment(self): return self.first.is_comment + @property + def has_semicolon(self): + return any(tok.value == ';' for tok in self._tokens) + def _IsIdNumberStringToken(tok): return tok.is_keyword or tok.is_name or tok.is_number or tok.is_string diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 47e790ebe..1d50719cb 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -143,7 +143,8 @@ def FormatCode(unformatted_source, lines = _LineRangesToSet(lines) _MarkLinesToFormat(uwlines, lines) - reformatted_source = reformatter.Reformat(uwlines, verify, lines) + reformatted_source = reformatter.Reformat( + _SplitSemicolons(uwlines), verify, lines) if unformatted_source == reformatted_source: return '' if print_diff else reformatted_source, False @@ -207,6 +208,13 @@ def ReadFile(filename, logger=None): raise +def _SplitSemicolons(uwlines): + res = [] + for uwline in uwlines: + res.extend(uwline.Split()) + return res + + DISABLE_PATTERN = r'^#.*\byapf:\s*disable\b' ENABLE_PATTERN = r'^#.*\byapf:\s*enable\b' diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 431ff9952..14cb2aecd 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -76,24 +76,6 @@ def testSingleWhiteBeforeTrailingComment(self): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - def testSplittingSemicolonStatements(self): - unformatted_code = textwrap.dedent("""\ - def f(): - x = y + 42 ; z = n * 42 - if True: a += 1 ; b += 1; c += 1 - """) - expected_formatted_code = textwrap.dedent("""\ - def f(): - x = y + 42 - z = n * 42 - if True: - a += 1 - b += 1 - c += 1 - """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - def testSpaceBetweenEndingCommandAndClosingBracket(self): unformatted_code = textwrap.dedent("""\ a = ( diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 7fe7e90cf..b0b3c85f3 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -278,6 +278,43 @@ def testDisabledHorizontalFormattingOnNewLine(self): formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(code, formatted_code) + def testSplittingSemicolonStatements(self): + unformatted_code = textwrap.dedent(u"""\ + def f(): + x = y + 42 ; z = n * 42 + if True: a += 1 ; b += 1; c += 1 + """) + expected_formatted_code = textwrap.dedent(u"""\ + def f(): + x = y + 42 + z = n * 42 + if True: + a += 1 + b += 1 + c += 1 + """) + with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: + formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') + self.assertCodeEqual(expected_formatted_code, formatted_code) + + def testSemicolonStatementsDisabled(self): + unformatted_code = textwrap.dedent(u"""\ + def f(): + x = y + 42 ; z = n * 42 # yapf: disable + if True: a += 1 ; b += 1; c += 1 + """) + expected_formatted_code = textwrap.dedent(u"""\ + def f(): + x = y + 42 ; z = n * 42 # yapf: disable + if True: + a += 1 + b += 1 + c += 1 + """) + with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: + formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') + self.assertCodeEqual(expected_formatted_code, formatted_code) + def testDisabledSemiColonSeparatedStatements(self): code = textwrap.dedent(u"""\ # yapf: disable From 13600d234ce5c74377f6f17b46886540cc9adf6f Mon Sep 17 00:00:00 2001 From: Bouwe Andela Date: Mon, 21 Aug 2017 21:04:16 +0200 Subject: [PATCH 160/719] Add test for issue #204 --- yapftests/comment_splicer_test.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/yapftests/comment_splicer_test.py b/yapftests/comment_splicer_test.py index ee0527e24..5abe4508f 100644 --- a/yapftests/comment_splicer_test.py +++ b/yapftests/comment_splicer_test.py @@ -206,6 +206,33 @@ def testCommentBeforeDedentTwoLevelImproperlyIndented(self): self._AssertNodeIsComment(if_suite.children[-2]) self._AssertNodeType('DEDENT', if_suite.children[-1]) + def testCommentBeforeDedentThreeLevel(self): + code = textwrap.dedent(r''' + if foo: + if bar: + z = 1 + # comment 2 + # comment 1 + # comment 0 + j = 2 + ''') + tree = pytree_utils.ParseCodeToTree(code) + comment_splicer.SpliceComments(tree) + + # comment 0 should go under the tree root + self._AssertNodeIsComment(tree.children[1], '# comment 0') + + # comment 1 is in the first if_suite, right before the DEDENT + if_suite_1 = self._FindNthChildNamed(tree, 'suite', n=1) + self._AssertNodeIsComment(if_suite_1.children[-2], '# comment 1') + self._AssertNodeType('DEDENT', if_suite_1.children[-1]) + + # comment 2 is in if_suite nested under the first if suite, + # right before the DEDENT + if_suite_2 = self._FindNthChildNamed(tree, 'suite', n=2) + self._AssertNodeIsComment(if_suite_2.children[-2], '# comment 2') + self._AssertNodeType('DEDENT', if_suite_2.children[-1]) + def testCommentsInClass(self): code = textwrap.dedent(r''' class Foo: From fbcc3142548faebeb3d4f6a93ca4a9eb45e8b9eb Mon Sep 17 00:00:00 2001 From: Bouwe Andela Date: Mon, 21 Aug 2017 21:05:01 +0200 Subject: [PATCH 161/719] Add test for issue #339 --- yapftests/reformatter_buganizer_test.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 2d0cf9fb0..996a0a3f4 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -501,6 +501,18 @@ def _(): uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB30087363(self): + code = textwrap.dedent("""\ + if False: + bar() + # This is a comment + # This is another comment + elif True: + foo() + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB29093579(self): unformatted_code = textwrap.dedent("""\ def _(): From dabe03949619d6f993a1c8998d170e22847bd812 Mon Sep 17 00:00:00 2001 From: Bouwe Andela Date: Mon, 21 Aug 2017 21:06:05 +0200 Subject: [PATCH 162/719] Add note for fix of issue #204 and issue #339 --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index d7a465c7b..99c7bffbb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,8 @@ - Corrected how `DEDENT_CLOSING_BRACKETS` and `COALESCE_BRACKETS` interacted. - Fix return value to return a boolean. - Correct vim plugin not to clobber edited code if yapf returns an error. +- Fix issue where subsequent comments at decreasing levels of indentation + were improperly aligned and/or caused output with invalid syntax. ## [0.16.3] 2017-07-13 ### Changed From 6afa76b31ae0b098da5cb0217831af229f16992b Mon Sep 17 00:00:00 2001 From: Bouwe Andela Date: Mon, 21 Aug 2017 21:33:23 +0200 Subject: [PATCH 163/719] Moved note to correct release --- CHANGELOG | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 13e0d1882..e90c25b25 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,8 @@ ## [0.17.1] UNRELEASED ### Fixed - Allow semicolons if the line is disabled. +- Fix issue where subsequent comments at decreasing levels of indentation + were improperly aligned and/or caused output with invalid syntax. ## [0.17.0] 2017-08-20 ### Added @@ -18,8 +20,6 @@ - Fix return value to return a boolean. - Correct vim plugin not to clobber edited code if yapf returns an error. - Ensured comma-terminated tuples with multiple elements are split onto separate lines. -- Fix issue where subsequent comments at decreasing levels of indentation - were improperly aligned and/or caused output with invalid syntax. ## [0.16.3] 2017-07-13 ### Changed From d52955e88bf17e513159e6b73fbe52713a95a27b Mon Sep 17 00:00:00 2001 From: Bouwe Andela Date: Mon, 21 Aug 2017 23:34:03 +0200 Subject: [PATCH 164/719] Removed unused and untested function _FindNextAncestor to improve test coverage --- yapf/yapflib/comment_splicer.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index dd60f860b..32997b7c4 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -326,16 +326,6 @@ def _FindAncestorAtIndent(node, indent): return _FindAncestorAtIndent(node.parent, indent) -def _FindNextAncestor(node): - if node.parent is None: - return node - - if node.parent.next_sibling is not None: - return node.parent.next_sibling - - return _FindNextAncestor(node.parent) - - def _AnnotateIndents(tree): """Annotate the tree with child_indent annotations. From c8a0d4fe5b83bf8af8b625ba4f7198961d155df7 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 23 Aug 2017 02:32:11 -0700 Subject: [PATCH 165/719] Don't remove newline before comment after a line range. --- CHANGELOG | 2 ++ yapf/yapflib/reformatter.py | 6 ++++-- yapftests/yapf_test.py | 26 ++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e90c25b25..8063310fc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,8 @@ - Allow semicolons if the line is disabled. - Fix issue where subsequent comments at decreasing levels of indentation were improperly aligned and/or caused output with invalid syntax. +- Fix issue where specifying a line range removed a needed line before a + comment. ## [0.17.0] 2017-08-20 ### Added diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 990b9e4cb..8d2b4dcde 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -137,8 +137,10 @@ def _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines): prev_lineno += prev_tok.value.count('\n') required_newlines = cur_lineno - prev_lineno - - if lines and (cur_lineno in lines or prev_lineno in lines): + if cur_tok.is_comment and not prev_tok.is_comment: + # Don't adjust between a comment and non-comment. + pass + elif lines and (cur_lineno in lines or prev_lineno in lines): desired_newlines = cur_tok.whitespace_prefix.count('\n') whitespace_lines = range(prev_lineno + 1, cur_lineno) deletable_lines = len(lines.intersection(whitespace_lines)) diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index b0b3c85f3..e1032b29b 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1197,6 +1197,32 @@ def foo_function(): expected_formatted_code, extra_options=['--style={0}'.format(stylepath)]) + def testSpacingBeforeComments(self): + unformatted_code = textwrap.dedent("""\ + A = 42 + + + # A comment + def x(): + pass + def _(): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + A = 42 + + + # A comment + def x(): + pass + def _(): + pass + """) + self.assertYapfReformats( + unformatted_code, + expected_formatted_code, + extra_options=['--lines', '1-2']) + class BadInputTest(unittest.TestCase): """Test yapf's behaviour when passed bad input.""" From 4dea3c3114cbcd5d5969a33ffda3ecacd6838325 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 23 Aug 2017 17:16:31 -0700 Subject: [PATCH 166/719] Cleanup some of the APIs. --- yapf/__init__.py | 4 ++-- yapf/yapflib/file_resources.py | 15 ++++++++++++--- yapf/yapflib/yapf_api.py | 11 ++--------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 91a50e3b1..bb279ad4f 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -258,8 +258,8 @@ def _FormatFile(filename, verify=verify, logger=logging.warning) if not in_place and reformatted_code: - file_resources.WriteReformattedCode(filename, reformatted_code, in_place, - encoding) + file_resources.WriteReformattedCode(filename, reformatted_code, encoding, + in_place) return has_change except SyntaxError as e: e.filename = filename diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index e7f9acdc7..b1305c8e5 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -78,8 +78,8 @@ def GetCommandLineFiles(command_line_file_list, recursive, exclude): def WriteReformattedCode(filename, reformatted_code, - in_place=False, - encoding=''): + encoding='', + in_place=False): """Emit the reformatted code. Write the reformatted code into the file, if in_place is True. Otherwise, @@ -88,8 +88,8 @@ def WriteReformattedCode(filename, Arguments: filename: (unicode) The name of the unformatted file. reformatted_code: (unicode) The reformatted code. - in_place: (bool) If True, then write the reformatted code to the file. encoding: (unicode) The encoding of the file. + in_place: (bool) If True, then write the reformatted code to the file. """ if in_place: with py3compat.open_with_encoding( @@ -167,3 +167,12 @@ def IsPythonFile(filename): return False return re.match(r'^#!.*\bpython[23]?\b', first_line) + + +def FileEncoding(filename): + """Return the file's encoding.""" + try: + with open(filename, 'rb') as fd: + return tokenize.detect_encoding(fd.readline)[0] + except IOError: + raise diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 1d50719cb..bdd1ad638 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -37,7 +37,6 @@ import sys from lib2to3.pgen2 import parse -from lib2to3.pgen2 import tokenize from yapf.yapflib import blank_line_calculator from yapf.yapflib import comment_splicer @@ -95,7 +94,7 @@ def FormatFile(filename, if in_place: if original_source and original_source != reformatted_source: file_resources.WriteReformattedCode(filename, reformatted_source, - in_place, encoding) + encoding, in_place) return None, encoding, changed return reformatted_source, encoding, changed @@ -186,14 +185,8 @@ def ReadFile(filename, logger=None): IOError: raised if there was an error reading the file. """ try: - with open(filename, 'rb') as fd: - encoding = tokenize.detect_encoding(fd.readline)[0] - except IOError as err: - if logger: - logger(err) - raise + encoding = file_resources.FileEncoding(filename) - try: # Preserves line endings. with py3compat.open_with_encoding( filename, mode='r', encoding=encoding, newline='') as fd: From 116fee89bed235b141127941914035494b119393 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 24 Aug 2017 20:15:08 -0700 Subject: [PATCH 167/719] Add space between unary 'not' and other unary operators. --- CHANGELOG | 1 + yapf/yapflib/unwrapped_line.py | 3 +++ yapftests/reformatter_pep8_test.py | 16 ++++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 8063310fc..0c09dc019 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,7 @@ were improperly aligned and/or caused output with invalid syntax. - Fix issue where specifying a line range removed a needed line before a comment. +- Fix spacing between unary operators if one is 'not'. ## [0.17.0] 2017-08-20 ### Added diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 242d31cf0..3b7e1afe0 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -275,6 +275,9 @@ def _SpaceRequiredBetween(left, right): if left.is_binary_op and lval != '**' and _IsUnaryOperator(right): # Space between the binary opertor and the unary operator. return True + if left.is_keyword and _IsUnaryOperator(right): + # Handle things like "not -3 < x". + return True if _IsUnaryOperator(left) and _IsUnaryOperator(right): # No space between two unary operators. return False diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 14cb2aecd..58e822af4 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -327,6 +327,22 @@ def a(): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testUnaryOperator(self): + unformatted_code = textwrap.dedent("""\ + if not -3 < x < 3: + pass + if -3 < x < 3: + pass + """) + expected_formatted_code = textwrap.dedent("""\ + if not -3 < x < 3: + pass + if -3 < x < 3: + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From 140f68978856646913552643d599d12c29619f28 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 24 Aug 2017 21:31:33 -0700 Subject: [PATCH 168/719] Add spaces around '=' in a typed name. --- CHANGELOG | 2 ++ yapf/yapflib/format_token.py | 2 ++ yapf/yapflib/split_penalty.py | 13 ++++++++- yapf/yapflib/subtype_assigner.py | 40 ++++++++++++++++++--------- yapf/yapflib/unwrapped_line.py | 15 ++++++---- yapftests/reformatter_python3_test.py | 6 ++-- 6 files changed, 55 insertions(+), 23 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0c09dc019..21bddc601 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,8 @@ # This project adheres to [Semantic Versioning](http://semver.org/). ## [0.17.1] UNRELEASED +### Changed +- Use spaces around the '=' in a typed name argument to align with 3.6 syntax. ### Fixed - Allow semicolons if the line is disabled. - Fix issue where subsequent comments at decreasing levels of indentation diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index de270cf58..1ace04afb 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -53,6 +53,8 @@ class Subtype(object): COMP_IF = 16 FUNC_DEF = 17 DECORATOR = 18 + TYPED_NAME = 19 + TYPED_NAME_ARG_LIST = 20 class FormatToken(object): diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 3ef4d8c20..24a851d8a 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -137,7 +137,6 @@ def Visit_arglist(self, node): # pylint: disable=invalid-name def Visit_argument(self, node): # pylint: disable=invalid-name # argument ::= test [comp_for] | test '=' test # Really [keyword '='] test self.DefaultNodeVisit(node) - index = 1 while index < len(node.children) - 1: child = node.children[index] @@ -147,6 +146,18 @@ def Visit_argument(self, node): # pylint: disable=invalid-name _FirstChildNode(node.children[index + 1]), NAMED_ASSIGN) index += 1 + def Visit_tname(self, node): # pylint: disable=invalid-name + # tname ::= NAME [':' test] + self.DefaultNodeVisit(node) + index = 1 + while index < len(node.children) - 1: + child = node.children[index] + if isinstance(child, pytree.Leaf) and child.value == ':': + _SetSplitPenalty(_FirstChildNode(node.children[index]), NAMED_ASSIGN) + _SetSplitPenalty( + _FirstChildNode(node.children[index + 1]), NAMED_ASSIGN) + index += 1 + def Visit_dotted_name(self, node): # pylint: disable=invalid-name # dotted_name ::= NAME ('.' NAME)* self._SetUnbreakableOnChildren(node) diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 646cdc8a4..40a1f3f4d 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -48,7 +48,7 @@ def AssignSubtypes(tree): # Map tokens in argument lists to their respective subtype. _ARGLIST_TOKEN_TO_SUBTYPE = { '=': format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN, - ':': format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN, + ':': format_token.Subtype.TYPED_NAME, '*': format_token.Subtype.VARARGS_STAR, '**': format_token.Subtype.KWARGS_STAR_STAR, } @@ -239,11 +239,13 @@ def Visit_arglist(self, node): # pylint: disable=invalid-name # | '*' test (',' argument)* [',' '**' test] # | '**' test) self._ProcessArgLists(node) - _SetDefaultOrNamedAssignArgListSubtype(node) + _SetArgListSubtype(node, format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN, + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) def Visit_tname(self, node): # pylint: disable=invalid-name self._ProcessArgLists(node) - _SetDefaultOrNamedAssignArgListSubtype(node) + _SetArgListSubtype(node, format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN, + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) def Visit_decorator(self, node): # pylint: disable=invalid-name # decorator ::= @@ -270,7 +272,21 @@ def Visit_typedargslist(self, node): # pylint: disable=invalid-name # | '**' tname) # | tfpdef ['=' test] (',' tfpdef ['=' test])* [',']) self._ProcessArgLists(node) - _SetDefaultOrNamedAssignArgListSubtype(node) + _SetArgListSubtype(node, format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN, + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) + tname = False + for child in node.children: + if pytree_utils.NodeName(child) == 'tname': + tname = True + _SetArgListSubtype(child, format_token.Subtype.TYPED_NAME, + format_token.Subtype.TYPED_NAME_ARG_LIST) + if not isinstance(child, pytree.Leaf): + continue + if child.value == ',': + tname = False + elif child.value == '=' and tname: + _AppendTokenSubtype(child, subtype=format_token.Subtype.TYPED_NAME) + tname = False def Visit_varargslist(self, node): # pylint: disable=invalid-name # varargslist ::= @@ -305,28 +321,26 @@ def _ProcessArgLists(self, node): format_token.Subtype.NONE)) -def _SetDefaultOrNamedAssignArgListSubtype(node): +def _SetArgListSubtype(node, node_subtype, list_subtype): """Set named assign subtype on elements in a arg list.""" - def HasDefaultOrNamedAssignSubtype(node): + def HasSubtype(node): """Return True if the arg list has a named assign subtype.""" if isinstance(node, pytree.Leaf): - if (format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in - pytree_utils.GetNodeAnnotation(node, pytree_utils.Annotation.SUBTYPE, - set())): + if node_subtype in pytree_utils.GetNodeAnnotation( + node, pytree_utils.Annotation.SUBTYPE, set()): return True return False has_subtype = False for child in node.children: if pytree_utils.NodeName(child) != 'arglist': - has_subtype |= HasDefaultOrNamedAssignSubtype(child) + has_subtype |= HasSubtype(child) return has_subtype - if HasDefaultOrNamedAssignSubtype(node): + if HasSubtype(node): for child in node.children: if pytree_utils.NodeName(child) != 'COMMA': - _AppendFirstLeafTokenSubtype( - child, format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) + _AppendFirstLeafTokenSubtype(child, list_subtype) def _AppendTokenSubtype(node, subtype): diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 3b7e1afe0..622df504d 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -262,6 +262,14 @@ def _SpaceRequiredBetween(left, right): (left.is_keyword or left.is_name)): # Don't merge two keywords/identifiers. return True + if (format_token.Subtype.SUBSCRIPT_COLON in left.subtypes or + format_token.Subtype.SUBSCRIPT_COLON in right.subtypes): + # A subscript shouldn't have spaces separating its colons. + return False + if (format_token.Subtype.TYPED_NAME in left.subtypes or + format_token.Subtype.TYPED_NAME in right.subtypes): + # A typed argument should have a space after the colon. + return True if left.is_string: if (rval == '=' and format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in right.subtypes): @@ -293,15 +301,10 @@ def _SpaceRequiredBetween(left, right): # The previous token was a unary op. No space is desired between it and # the current token. return False - if (format_token.Subtype.SUBSCRIPT_COLON in left.subtypes or - format_token.Subtype.SUBSCRIPT_COLON in right.subtypes): - # A subscript shouldn't have spaces separating its colons. - return False if (format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in left.subtypes or format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in right.subtypes): # A named argument or default parameter shouldn't have spaces around it. - # However, a typed argument should have a space after the colon. - return lval == ':' or style.Get('SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN') + return style.Get('SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN') if (format_token.Subtype.VARARGS_LIST in left.subtypes or format_token.Subtype.VARARGS_LIST in right.subtypes): return False diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index 3dcbe4bbd..12bf419e6 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -41,7 +41,7 @@ def x(aaaaaaaaaaaaaaa:int,bbbbbbbbbbbbbbbb:str,ccccccccccccccc:dict,eeeeeeeeeeee def x(aaaaaaaaaaaaaaa: int, bbbbbbbbbbbbbbbb: str, ccccccccccccccc: dict, - eeeeeeeeeeeeee: set={1, 2, 3}) -> bool: + eeeeeeeeeeeeee: set = {1, 2, 3}) -> bool: pass """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) @@ -161,11 +161,11 @@ def foo2(x: 'int' =42): pass """) expected_formatted_code = textwrap.dedent("""\ - def foo(x: int=42): + def foo(x: int = 42): pass - def foo2(x: 'int'=42): + def foo2(x: 'int' = 42): pass """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) From fe3f32e6d3ba26093dec79f37abcb8f0f3ec7fbc Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 24 Aug 2017 22:26:59 -0700 Subject: [PATCH 169/719] Indent dictionary value correctly if there is a multi-line key. --- CHANGELOG | 1 + yapf/yapflib/format_decision_state.py | 5 ++++- yapftests/reformatter_basic_test.py | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 21bddc601..241df97eb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,7 @@ - Fix issue where specifying a line range removed a needed line before a comment. - Fix spacing between unary operators if one is 'not'. +- Indent the dictionary value correctly if there's a multi-line key. ## [0.17.0] 2017-08-20 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index b7b599705..accd8e1e9 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -598,7 +598,10 @@ def MoveStateToNextToken(self): # If we encounter a closing bracket, we can remove a level from our # parenthesis stack. if len(self.stack) > 1 and current.ClosesScope(): - self.stack[-2].last_space = self.stack[-1].last_space + if format_token.Subtype.DICTIONARY_KEY_PART in current.subtypes: + self.stack[-2].last_space = self.stack[-2].indent + else: + self.stack[-2].last_space = self.stack[-1].last_space self.stack.pop() self.paren_level -= 1 diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index c205f4790..8905876d8 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1590,7 +1590,7 @@ def testMultilineDictionaryKeys(self): 1, ('consectetur adipiscing elit.', 'Vestibulum mauris justo, ornare eget dolor eget'): - 2, + 2, ('vehicula convallis nulla. Vestibulum dictum nisl in malesuada finibus.',): 3 } From 7ec4c8924db79967fd1addb9e69efd88ba0d72e6 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 26 Aug 2017 02:34:03 -0700 Subject: [PATCH 170/719] Add ALLOW_SPLIT_BEFORE_DICT_VALUE knob. If set to False, don't split before a dictionary value even if it goes over the column limit. Fixes #378 --- CHANGELOG | 5 +- README.rst | 3 + yapf/yapflib/format_decision_state.py | 21 ++++++- yapf/yapflib/style.py | 16 +++-- yapftests/reformatter_pep8_test.py | 88 +++++++++++++++++++++++++++ 5 files changed, 125 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 241df97eb..b7afd644e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.17.1] UNRELEASED +## [0.18.0] UNRELEASED +### Added +- Option `ALLOW_SPLIT_BEFORE_DICT_VALUE` allows a split before a value. If + False, then it won't be split even if it goes over the column limit. ### Changed - Use spaces around the '=' in a typed name argument to align with 3.6 syntax. ### Fixed diff --git a/README.rst b/README.rst index 3ccf98996..a6e33b935 100644 --- a/README.rst +++ b/README.rst @@ -301,6 +301,9 @@ Knobs value, } +``ALLOW_SPLIT_BEFORE_DICT_VALUE`` + Allow splits before the dictionary value. + ``BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF`` Insert a blank line before a ``def`` or ``class`` immediately nested within another ``def`` or ``class``. For example: diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index accd8e1e9..34db6c951 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -129,6 +129,7 @@ def CanSplit(self, must_split): True if the line can be split before the next token. """ current = self.next_token + previous = current.previous_token if current.is_pseudo_paren: return False @@ -141,6 +142,24 @@ def CanSplit(self, must_split): # like it. So don't allow it unless forced to. return False + if (not must_split and + format_token.Subtype.DICTIONARY_VALUE in current.subtypes and + not style.Get('ALLOW_SPLIT_BEFORE_DICT_VALUE')): + return False + + if previous and previous.value == '(' and current.value == ')': + # Don't split an empty function call list if we aren't splitting before + # dict values. + token = previous.previous_token + while token: + prev = token.previous_token + if not prev or prev.name not in {'NAME', 'DOT'}: + break + token = token.previous_token + if token and format_token.Subtype.DICTIONARY_VALUE in token.subtypes: + if not style.Get('ALLOW_SPLIT_BEFORE_DICT_VALUE'): + return False + return current.can_break_before def MustSplit(self): @@ -256,7 +275,7 @@ def MustSplit(self): if not current.OpensScope(): opening = _GetOpeningBracket(current) if not self._EachDictEntryFitsOnOneLine(opening): - return True + return style.Get('ALLOW_SPLIT_BEFORE_DICT_VALUE') if previous.value == '{': # Split if the dict/set cannot fit on one line and ends in a comma. diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index e8840e408..d475cd4f4 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -59,6 +59,8 @@ def SetGlobalStyle(style): 'this is the second element of a tuple'): value, }"""), + ALLOW_SPLIT_BEFORE_DICT_VALUE=textwrap.dedent("""\ + Allow splits before the dictionary value."""), BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=textwrap.dedent("""\ Insert a blank line before a 'def' or 'class' immediately nested within another 'def' or 'class'. For example: @@ -131,11 +133,6 @@ def method(): The number of columns to use for indentation."""), JOIN_MULTIPLE_LINES=textwrap.dedent("""\ Join short lines into one line. E.g., single line 'if' statements."""), - SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=textwrap.dedent("""\ - Insert a space between the ending comma and closing bracket of a list, - etc."""), - SPACES_AROUND_POWER_OPERATOR=textwrap.dedent("""\ - Use spaces around the power operator."""), NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=textwrap.dedent("""\ Do not include spaces around selected binary operators. For example: @@ -146,6 +143,11 @@ def method(): 1 + 2*3 - 4/5 """), + SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=textwrap.dedent("""\ + Insert a space between the ending comma and closing bracket of a list, + etc."""), + SPACES_AROUND_POWER_OPERATOR=textwrap.dedent("""\ + Use spaces around the power operator."""), SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=textwrap.dedent("""\ Use spaces around default or named assigns."""), SPACES_BEFORE_COMMENT=textwrap.dedent("""\ @@ -212,6 +214,7 @@ def CreatePEP8Style(): ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=True, ALLOW_MULTILINE_LAMBDAS=False, ALLOW_MULTILINE_DICTIONARY_KEYS=False, + ALLOW_SPLIT_BEFORE_DICT_VALUE=True, BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=False, BLANK_LINE_BEFORE_CLASS_DOCSTRING=False, COALESCE_BRACKETS=False, @@ -332,6 +335,7 @@ def _BoolConverter(s): ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=_BoolConverter, ALLOW_MULTILINE_LAMBDAS=_BoolConverter, ALLOW_MULTILINE_DICTIONARY_KEYS=_BoolConverter, + ALLOW_SPLIT_BEFORE_DICT_VALUE=_BoolConverter, BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=_BoolConverter, BLANK_LINE_BEFORE_CLASS_DOCSTRING=_BoolConverter, COALESCE_BRACKETS=_BoolConverter, @@ -344,8 +348,8 @@ def _BoolConverter(s): INDENT_DICTIONARY_VALUE=_BoolConverter, INDENT_WIDTH=int, JOIN_MULTIPLE_LINES=_BoolConverter, - SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=_BoolConverter, NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=_StringSetConverter, + SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=_BoolConverter, SPACES_AROUND_POWER_OPERATOR=_BoolConverter, SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=_BoolConverter, SPACES_BEFORE_COMMENT=int, diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 58e822af4..e47ec400a 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -343,6 +343,94 @@ def testUnaryOperator(self): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testNoSplitBeforeDictValue(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{based_on_style: pep8, ' + 'allow_split_before_dict_value: false, ' + 'coalesce_brackets: true, ' + 'dedent_closing_brackets: true, ' + 'each_dict_entry_on_separate_line: true, ' + 'split_before_logical_operator: true}')) + + unformatted_code = textwrap.dedent("""\ + some_dict = { + 'title': _("I am example data"), + 'description': _("Lorem ipsum dolor met sit amet elit, si vis pacem para bellum " + "elites nihi very long string."), + } + """) + expected_formatted_code = textwrap.dedent("""\ + some_dict = { + 'title': _("I am example data"), + 'description': _( + "Lorem ipsum dolor met sit amet elit, si vis pacem para bellum " + "elites nihi very long string." + ), + } + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + + unformatted_code = textwrap.dedent("""\ + X = {'a': 1, 'b': 2, 'key': this_is_a_function_call_that_goes_over_the_column_limit_im_pretty_sure()} + """) + expected_formatted_code = textwrap.dedent("""\ + X = { + 'a': 1, + 'b': 2, + 'key': this_is_a_function_call_that_goes_over_the_column_limit_im_pretty_sure() + } + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + + unformatted_code = textwrap.dedent("""\ + attrs = { + 'category': category, + 'role': forms.ModelChoiceField(label=_("Role"), required=False, queryset=category_roles, initial=selected_role, empty_label=_("No access"),), + } + """) + expected_formatted_code = textwrap.dedent("""\ + attrs = { + 'category': category, + 'role': forms.ModelChoiceField( + label=_("Role"), + required=False, + queryset=category_roles, + initial=selected_role, + empty_label=_("No access"), + ), + } + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + + unformatted_code = textwrap.dedent("""\ + css_class = forms.CharField( + label=_("CSS class"), + required=False, + help_text=_("Optional CSS class used to customize this category appearance from templates."), + ) + """) + expected_formatted_code = textwrap.dedent("""\ + css_class = forms.CharField( + label=_("CSS class"), + required=False, + help_text=_( + "Optional CSS class used to customize this category appearance from templates." + ), + ) + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreatePEP8Style()) + if __name__ == '__main__': unittest.main() From 72a8266e7c1eabf5dcbc1d86f64736efbcfb1119 Mon Sep 17 00:00:00 2001 From: Max Vorobev Date: Tue, 8 Aug 2017 19:26:37 +0300 Subject: [PATCH 171/719] Add verbose flag to print out filenames as they are processed --- yapf/__init__.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index bb279ad4f..add634529 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -119,6 +119,11 @@ def main(argv): action='store_true', help=('Run yapf in parallel when formatting multiple files. Requires ' 'concurrent.futures in Python 2.X')) + parser.add_argument( + '-vv', + '--verbose', + action='store_true', + help='Print out file names while processing') parser.add_argument('files', nargs='*') args = parser.parse_args(argv[1:]) @@ -185,7 +190,8 @@ def main(argv): in_place=args.in_place, print_diff=args.diff, verify=args.verify, - parallel=args.parallel) + parallel=args.parallel, + verbose=args.verbose) return 1 if changed and args.diff else 0 @@ -196,7 +202,8 @@ def FormatFiles(filenames, in_place=False, print_diff=False, verify=True, - parallel=False): + parallel=False, + verbose=False): """Format a list of files. Arguments: @@ -213,6 +220,7 @@ def FormatFiles(filenames, diff that turns the formatted source into reformatter source. verify: (bool) True if reformatted code should be verified for syntax. parallel: (bool) True if should format multiple files in parallel. + verbose: (bool) True if should print out filenames while processing. Returns: True if the source code changed in any of the files being formatted. @@ -225,7 +233,8 @@ def FormatFiles(filenames, with concurrent.futures.ProcessPoolExecutor(workers) as executor: future_formats = [ executor.submit(_FormatFile, filename, lines, style_config, - no_local_style, in_place, print_diff, verify) + no_local_style, in_place, print_diff, verify, + verbose) for filename in filenames ] for future in concurrent.futures.as_completed(future_formats): @@ -233,7 +242,7 @@ def FormatFiles(filenames, else: for filename in filenames: changed |= _FormatFile(filename, lines, style_config, no_local_style, - in_place, print_diff, verify) + in_place, print_diff, verify, verbose) return changed @@ -243,8 +252,11 @@ def _FormatFile(filename, no_local_style=False, in_place=False, print_diff=False, - verify=True): + verify=True, + verbose=False): logging.info('Reformatting %s', filename) + if verbose: + print('Reformatting %s' % filename) if style_config is None and not no_local_style: style_config = ( file_resources.GetDefaultStyleForDir(os.path.dirname(filename))) From cb030460bc77aa4cb1b3232436c89fc645ccdd3c Mon Sep 17 00:00:00 2001 From: Max Vorobev Date: Sat, 26 Aug 2017 14:43:48 +0300 Subject: [PATCH 172/719] update CHANGELOG, don't use logging to print filenames --- CHANGELOG | 1 + yapf/__init__.py | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b7afd644e..b51e47d70 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -24,6 +24,7 @@ ### Changed - Adjust blank lines on formatting boundaries when using the `--lines` option. - Return 1 if a diff changed the code. This is in line with how GNU diff acts. +- Add `-vv` flag to print out file names as they are processed ### Fixed - Corrected how `DEDENT_CLOSING_BRACKETS` and `COALESCE_BRACKETS` interacted. - Fix return value to return a boolean. diff --git a/yapf/__init__.py b/yapf/__init__.py index add634529..08edbf062 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -233,8 +233,7 @@ def FormatFiles(filenames, with concurrent.futures.ProcessPoolExecutor(workers) as executor: future_formats = [ executor.submit(_FormatFile, filename, lines, style_config, - no_local_style, in_place, print_diff, verify, - verbose) + no_local_style, in_place, print_diff, verify, verbose) for filename in filenames ] for future in concurrent.futures.as_completed(future_formats): @@ -254,7 +253,6 @@ def _FormatFile(filename, print_diff=False, verify=True, verbose=False): - logging.info('Reformatting %s', filename) if verbose: print('Reformatting %s' % filename) if style_config is None and not no_local_style: From 122a5a0d6062f45c2e6e58df1a46902e8d960b3f Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 28 Aug 2017 11:52:26 -0700 Subject: [PATCH 173/719] Remove some linter warnings. --- yapf/yapflib/comment_splicer.py | 4 ++-- yapf/yapflib/file_resources.py | 7 ++----- yapf/yapflib/pytree_utils.py | 1 + yapf/yapflib/unwrapped_line.py | 2 +- yapf/yapflib/yapf_api.py | 2 +- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index 32997b7c4..72e4d8c6a 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -119,9 +119,9 @@ def _VisitNodeRec(node): for comment_column, comment_indent, comment_group in comment_groups: ancestor_at_indent = _FindAncestorAtIndent(child, comment_indent) if ancestor_at_indent.type == token.DEDENT: - InsertNodes = pytree_utils.InsertNodesBefore + InsertNodes = pytree_utils.InsertNodesBefore # pylint: disable=invalid-name else: - InsertNodes = pytree_utils.InsertNodesAfter + InsertNodes = pytree_utils.InsertNodesAfter # pylint: disable=invalid-name InsertNodes( _CreateCommentsFromPrefix( '\n'.join(comment_group) + '\n', diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index b1305c8e5..021764ef4 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -171,8 +171,5 @@ def IsPythonFile(filename): def FileEncoding(filename): """Return the file's encoding.""" - try: - with open(filename, 'rb') as fd: - return tokenize.detect_encoding(fd.readline)[0] - except IOError: - raise + with open(filename, 'rb') as fd: + return tokenize.detect_encoding(fd.readline)[0] diff --git a/yapf/yapflib/pytree_utils.py b/yapf/yapflib/pytree_utils.py index 60fd955ff..7411db4e6 100644 --- a/yapf/yapflib/pytree_utils.py +++ b/yapf/yapflib/pytree_utils.py @@ -25,6 +25,7 @@ """ import ast + from lib2to3 import pygram from lib2to3 import pytree from lib2to3.pgen2 import driver diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 622df504d..eb0a5c2c4 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -99,7 +99,7 @@ def Split(self): else: uwline.AppendToken(tok) - if len(uwline.tokens): + if uwline.tokens: uwlines.append(uwline) for uwline in uwlines: diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index bdd1ad638..4f9a5830c 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -152,7 +152,7 @@ def FormatCode(unformatted_source, unformatted_source, reformatted_source, filename=filename) if print_diff: - return code_diff, code_diff.strip() != '' + return code_diff, code_diff.strip() != '' # pylint: disable=g-explicit-bool-comparison return reformatted_source, True From 96558985f05648d77f835b29d410faae581b14d2 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 6 Sep 2017 13:58:32 -0700 Subject: [PATCH 174/719] Retain the spacing before comments in a dict. --- CHANGELOG | 2 ++ yapf/yapflib/format_token.py | 8 +++++++- yapftests/yapf_test.py | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index b51e47d70..326552c05 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,8 @@ comment. - Fix spacing between unary operators if one is 'not'. - Indent the dictionary value correctly if there's a multi-line key. +- Don't remove needed spacing before a comment in a dict when in "chromium" + style. ## [0.17.0] 2017-08-20 ### Added diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 1ace04afb..88a79a390 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -147,9 +147,14 @@ def AdjustNewlinesBefore(self, newlines_before): def RetainHorizontalSpacing(self, first_column, depth): """Retains a token's horizontal spacing.""" previous = self.previous_token - if previous is None: + if not previous: return + if previous.is_pseudo_paren: + previous = previous.previous_token + if not previous: + return + cur_lineno = self.lineno prev_lineno = previous.lineno if previous.is_multiline_string: @@ -174,6 +179,7 @@ def RetainHorizontalSpacing(self, first_column, depth): prev_len = len(previous.value.split('\n')[-1]) if '\n' in previous.value: prev_column = 0 # Last line starts in column 0. + self.spaces_required_before = cur_column - (prev_column + prev_len) def OpensScope(self): diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index e1032b29b..490f2d4d4 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1223,6 +1223,42 @@ def _(): expected_formatted_code, extra_options=['--lines', '1-2']) + def testSpacingBeforeCommentsInDicts(self): + unformatted_code = textwrap.dedent("""\ + A=42 + + X = { + # 'Valid' statuses. + PASSED: # Passed + 'PASSED', + FAILED: # Failed + 'FAILED', + TIMED_OUT: # Timed out. + 'FAILED', + BORKED: # Broken. + 'BROKEN' + } + """) + expected_formatted_code = textwrap.dedent("""\ + A = 42 + + X = { + # 'Valid' statuses. + PASSED: # Passed + 'PASSED', + FAILED: # Failed + 'FAILED', + TIMED_OUT: # Timed out. + 'FAILED', + BORKED: # Broken. + 'BROKEN' + } + """) + self.assertYapfReformats( + unformatted_code, + expected_formatted_code, + extra_options=['--style', 'chromium', '--lines', '1-1']) + class BadInputTest(unittest.TestCase): """Test yapf's behaviour when passed bad input.""" From 4a0647603129172d21a8d4560ecb1d6b2b51e66f Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 18 Sep 2017 16:18:48 -0700 Subject: [PATCH 175/719] Increase continuation indent for 'async with' stmt An 'async with' statement needs the continuation indent increase to avoid E125. Closes #453 --- CHANGELOG | 2 ++ yapf/yapflib/format_decision_state.py | 17 ++++++++++++----- yapftests/reformatter_python3_test.py | 18 ++++++++++++++++++ 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 326552c05..c5ee9c9cb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -18,6 +18,8 @@ - Indent the dictionary value correctly if there's a multi-line key. - Don't remove needed spacing before a comment in a dict when in "chromium" style. +- Increase indent for continuation line with same indent as next logical line + with 'async with' statement. ## [0.17.0] 2017-08-20 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 34db6c951..feaffc6f1 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -31,9 +31,6 @@ from yapf.yapflib import style from yapf.yapflib import unwrapped_line -_COMPOUND_STMTS = frozenset( - {'for', 'while', 'if', 'elif', 'with', 'except', 'def', 'class'}) - class FormatDecisionState(object): """The current state when indenting an unwrapped line. @@ -184,7 +181,7 @@ def MustSplit(self): # with the exception of function declarations. if (style.Get('SPLIT_BEFORE_FIRST_ARGUMENT') and self.line.first.value != 'def' and - self.line.first.value in _COMPOUND_STMTS): + _IsCompoundStatement(self.line.first)): return False ########################################################################### @@ -580,7 +577,7 @@ def _GetNewlineColumn(self): if format_token.Subtype.DICTIONARY_VALUE in current.subtypes: return top_of_stack.indent - if (self.line.first.value in _COMPOUND_STMTS and + if (_IsCompoundStatement(self.line.first) and (not style.Get('DEDENT_CLOSING_BRACKETS') or style.Get('SPLIT_BEFORE_FIRST_ARGUMENT'))): token_indent = (len(self.line.first.whitespace_prefix.split('\n')[-1]) + @@ -715,6 +712,16 @@ def ImplicitStringConcatenation(tok): return length + self.stack[-2].indent <= self.column_limit +_COMPOUND_STMTS = frozenset( + {'for', 'while', 'if', 'elif', 'with', 'except', 'def', 'class'}) + + +def _IsCompoundStatement(token): + if token.value == 'async': + token = token.next_token + return token.value in _COMPOUND_STMTS + + def _IsFunctionCallWithArguments(token): while token: if token.value == '(': diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index 12bf419e6..d35301835 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -227,6 +227,24 @@ def _ReduceAbstractContainers( uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testContinuationIndentWithAsync(self): + if sys.version_info[1] < 5: + return + unformatted_code = textwrap.dedent("""\ + async def start_websocket(): + async with session.ws_connect( + r"ws://a_really_long_long_long_long_long_long_url") as ws: + pass + """) + expected_formatted_code = textwrap.dedent("""\ + async def start_websocket(): + async with session.ws_connect( + r"ws://a_really_long_long_long_long_long_long_url") as ws: + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From 29387650f82276bcb4650d85d9ae24ad62659d1c Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 18 Sep 2017 16:59:48 -0700 Subject: [PATCH 176/719] Bump version to v0.18.0 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c5ee9c9cb..c5811f312 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.18.0] UNRELEASED +## [0.18.0] 2017-09-18 ### Added - Option `ALLOW_SPLIT_BEFORE_DICT_VALUE` allows a split before a value. If False, then it won't be split even if it goes over the column limit. diff --git a/yapf/__init__.py b/yapf/__init__.py index 08edbf062..74cba3dee 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.17.0' +__version__ = '0.18.0' def main(argv): From cf7c43d0b13f26a4d97800015910986306918951 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 19 Sep 2017 14:30:02 -0700 Subject: [PATCH 177/719] Prefer to split after comma in argument list. --- CHANGELOG | 5 +++++ yapf/__init__.py | 4 ++-- yapf/yapflib/pytree_utils.py | 6 +++-- yapf/yapflib/split_penalty.py | 27 +++++++++++++++------- yapf/yapflib/style.py | 4 ++-- yapf/yapflib/yapf_api.py | 4 ++-- yapftests/reformatter_basic_test.py | 30 ++++++++++++------------- yapftests/reformatter_buganizer_test.py | 13 +++++++++++ 8 files changed, 61 insertions(+), 32 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c5811f312..22f6f1647 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,11 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.18.1] UNRELEASED +### Fixed +- Prefer to split after a comma in an argument list rather than in the middle + of an argument. + ## [0.18.0] 2017-09-18 ### Added - Option `ALLOW_SPLIT_BEFORE_DICT_VALUE` allows a split before a value. If diff --git a/yapf/__init__.py b/yapf/__init__.py index 74cba3dee..577637688 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -256,8 +256,8 @@ def _FormatFile(filename, if verbose: print('Reformatting %s' % filename) if style_config is None and not no_local_style: - style_config = ( - file_resources.GetDefaultStyleForDir(os.path.dirname(filename))) + style_config = file_resources.GetDefaultStyleForDir( + os.path.dirname(filename)) try: reformatted_code, encoding, has_change = yapf_api.FormatFile( filename, diff --git a/yapf/yapflib/pytree_utils.py b/yapf/yapflib/pytree_utils.py index 7411db4e6..be8177502 100644 --- a/yapf/yapflib/pytree_utils.py +++ b/yapf/yapflib/pytree_utils.py @@ -269,13 +269,15 @@ def DumpNodeToString(node): The string representation. """ if isinstance(node, pytree.Leaf): - fmt = '{name}({value}) [lineno={lineno}, column={column}, prefix={prefix}]' + fmt = ('{name}({value}) [lineno={lineno}, column={column}, ' + + 'prefix={prefix}, penalty={penalty}]') return fmt.format( name=NodeName(node), value=_PytreeNodeRepr(node), lineno=node.lineno, column=node.column, - prefix=repr(node.prefix)) + prefix=repr(node.prefix), + penalty=GetNodeAnnotation(node, Annotation.SPLIT_PENALTY, None)) else: fmt = '{node} [{len} children] [child_indent="{indent}"]' return fmt.format( diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 24a851d8a..c7092ed38 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -24,7 +24,7 @@ # TODO(morbo): Document the annotations in a centralized place. E.g., the # README file. UNBREAKABLE = 1000 * 1000 -NAMED_ASSIGN = 8500 +NAMED_ASSIGN = 11000 DOTTED_NAME = 4000 VERY_STRONGLY_CONNECTED = 3500 STRONGLY_CONNECTED = 3000 @@ -184,12 +184,11 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name _SetSplitPenalty(node.children[1], VERY_STRONGLY_CONNECTED) elif len(node.children) == 3: name = pytree_utils.NodeName(node.children[1]) - if name == 'power': - if pytree_utils.NodeName(node.children[1].children[0]) != 'atom': - # Don't split an argument list with one element if at all possible. - _SetStronglyConnected(node.children[1], node.children[2]) - _SetSplitPenalty( - _FirstChildNode(node.children[1]), ONE_ELEMENT_ARGUMENT) + if name in {'argument', 'comparison'}: + # Don't split an argument list with one element if at all possible. + _SetStronglyConnected(node.children[1]) + _SetSplitPenalty( + _FirstChildNode(node.children[1]), ONE_ELEMENT_ARGUMENT) elif (pytree_utils.NodeName(node.children[0]) == 'LSQB' and len(node.children[1].children) > 2 and (name.endswith('_test') or name.endswith('_expr'))): @@ -210,7 +209,7 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name _SetVeryStronglyConnected(node.children[-1]) elif name not in { 'arglist', 'argument', 'term', 'or_test', 'and_test', 'comparison', - 'atom' + 'atom', 'power' }: # Don't split an argument list with one element if at all possible. _SetStronglyConnected(node.children[1], node.children[2]) @@ -383,6 +382,18 @@ def Visit_arith_expr(self, node): # pylint: disable=invalid-name self.DefaultNodeVisit(node) _IncreasePenalty(node, ARITH_EXPR) + index = 1 + while index < len(node.children) - 1: + child = node.children[index] + if isinstance(child, pytree.Leaf) and child.value in '+-': + next_node = _FirstChildNode(node.children[index + 1]) + _SetSplitPenalty( + next_node, + pytree_utils.GetNodeAnnotation( + next_node, pytree_utils.Annotation.SPLIT_PENALTY, default=0) - + 100) + index += 1 + def Visit_term(self, node): # pylint: disable=invalid-name # term ::= factor (('*'|'@'|'/'|'%'|'//') factor)* _IncreasePenalty(node, TERM) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index d475cd4f4..bb5a65b5a 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -495,8 +495,8 @@ def _CreateStyleFromConfigParser(config): try: base_style[option] = _STYLE_OPTION_VALUE_CONVERTER[option](value) except ValueError: - raise StyleConfigError( - "'{}' is not a valid setting for {}.".format(value, option)) + raise StyleConfigError("'{}' is not a valid setting for {}.".format( + value, option)) return base_style diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 4f9a5830c..9c2d65a36 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -229,8 +229,8 @@ def _MarkLinesToFormat(uwlines, lines): """Skip sections of code that we shouldn't reformat.""" if lines: for uwline in uwlines: - uwline.disable = not ( - lines.intersection(range(uwline.lineno, uwline.last.lineno + 1))) + uwline.disable = not lines.intersection( + range(uwline.lineno, uwline.last.lineno + 1)) # Now go through the lines and disable any lines explicitly marked as # disabled. diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 8905876d8..780b4da29 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -486,18 +486,17 @@ def foo(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testNoQueueSeletionInMiddleOfLine(self): - # If the queue isn't properly consttructed, then a token in the middle of - # the line may be selected as the one with least penalty. The tokens after - # that one are then splatted at the end of the line with no formatting. + # If the queue isn't properly constructed, then a token in the middle of the + # line may be selected as the one with least penalty. The tokens after that + # one are then splatted at the end of the line with no formatting. # FIXME(morbo): The formatting here isn't ideal. - unformatted_code = textwrap.dedent("""\ - find_symbol(node.type) + "< " + " ".join(find_pattern(n) for n in \ -node.child) + " >" - """) - expected_formatted_code = textwrap.dedent("""\ - find_symbol(node.type) + "< " + " ".join(find_pattern(n) - for n in node.child) + " >" - """) + unformatted_code = """\ +find_symbol(node.type) + "< " + " ".join(find_pattern(n) for n in node.child) + " >" +""" + expected_formatted_code = """\ +find_symbol( + node.type) + "< " + " ".join(find_pattern(n) for n in node.child) + " >" +""" uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -744,9 +743,9 @@ def testClosingBracketIndent(self): def f(): def g(): - while ( - xxxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz]) == 'aaaaaaaaaaa' and - xxxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): + while (xxxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz]) == 'aaaaaaaaaaa' and + xxxxxxxxxxxxxxxxxxxxx( + yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): pass ''') uwlines = yapf_test_helper.ParseAndUnwrap(code) @@ -1319,8 +1318,7 @@ def testEndingComment(self): code = textwrap.dedent("""\ a = f( a="something", - b= - "something requiring comment which is quite long", # comment about b (pushes line over 79) + b="something requiring comment which is quite long", # comment about b (pushes line over 79) c="something else, about which comment doesn't make sense") """) uwlines = yapf_test_helper.ParseAndUnwrap(code) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 996a0a3f4..1feb43b2a 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,19 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB65241516(self): + unformatted_code = """\ +checkpoint_files = gfile.Glob(os.path.join(TrainTraceDir(unit_key, "*", "*"), embedding_model.CHECKPOINT_FILENAME + "-*")) +""" + expected_formatted_code = """\ +checkpoint_files = gfile.Glob( + os.path.join( + TrainTraceDir(unit_key, "*", "*"), + embedding_model.CHECKPOINT_FILENAME + "-*")) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB37460004(self): code = textwrap.dedent("""\ assert all(s not in (_SENTINEL, None) for s in From 8413f6828c9d1a15e63031e16a92a81497c1cbda Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 1 Oct 2017 00:35:30 -0700 Subject: [PATCH 178/719] Count newlines in non-multiline strings A string may have continuations in it. Account for this when retaining vertical space. Closes #457 --- CHANGELOG | 3 +++ yapf/yapflib/reformatter.py | 2 +- yapftests/reformatter_basic_test.py | 9 +++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 22f6f1647..1adc2b42d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,9 @@ ### Fixed - Prefer to split after a comma in an argument list rather than in the middle of an argument. +- A non-multiline string may have newlines if it contains continuation markers + itself. Don't add a newline after the string when retaining the vertical + space. ## [0.18.0] 2017-09-18 ### Added diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 8d2b4dcde..0417bfd3f 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -178,7 +178,7 @@ def _EmitLineUnformatted(state): previous_token = state.next_token.previous_token previous_lineno = previous_token.lineno - if previous_token.is_multiline_string: + if previous_token.is_multiline_string or previous_token.is_string: previous_lineno += previous_token.value.count('\n') if previous_token.is_continuation: diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 780b4da29..8c88fad18 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1106,6 +1106,15 @@ def testMultipleContinuationMarkers(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testContinuationMarkerAfterStringWithContinuation(self): + code = """\ +s = 'foo \\ + bar' \\ + .format() +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testEmptyContainers(self): code = textwrap.dedent("""\ flags.DEFINE_list( From 2863c5b63b1cd1d304a0f05820ac7871f015f1b3 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 1 Oct 2017 01:12:22 -0700 Subject: [PATCH 179/719] Take "async" into account when splitting before first arg. Closes #458 --- CHANGELOG | 2 + yapf/yapflib/format_decision_state.py | 10 +++- yapftests/reformatter_python3_test.py | 67 +++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1adc2b42d..c266a3675 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,8 @@ - A non-multiline string may have newlines if it contains continuation markers itself. Don't add a newline after the string when retaining the vertical space. +- Take into account the "async" keyword when determining if we must split + before the first argument. ## [0.18.0] 2017-09-18 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index feaffc6f1..109b64e96 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -180,8 +180,8 @@ def MustSplit(self): # Prevent splitting before the first argument in compound statements # with the exception of function declarations. if (style.Get('SPLIT_BEFORE_FIRST_ARGUMENT') and - self.line.first.value != 'def' and - _IsCompoundStatement(self.line.first)): + _IsCompoundStatement(self.line.first) and + not _IsFunctionDef(self.line.first)): return False ########################################################################### @@ -722,6 +722,12 @@ def _IsCompoundStatement(token): return token.value in _COMPOUND_STMTS +def _IsFunctionDef(token): + if token.value == 'async': + token = token.next_token + return token.value == 'def' + + def _IsFunctionCallWithArguments(token): while token: if token.value == '(': diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index d35301835..bd0c2115f 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -245,6 +245,73 @@ async def start_websocket(): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testNoSpacesAroundPowerOparator(self): + if sys.version_info[1] < 5: + return + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: pep8, ' + 'dedent_closing_brackets: true, ' + 'coalesce_brackets: false, ' + 'space_between_ending_comma_and_closing_bracket: false, ' + 'split_arguments_when_comma_terminated: true, ' + 'split_before_first_argument: true}')) + unformatted_code = """\ +async def open_file(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None): + pass + +async def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): + pass + +def open_file(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None): + pass + +def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): + pass +""" + expected_formatted_code = """\ +async def open_file( + file, + mode='r', + buffering=-1, + encoding=None, + errors=None, + newline=None, + closefd=True, + opener=None +): + pass + + +async def run_sync_in_worker_thread( + sync_fn, *args, cancellable=False, limiter=None +): + pass + + +def open_file( + file, + mode='r', + buffering=-1, + encoding=None, + errors=None, + newline=None, + closefd=True, + opener=None +): + pass + + +def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): + pass +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreatePEP8Style()) + if __name__ == '__main__': unittest.main() From 1fccd67c1879be85cff882d9613f4cf2f1f2278d Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 4 Oct 2017 02:59:30 -0700 Subject: [PATCH 180/719] Increase affinity for "atom" arguments. --- CHANGELOG | 2 ++ yapf/yapflib/split_penalty.py | 4 ++++ yapftests/reformatter_basic_test.py | 6 +++--- yapftests/reformatter_buganizer_test.py | 10 ++++++++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c266a3675..b54db777e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,8 @@ space. - Take into account the "async" keyword when determining if we must split before the first argument. +- Increase affinity for "atom" arguments in function calls. This helps prevent + lists from being separated when they don't need to be. ## [0.18.0] 2017-09-18 ### Added diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index c7092ed38..3770dcbef 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -28,6 +28,7 @@ DOTTED_NAME = 4000 VERY_STRONGLY_CONNECTED = 3500 STRONGLY_CONNECTED = 3000 +CONNECTED = 500 OR_TEST = 1000 AND_TEST = 1100 @@ -133,6 +134,9 @@ def Visit_arglist(self, node): # pylint: disable=invalid-name if isinstance(child, pytree.Leaf) and child.value == ',': _SetUnbreakable(child) index += 1 + for child in node.children: + if pytree_utils.NodeName(child) == 'atom': + _IncreasePenalty(child, CONNECTED) def Visit_argument(self, node): # pylint: disable=invalid-name # argument ::= test [comp_for] | test '=' test # Really [keyword '='] test diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 8c88fad18..3464d845f 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2045,9 +2045,9 @@ def testDictionaryElementsOnOneLine(self): code = textwrap.dedent("""\ class _(): - @mock.patch.dict(os.environ, { - 'HTTP_' + xsrf._XSRF_TOKEN_HEADER.replace('-', '_'): 'atoken' - }) + @mock.patch.dict( + os.environ, + {'HTTP_' + xsrf._XSRF_TOKEN_HEADER.replace('-', '_'): 'atoken'}) def _(): pass diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 1feb43b2a..375229316 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,16 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB67312284(self): + code = """\ +def _(): + self.assertEqual( + [u'to be published 2', u'to be published 1', u'to be published 0'], + [el.text for el in page.first_column_tds]) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB65241516(self): unformatted_code = """\ checkpoint_files = gfile.Glob(os.path.join(TrainTraceDir(unit_key, "*", "*"), embedding_model.CHECKPOINT_FILENAME + "-*")) From 911e0eec3ff88221b19603775bd7872352a6ee84 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 5 Oct 2017 15:54:09 -0700 Subject: [PATCH 181/719] Reformat to remove 80-column violations. --- CONTRIBUTING.rst | 4 +-- plugins/README.rst | 70 +++++++++++++++++++++++-------------------- plugins/pre-commit.sh | 37 +++++++++++++---------- 3 files changed, 61 insertions(+), 50 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index e6a71800b..0b113c0d8 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -34,8 +34,8 @@ as the Google Python Style guide with two exceptions: - 2 spaces for indentation rather than 4. - CamelCase for function and method names rather than words_with_underscores. -The rationale for this is that YAPF was initially developed at Google where these -two exceptions are still part of the internal Python style guide. +The rationale for this is that YAPF was initially developed at Google where +these two exceptions are still part of the internal Python style guide. Small print ----------- diff --git a/plugins/README.rst b/plugins/README.rst index 56d32175b..550aa5dc7 100644 --- a/plugins/README.rst +++ b/plugins/README.rst @@ -5,8 +5,8 @@ IDE Plugins Emacs ===== -The ``Emacs`` plugin is maintained separately. -Installation directions can be found here: https://github.com/paetzke/py-yapf.el +The ``Emacs`` plugin is maintained separately. Installation directions can be +found here: https://github.com/paetzke/py-yapf.el VIM === @@ -33,11 +33,11 @@ You can add key bindings in the ``.vimrc`` file: Sublime Text ============ -The ``Sublime Text`` plugin is also maintained separately. -It is compatible with both Sublime Text 2 and 3. +The ``Sublime Text`` plugin is also maintained separately. It is compatible +with both Sublime Text 2 and 3. -The plugin can be easily installed by using *Sublime Package Control*. -Check the project page of the plugin for more information: +The plugin can be easily installed by using *Sublime Package Control*. Check +the project page of the plugin for more information: https://github.com/jason-kane/PyYapf =================== @@ -48,7 +48,8 @@ The ``git`` pre-commit hook automatically formats your Python files before they are committed to your local repository. Any changes ``yapf`` makes to the files will stay unstaged so that you can diff them manually. -To install, simply download the raw file and copy it into your git hooks directory: +To install, simply download the raw file and copy it into your git hooks +directory: .. code-block:: bash @@ -60,40 +61,43 @@ To install, simply download the raw file and copy it into your git hooks directo Textmate 2 ========== -Plugin for ``Textmate 2`` requires ``yapf`` Python package installed on your system: +Plugin for ``Textmate 2`` requires ``yapf`` Python package installed on your +system: .. code-block:: shell pip install yapf -Also, you will need to activate ``Python`` bundle from ``Preferences >> Bundles``. +Also, you will need to activate ``Python`` bundle from ``Preferences >> +Bundles``. -Finally, create a ``~/Library/Application Support/TextMate/Bundles/Python.tmbundle/Commands/YAPF.tmCommand`` -file with the following content: +Finally, create a ``~/Library/Application +Support/TextMate/Bundles/Python.tmbundle/Commands/YAPF.tmCommand`` file with +the following content: .. code-block:: xml - - - - - beforeRunningCommand - saveActiveFile - command - #!/bin/bash - - TPY=${TM_PYTHON:-python} - - "$TPY" "/usr/local/bin/yapf" "$TM_FILEPATH" - input - document - name - YAPF - scope - source.python - uuid - 297D5A82-2616-4950-9905-BD2D1C94D2D4 - - + + + + + beforeRunningCommand + saveActiveFile + command + #!/bin/bash + + TPY=${TM_PYTHON:-python} + + "$TPY" "/usr/local/bin/yapf" "$TM_FILEPATH" + input + document + name + YAPF + scope + source.python + uuid + 297D5A82-2616-4950-9905-BD2D1C94D2D4 + + You will see a new menu item ``Bundles > Python > YAPF``. diff --git a/plugins/pre-commit.sh b/plugins/pre-commit.sh index 24976b51f..acd46c68f 100644 --- a/plugins/pre-commit.sh +++ b/plugins/pre-commit.sh @@ -1,22 +1,28 @@ #!/bin/bash -# Git pre-commit hook to check staged Python files for formatting issues with yapf. +# Git pre-commit hook to check staged Python files for formatting issues with +# yapf. # -# INSTALLING: Copy this script into `.git/hooks/pre-commit`, and mark it as executable. +# INSTALLING: Copy this script into `.git/hooks/pre-commit`, and mark it as +# executable. # -# This requires that yapf is installed and runnable in the environment running the pre-commit hook. +# This requires that yapf is installed and runnable in the environment running +# the pre-commit hook. # -# When running, this first checks for unstaged changes to staged files, and if there are any, it -# will exit with an error. Files with unstaged changes will be printed. +# When running, this first checks for unstaged changes to staged files, and if +# there are any, it will exit with an error. Files with unstaged changes will be +# printed. # -# If all staged files have no unstaged changes, it will run yapf against them, leaving the -# formatting changes unstaged. Changed files will be printed. +# If all staged files have no unstaged changes, it will run yapf against them, +# leaving the formatting changes unstaged. Changed files will be printed. # -# BUGS: This does not leave staged changes alone when used with the -a flag to git commit, due to -# the fact that git stages ALL unstaged files when that flag is used. +# BUGS: This does not leave staged changes alone when used with the -a flag to +# git commit, due to the fact that git stages ALL unstaged files when that flag +# is used. # Find all staged Python files, and exit early if there aren't any. -PYTHON_FILES=(`git diff --name-only --cached --diff-filter=AM | grep --color=never '.py$'`) +PYTHON_FILES=(`git diff --name-only --cached --diff-filter=AM | \ + grep --color=never '.py$'`) if [ ! "$PYTHON_FILES" ]; then exit 0 fi @@ -31,9 +37,9 @@ fi # Check for unstaged changes to files in the index. CHANGED_FILES=(`git diff --name-only ${PYTHON_FILES[@]}`) if [ "$CHANGED_FILES" ]; then - echo 'You have unstaged changes to some files in your commit; skipping auto-format.' - echo 'Please stage, stash, or revert these changes.' - echo 'You may find `git stash -k` helpful here.' + echo 'You have unstaged changes to some files in your commit; skipping ' + echo 'auto-format. Please stage, stash, or revert these changes. You may ' + echo 'find `git stash -k` helpful here.' echo echo 'Files with unstaged changes:' for file in ${CHANGED_FILES[@]}; do @@ -41,12 +47,13 @@ if [ "$CHANGED_FILES" ]; then done exit 1 fi -# Format all staged files, then exit with an error code if any have uncommitted changes. +# Format all staged files, then exit with an error code if any have uncommitted +# changes. echo 'Formatting staged Python files . . .' yapf -i -r ${PYTHON_FILES[@]} CHANGED_FILES=(`git diff --name-only ${PYTHON_FILES[@]}`) if [ "$CHANGED_FILES" ]; then - echo 'Some staged files were reformatted. Please review the changes and stage them.' + echo 'Reformatted staged files. Please review and stage the changes.' echo echo 'Files updated:' for file in ${CHANGED_FILES[@]}; do From 41dcba67b0c6d7736ff5a6baffb81e317e328f16 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 5 Oct 2017 16:11:44 -0700 Subject: [PATCH 182/719] Fix some pylint warnings. --- yapf/__main__.py | 2 ++ yapf/yapflib/pytree_utils.py | 2 +- yapftests/main_test.py | 2 +- yapftests/reformatter_python3_test.py | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/yapf/__main__.py b/yapf/__main__.py index 88f1ec69e..2ebc7a635 100644 --- a/yapf/__main__.py +++ b/yapf/__main__.py @@ -11,6 +11,8 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Main entry point.""" +# pylint: disable=invalid-name import yapf yapf.run_main() diff --git a/yapf/yapflib/pytree_utils.py b/yapf/yapflib/pytree_utils.py index be8177502..417bdb11e 100644 --- a/yapf/yapflib/pytree_utils.py +++ b/yapf/yapflib/pytree_utils.py @@ -269,7 +269,7 @@ def DumpNodeToString(node): The string representation. """ if isinstance(node, pytree.Leaf): - fmt = ('{name}({value}) [lineno={lineno}, column={column}, ' + + fmt = ('{name}({value}) [lineno={lineno}, column={column}, ' 'prefix={prefix}, penalty={penalty}]') return fmt.format( name=NodeName(node), diff --git a/yapftests/main_test.py b/yapftests/main_test.py index 95e199182..508c02c26 100644 --- a/yapftests/main_test.py +++ b/yapftests/main_test.py @@ -123,7 +123,7 @@ def testEchoInputWithStyle(self): def testEchoBadInput(self): bad_syntax = ' a = 1\n' with patched_input(bad_syntax): - with captured_output() as (out, _): + with captured_output() as (_, _): with self.assertRaisesRegexp(SyntaxError, 'unexpected indent'): yapf.main([]) diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index bd0c2115f..c6a3e99dd 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -245,7 +245,7 @@ async def start_websocket(): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - def testNoSpacesAroundPowerOparator(self): + def testSplittingArguments(self): if sys.version_info[1] < 5: return try: From f3154357d6ab4572364cdee1ababa6bc79cfa20a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 7 Oct 2017 03:22:12 -0700 Subject: [PATCH 183/719] Split before dict key if it's the last argument. --- CHANGELOG | 2 ++ yapf/yapflib/format_decision_state.py | 11 ++++++++++- yapftests/reformatter_basic_test.py | 6 +++--- yapftests/reformatter_buganizer_test.py | 24 ++++++++++++++++++++++++ yapftests/style_test.py | 10 ++++++---- 5 files changed, 45 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b54db777e..a0566cd2b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,8 @@ before the first argument. - Increase affinity for "atom" arguments in function calls. This helps prevent lists from being separated when they don't need to be. +- Don't place a dictionary argument on its own line if it's the last argument + in the function call where that function is part of a builder-style call. ## [0.18.0] 2017-09-18 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 109b64e96..28c866699 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -255,7 +255,16 @@ def MustSplit(self): if (opening and opening.value == '(' and opening.previous_token and opening.previous_token.is_name): # This is a dictionary that's an argument to a function. - if self._FitsOnLine(previous, previous.matching_bracket): + if (self._FitsOnLine(previous, previous.matching_bracket) and + previous.matching_bracket.next_token and + not previous.matching_bracket.next_token.ClosesScope() and + (not opening.matching_bracket.next_token or + opening.matching_bracket.next_token.value != '.')): + # Don't split before the key if: + # - The dictionary fits on a line, and + # - The dictionary brackets don't have a closing scope after + # them, and + # - The function call isn't part of a builder-style call. return False return True diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 3464d845f..8c88fad18 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2045,9 +2045,9 @@ def testDictionaryElementsOnOneLine(self): code = textwrap.dedent("""\ class _(): - @mock.patch.dict( - os.environ, - {'HTTP_' + xsrf._XSRF_TOKEN_HEADER.replace('-', '_'): 'atoken'}) + @mock.patch.dict(os.environ, { + 'HTTP_' + xsrf._XSRF_TOKEN_HEADER.replace('-', '_'): 'atoken' + }) def _(): pass diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 375229316..72eb4239e 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,30 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB66912275(self): + unformatted_code = """\ +def _(): + with self.assertRaisesRegexp(errors.HttpError, 'Invalid'): + patch_op = api_client.forwardingRules().patch( + project=project_id, + region=region, + forwardingRule=rule_name, + body={'fingerprint': base64.urlsafe_b64encode('invalid_fingerprint')}).execute() +""" + expected_formatted_code = """\ +def _(): + with self.assertRaisesRegexp(errors.HttpError, 'Invalid'): + patch_op = api_client.forwardingRules().patch( + project=project_id, + region=region, + forwardingRule=rule_name, + body={ + 'fingerprint': base64.urlsafe_b64encode('invalid_fingerprint') + }).execute() +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB67312284(self): code = """\ def _(): diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 02ecbae7e..583b80cef 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -225,11 +225,13 @@ def testDefaultBasedOnStyle(self): def testDefaultBasedOnStyleBadDict(self): self.assertRaisesRegexp(style.StyleConfigError, 'Unknown style option', - style.CreateStyleFromConfig, - {'based_on_styl': 'pep8'}) + style.CreateStyleFromConfig, { + 'based_on_styl': 'pep8' + }) self.assertRaisesRegexp(style.StyleConfigError, 'not a valid', - style.CreateStyleFromConfig, - {'INDENT_WIDTH': 'FOUR'}) + style.CreateStyleFromConfig, { + 'INDENT_WIDTH': 'FOUR' + }) class StyleFromCommandLine(unittest.TestCase): From 17b98a03c6e99885db94919e6e2e247b19439085 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 8 Oct 2017 01:12:27 -0700 Subject: [PATCH 184/719] Split before ending ')' if comma terminated. --- CHANGELOG | 3 ++ setup.py | 3 +- yapf/yapflib/format_decision_state.py | 18 +++++++ yapf/yapflib/style.py | 9 ++-- yapftests/reformatter_basic_test.py | 27 +++++----- yapftests/reformatter_buganizer_test.py | 71 +++++++++++++++++-------- 6 files changed, 93 insertions(+), 38 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a0566cd2b..b64975004 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,9 @@ # This project adheres to [Semantic Versioning](http://semver.org/). ## [0.18.1] UNRELEASED +### Changed +- Split before the ending bracket of a comma-terminated tuple / argument list + if it's not a single element tuple / arg list. ### Fixed - Prefer to split after a comma in an argument list rather than in the middle of an argument. diff --git a/setup.py b/setup.py index 30ea2508b..7d677b290 100644 --- a/setup.py +++ b/setup.py @@ -70,4 +70,5 @@ def run(self): }, cmdclass={ 'test': RunTests, - },) + }, + ) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 28c866699..92d28ae96 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -177,6 +177,10 @@ def MustSplit(self): # Split before the closing bracket if we can. return current.node_split_penalty != split_penalty.UNBREAKABLE + if current.value == ')' and previous.value == ',' and not _IsSingleElementTuple( + current.matching_bracket): + return True + # Prevent splitting before the first argument in compound statements # with the exception of function declarations. if (style.Get('SPLIT_BEFORE_FIRST_ARGUMENT') and @@ -791,6 +795,20 @@ def _IsLastScopeInLine(current): return True +def _IsSingleElementTuple(token): + close = token.matching_bracket + token = token.next_token + num_commas = 0 + while token != close: + if token.value == ',': + num_commas += 1 + if token.OpensScope(): + token = token.matching_bracket + else: + token = token.next_token + return num_commas == 1 + + class _ParenState(object): """Maintains the state of the bracket enclosures. diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index bb5a65b5a..edfbab68f 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -246,7 +246,8 @@ def CreatePEP8Style(): SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=30, SPLIT_PENALTY_IMPORT_NAMES=0, SPLIT_PENALTY_LOGICAL_OPERATOR=300, - USE_TABS=False,) + USE_TABS=False, + ) def CreateGoogleStyle(): @@ -292,7 +293,8 @@ def CreateFacebookStyle(): pep8=CreatePEP8Style, chromium=CreateChromiumStyle, google=CreateGoogleStyle, - facebook=CreateFacebookStyle,) + facebook=CreateFacebookStyle, +) _DEFAULT_STYLE_TO_FACTORY = [ (CreateChromiumStyle(), CreateChromiumStyle), @@ -367,7 +369,8 @@ def _BoolConverter(s): SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=int, SPLIT_PENALTY_IMPORT_NAMES=int, SPLIT_PENALTY_LOGICAL_OPERATOR=int, - USE_TABS=_BoolConverter,) + USE_TABS=_BoolConverter, +) def CreateStyleFromConfig(style_config): diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 8c88fad18..66ac1b215 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -458,19 +458,20 @@ def given(y): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testOpeningAndClosingBrackets(self): - unformatted_code = textwrap.dedent("""\ - foo( (1, ) ) - foo( ( 1, 2, 3 ) ) - foo( ( 1, 2, 3, ) ) - """) - expected_formatted_code = textwrap.dedent("""\ - foo((1,)) - foo((1, 2, 3)) - foo(( - 1, - 2, - 3,)) - """) + unformatted_code = """\ +foo( (1, ) ) +foo( ( 1, 2, 3 ) ) +foo( ( 1, 2, 3, ) ) +""" + expected_formatted_code = """\ +foo((1,)) +foo((1, 2, 3)) +foo(( + 1, + 2, + 3, +)) +""" uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 72eb4239e..199cea034 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,33 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB32167774(self): + unformatted_code = """\ +X = ( + 'is_official', + 'is_cover', + 'is_remix', + 'is_instrumental', + 'is_live', + 'has_lyrics', + 'is_album', + 'is_compilation',) +""" + expected_formatted_code = """\ +X = ( + 'is_official', + 'is_cover', + 'is_remix', + 'is_instrumental', + 'is_live', + 'has_lyrics', + 'is_album', + 'is_compilation', +) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB66912275(self): unformatted_code = """\ def _(): @@ -372,17 +399,18 @@ def __init__(self, metric, fields_cb=None): self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB31911533(self): - code = textwrap.dedent("""\ - class _(): - - @parameterized.NamedParameters( - ('IncludingModInfoWithHeaderList', AAAA, aaaa), - ('IncludingModInfoWithoutHeaderList', BBBB, bbbbb), - ('ExcludingModInfoWithHeaderList', CCCCC, cccc), - ('ExcludingModInfoWithoutHeaderList', DDDDD, ddddd),) - def _(): - pass - """) + code = """\ +class _(): + + @parameterized.NamedParameters( + ('IncludingModInfoWithHeaderList', AAAA, aaaa), + ('IncludingModInfoWithoutHeaderList', BBBB, bbbbb), + ('ExcludingModInfoWithHeaderList', CCCCC, cccc), + ('ExcludingModInfoWithoutHeaderList', DDDDD, ddddd), + ) + def _(): + pass +""" uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1465,16 +1493,17 @@ def testB15438132(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB14468247(self): - unformatted_code = textwrap.dedent("""\ - call(a=1, - b=2, - ) - """) - expected_formatted_code = textwrap.dedent("""\ - call( - a=1, - b=2,) - """) + unformatted_code = """\ +call(a=1, + b=2, +) +""" + expected_formatted_code = """\ +call( + a=1, + b=2, +) +""" uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) From c154464fb505f730ee329e30a968fb06e3a59ab1 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 9 Oct 2017 01:11:38 -0700 Subject: [PATCH 185/719] Split after opening paren that surrounds an expr --- CHANGELOG | 5 +++- README.rst | 4 +++ yapf/yapflib/comment_splicer.py | 5 ++-- yapf/yapflib/format_decision_state.py | 38 +++++++++++++++++++++---- yapf/yapflib/format_token.py | 5 ++-- yapf/yapflib/pytree_unwrapper.py | 4 +-- yapf/yapflib/reformatter.py | 4 +-- yapf/yapflib/style.py | 14 +++++++-- yapf/yapflib/unwrapped_line.py | 4 +-- yapftests/reformatter_buganizer_test.py | 21 ++++++++++++++ 10 files changed, 84 insertions(+), 20 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b64975004..795b21a39 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.18.1] UNRELEASED +## [0.19.0] UNRELEASED +### Added +- Added `SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN` that enforces a split + after the opening paren of an expression that's surrounded by parens. ### Changed - Split before the ending bracket of a comma-terminated tuple / argument list if it's not a single element tuple / arg list. diff --git a/README.rst b/README.rst index a6e33b935..3578e2072 100644 --- a/README.rst +++ b/README.rst @@ -443,6 +443,10 @@ Knobs for variable in bar if variable != 42 } +``SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN`` + Split after the opening paren which surrounds an expression if it doesn't + fit on a single line. + ``SPLIT_BEFORE_FIRST_ARGUMENT`` If an argument / parameter list is going to be split, then split before the first argument. diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index 72e4d8c6a..f374eea07 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -176,8 +176,9 @@ def _VisitNodeRec(node): rindex = (0 if '\n' not in comment_prefix.rstrip() else comment_prefix.rstrip().rindex('\n') + 1) - comment_column = (len(comment_prefix[rindex:]) - - len(comment_prefix[rindex:].lstrip())) + comment_column = ( + len(comment_prefix[rindex:]) - + len(comment_prefix[rindex:].lstrip())) comments = _CreateCommentsFromPrefix( comment_prefix, comment_lineno, diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 92d28ae96..539085e4a 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -216,6 +216,29 @@ def MustSplit(self): # Split before and dedent the closing bracket. return self.stack[-1].split_before_closing_bracket + if (style.Get('SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN') and + current.is_name): + # An expression that's surrounded by parens gets split after the opening + # parenthesis. + def SurroundedByParens(token): + while token: + if token.value == ',': + return False + if token.value == ')': + return not token.next_token + if token.OpensScope(): + token = token.matching_bracket.next_token + else: + token = token.next_token + return False + + if (previous.value == '(' and not previous.is_pseudo_paren and + not unwrapped_line.IsSurroundedByBrackets(previous)): + pptoken = previous.previous_token + if (pptoken and not pptoken.is_name and not pptoken.is_keyword and + SurroundedByParens(current)): + return True + if (current.is_name or current.is_string) and previous.value == ',': # If the list has function calls in it and the full list itself cannot # fit on the line, then we want to split. Otherwise, we'll get something @@ -323,8 +346,9 @@ def MustSplit(self): opening = _GetOpeningBracket(current) if opening: - arglist_length = (opening.matching_bracket.total_length - - opening.total_length + self.stack[-1].indent) + arglist_length = ( + opening.matching_bracket.total_length - opening.total_length + + self.stack[-1].indent) return arglist_length > self.column_limit if style.Get('SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED'): @@ -549,8 +573,9 @@ def _AddTokenOnNewline(self, dry_run, must_split): if current.value not in {'if', 'for'}: last = self.stack[-1] last.num_line_splits += 1 - penalty += (style.Get('SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT') * - last.num_line_splits) + penalty += ( + style.Get('SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT') * + last.num_line_splits) if current.OpensScope() and previous.OpensScope(): # Prefer to keep opening brackets coalesced (unless it's at the beginning @@ -593,8 +618,9 @@ def _GetNewlineColumn(self): if (_IsCompoundStatement(self.line.first) and (not style.Get('DEDENT_CLOSING_BRACKETS') or style.Get('SPLIT_BEFORE_FIRST_ARGUMENT'))): - token_indent = (len(self.line.first.whitespace_prefix.split('\n')[-1]) + - style.Get('INDENT_WIDTH')) + token_indent = ( + len(self.line.first.whitespace_prefix.split('\n')[-1]) + + style.Get('INDENT_WIDTH')) if token_indent == top_of_stack.indent: return top_of_stack.indent + style.Get('CONTINUATION_INDENT_WIDTH') diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 88a79a390..88952762f 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -123,8 +123,9 @@ def AddWhitespacePrefix(self, newlines_before, spaces=0, indent_level=0): """ indent_char = '\t' if style.Get('USE_TABS') else ' ' token_indent_char = indent_char if newlines_before > 0 else ' ' - indent_before = (indent_char * indent_level * style.Get('INDENT_WIDTH') + - token_indent_char * spaces) + indent_before = ( + indent_char * indent_level * style.Get('INDENT_WIDTH') + + token_indent_char * spaces) if self.is_comment: comment_lines = [s.lstrip() for s in self.value.splitlines()] diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index 67be85ba1..31df6b90f 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -133,8 +133,8 @@ def Visit_simple_stmt(self, node): # standalone comment and in the case of it coming directly after the # funcdef, it is a "top" comment for the whole function. # TODO(eliben): add more relevant compound statements here. - single_stmt_suite = (node.parent and - pytree_utils.NodeName(node.parent) in self._STMT_TYPES) + single_stmt_suite = ( + node.parent and pytree_utils.NodeName(node.parent) in self._STMT_TYPES) is_comment_stmt = pytree_utils.IsCommentStatement(node) if single_stmt_suite and not is_comment_stmt: self._cur_depth += 1 diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 0417bfd3f..647cff931 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -184,8 +184,8 @@ def _EmitLineUnformatted(state): if previous_token.is_continuation: newline = False else: - newline = (prev_lineno is not None and - state.next_token.lineno > previous_lineno) + newline = ( + prev_lineno is not None and state.next_token.lineno > previous_lineno) prev_lineno = state.next_token.lineno state.AddTokenToState(newline=newline, dry_run=False) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index edfbab68f..8f30ab034 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -166,6 +166,10 @@ def method(): variable: 'Hello world, have a nice day!' for variable in bar if variable != 42 }"""), + SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=textwrap.dedent("""\ + Split after the opening paren which surrounds an expression if it doesn't + fit on a single line. + """), SPLIT_BEFORE_FIRST_ARGUMENT=textwrap.dedent("""\ If an argument / parameter list is going to be split, then split before the first argument."""), @@ -235,6 +239,7 @@ def CreatePEP8Style(): SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False, SPLIT_BEFORE_BITWISE_OPERATOR=True, SPLIT_BEFORE_DICT_SET_GENERATOR=True, + SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=False, SPLIT_BEFORE_FIRST_ARGUMENT=False, SPLIT_BEFORE_LOGICAL_OPERATOR=True, SPLIT_BEFORE_NAMED_ASSIGNS=True, @@ -271,6 +276,7 @@ def CreateChromiumStyle(): style['INDENT_WIDTH'] = 2 style['JOIN_MULTIPLE_LINES'] = False style['SPLIT_BEFORE_BITWISE_OPERATOR'] = True + style['SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN'] = True return style @@ -358,6 +364,7 @@ def _BoolConverter(s): SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter, SPLIT_BEFORE_BITWISE_OPERATOR=_BoolConverter, SPLIT_BEFORE_DICT_SET_GENERATOR=_BoolConverter, + SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=_BoolConverter, SPLIT_BEFORE_FIRST_ARGUMENT=_BoolConverter, SPLIT_BEFORE_LOGICAL_OPERATOR=_BoolConverter, SPLIT_BEFORE_NAMED_ASSIGNS=_BoolConverter, @@ -510,9 +517,10 @@ def _CreateStyleFromConfigParser(config): _GLOBAL_STYLE_FACTORY = CreatePEP8Style # The name of the file to use for global style definition. -GLOBAL_STYLE = (os.path.join( - os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'), 'yapf', - 'style')) +GLOBAL_STYLE = ( + os.path.join( + os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'), 'yapf', + 'style')) # The name of the file to use for directory-local style definition. LOCAL_STYLE = '.style.yapf' diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index eb0a5c2c4..b27de2978 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -79,8 +79,8 @@ def CalculateFormattingInformation(self): # because these may use it for their decision. token.split_penalty += _SplitPenalty(prev_token, token) token.must_break_before = _MustBreakBefore(prev_token, token) - token.can_break_before = (token.must_break_before or - _CanBreakBefore(prev_token, token)) + token.can_break_before = ( + token.must_break_before or _CanBreakBefore(prev_token, token)) prev_length = token.total_length prev_token = token diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 199cea034..c733981ff 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,27 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB35210166(self): + unformatted_code = """\ +def _(): + query = ( + m.Fetch(n.Raw('monarch.BorgTask', '/proc/container/memory/usage'), { 'borg_user': borguser, 'borg_job': jobname }) + | o.Window(m.Align('5m')) | p.GroupBy(['borg_user', 'borg_job', 'borg_cell'], q.Mean())) +""" + expected_formatted_code = """\ +def _(): + query = ( + m.Fetch( + n.Raw('monarch.BorgTask', '/proc/container/memory/usage'), { + 'borg_user': borguser, + 'borg_job': jobname + }) + | o.Window(m.Align('5m')) + | p.GroupBy(['borg_user', 'borg_job', 'borg_cell'], q.Mean())) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB32167774(self): unformatted_code = """\ X = ( From ea22c15991743266ff03854688754731c24bec43 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 9 Oct 2017 01:11:38 -0700 Subject: [PATCH 186/719] Split after opening paren that surrounds an expr --- CHANGELOG | 5 ++- README.rst | 4 +++ yapf/yapflib/comment_splicer.py | 5 +-- yapf/yapflib/format_decision_state.py | 44 ++++++++++++++++++++----- yapf/yapflib/format_token.py | 5 +-- yapf/yapflib/pytree_unwrapper.py | 4 +-- yapf/yapflib/reformatter.py | 4 +-- yapf/yapflib/style.py | 14 ++++++-- yapf/yapflib/unwrapped_line.py | 4 +-- yapftests/reformatter_buganizer_test.py | 21 ++++++++++++ 10 files changed, 88 insertions(+), 22 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b64975004..795b21a39 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.18.1] UNRELEASED +## [0.19.0] UNRELEASED +### Added +- Added `SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN` that enforces a split + after the opening paren of an expression that's surrounded by parens. ### Changed - Split before the ending bracket of a comma-terminated tuple / argument list if it's not a single element tuple / arg list. diff --git a/README.rst b/README.rst index a6e33b935..3578e2072 100644 --- a/README.rst +++ b/README.rst @@ -443,6 +443,10 @@ Knobs for variable in bar if variable != 42 } +``SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN`` + Split after the opening paren which surrounds an expression if it doesn't + fit on a single line. + ``SPLIT_BEFORE_FIRST_ARGUMENT`` If an argument / parameter list is going to be split, then split before the first argument. diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index 72e4d8c6a..f374eea07 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -176,8 +176,9 @@ def _VisitNodeRec(node): rindex = (0 if '\n' not in comment_prefix.rstrip() else comment_prefix.rstrip().rindex('\n') + 1) - comment_column = (len(comment_prefix[rindex:]) - - len(comment_prefix[rindex:].lstrip())) + comment_column = ( + len(comment_prefix[rindex:]) - + len(comment_prefix[rindex:].lstrip())) comments = _CreateCommentsFromPrefix( comment_prefix, comment_lineno, diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 92d28ae96..60913b4d3 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -177,8 +177,8 @@ def MustSplit(self): # Split before the closing bracket if we can. return current.node_split_penalty != split_penalty.UNBREAKABLE - if current.value == ')' and previous.value == ',' and not _IsSingleElementTuple( - current.matching_bracket): + if (current.value == ')' and previous.value == ',' and + not _IsSingleElementTuple(current.matching_bracket)): return True # Prevent splitting before the first argument in compound statements @@ -216,6 +216,30 @@ def MustSplit(self): # Split before and dedent the closing bracket. return self.stack[-1].split_before_closing_bracket + if (style.Get('SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN') and + current.is_name): + # An expression that's surrounded by parens gets split after the opening + # parenthesis. + def SurroundedByParens(token): + """Check if it's an expression surrounded by parentheses.""" + while token: + if token.value == ',': + return False + if token.value == ')': + return not token.next_token + if token.OpensScope(): + token = token.matching_bracket.next_token + else: + token = token.next_token + return False + + if (previous.value == '(' and not previous.is_pseudo_paren and + not unwrapped_line.IsSurroundedByBrackets(previous)): + pptoken = previous.previous_token + if (pptoken and not pptoken.is_name and not pptoken.is_keyword and + SurroundedByParens(current)): + return True + if (current.is_name or current.is_string) and previous.value == ',': # If the list has function calls in it and the full list itself cannot # fit on the line, then we want to split. Otherwise, we'll get something @@ -323,8 +347,9 @@ def MustSplit(self): opening = _GetOpeningBracket(current) if opening: - arglist_length = (opening.matching_bracket.total_length - - opening.total_length + self.stack[-1].indent) + arglist_length = ( + opening.matching_bracket.total_length - opening.total_length + + self.stack[-1].indent) return arglist_length > self.column_limit if style.Get('SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED'): @@ -549,8 +574,9 @@ def _AddTokenOnNewline(self, dry_run, must_split): if current.value not in {'if', 'for'}: last = self.stack[-1] last.num_line_splits += 1 - penalty += (style.Get('SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT') * - last.num_line_splits) + penalty += ( + style.Get('SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT') * + last.num_line_splits) if current.OpensScope() and previous.OpensScope(): # Prefer to keep opening brackets coalesced (unless it's at the beginning @@ -593,8 +619,9 @@ def _GetNewlineColumn(self): if (_IsCompoundStatement(self.line.first) and (not style.Get('DEDENT_CLOSING_BRACKETS') or style.Get('SPLIT_BEFORE_FIRST_ARGUMENT'))): - token_indent = (len(self.line.first.whitespace_prefix.split('\n')[-1]) + - style.Get('INDENT_WIDTH')) + token_indent = ( + len(self.line.first.whitespace_prefix.split('\n')[-1]) + + style.Get('INDENT_WIDTH')) if token_indent == top_of_stack.indent: return top_of_stack.indent + style.Get('CONTINUATION_INDENT_WIDTH') @@ -796,6 +823,7 @@ def _IsLastScopeInLine(current): def _IsSingleElementTuple(token): + """Check if it's a single-element tuple.""" close = token.matching_bracket token = token.next_token num_commas = 0 diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 88a79a390..88952762f 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -123,8 +123,9 @@ def AddWhitespacePrefix(self, newlines_before, spaces=0, indent_level=0): """ indent_char = '\t' if style.Get('USE_TABS') else ' ' token_indent_char = indent_char if newlines_before > 0 else ' ' - indent_before = (indent_char * indent_level * style.Get('INDENT_WIDTH') + - token_indent_char * spaces) + indent_before = ( + indent_char * indent_level * style.Get('INDENT_WIDTH') + + token_indent_char * spaces) if self.is_comment: comment_lines = [s.lstrip() for s in self.value.splitlines()] diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index 67be85ba1..31df6b90f 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -133,8 +133,8 @@ def Visit_simple_stmt(self, node): # standalone comment and in the case of it coming directly after the # funcdef, it is a "top" comment for the whole function. # TODO(eliben): add more relevant compound statements here. - single_stmt_suite = (node.parent and - pytree_utils.NodeName(node.parent) in self._STMT_TYPES) + single_stmt_suite = ( + node.parent and pytree_utils.NodeName(node.parent) in self._STMT_TYPES) is_comment_stmt = pytree_utils.IsCommentStatement(node) if single_stmt_suite and not is_comment_stmt: self._cur_depth += 1 diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 0417bfd3f..647cff931 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -184,8 +184,8 @@ def _EmitLineUnformatted(state): if previous_token.is_continuation: newline = False else: - newline = (prev_lineno is not None and - state.next_token.lineno > previous_lineno) + newline = ( + prev_lineno is not None and state.next_token.lineno > previous_lineno) prev_lineno = state.next_token.lineno state.AddTokenToState(newline=newline, dry_run=False) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index edfbab68f..8f30ab034 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -166,6 +166,10 @@ def method(): variable: 'Hello world, have a nice day!' for variable in bar if variable != 42 }"""), + SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=textwrap.dedent("""\ + Split after the opening paren which surrounds an expression if it doesn't + fit on a single line. + """), SPLIT_BEFORE_FIRST_ARGUMENT=textwrap.dedent("""\ If an argument / parameter list is going to be split, then split before the first argument."""), @@ -235,6 +239,7 @@ def CreatePEP8Style(): SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False, SPLIT_BEFORE_BITWISE_OPERATOR=True, SPLIT_BEFORE_DICT_SET_GENERATOR=True, + SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=False, SPLIT_BEFORE_FIRST_ARGUMENT=False, SPLIT_BEFORE_LOGICAL_OPERATOR=True, SPLIT_BEFORE_NAMED_ASSIGNS=True, @@ -271,6 +276,7 @@ def CreateChromiumStyle(): style['INDENT_WIDTH'] = 2 style['JOIN_MULTIPLE_LINES'] = False style['SPLIT_BEFORE_BITWISE_OPERATOR'] = True + style['SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN'] = True return style @@ -358,6 +364,7 @@ def _BoolConverter(s): SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter, SPLIT_BEFORE_BITWISE_OPERATOR=_BoolConverter, SPLIT_BEFORE_DICT_SET_GENERATOR=_BoolConverter, + SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=_BoolConverter, SPLIT_BEFORE_FIRST_ARGUMENT=_BoolConverter, SPLIT_BEFORE_LOGICAL_OPERATOR=_BoolConverter, SPLIT_BEFORE_NAMED_ASSIGNS=_BoolConverter, @@ -510,9 +517,10 @@ def _CreateStyleFromConfigParser(config): _GLOBAL_STYLE_FACTORY = CreatePEP8Style # The name of the file to use for global style definition. -GLOBAL_STYLE = (os.path.join( - os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'), 'yapf', - 'style')) +GLOBAL_STYLE = ( + os.path.join( + os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'), 'yapf', + 'style')) # The name of the file to use for directory-local style definition. LOCAL_STYLE = '.style.yapf' diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index eb0a5c2c4..b27de2978 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -79,8 +79,8 @@ def CalculateFormattingInformation(self): # because these may use it for their decision. token.split_penalty += _SplitPenalty(prev_token, token) token.must_break_before = _MustBreakBefore(prev_token, token) - token.can_break_before = (token.must_break_before or - _CanBreakBefore(prev_token, token)) + token.can_break_before = ( + token.must_break_before or _CanBreakBefore(prev_token, token)) prev_length = token.total_length prev_token = token diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 199cea034..c733981ff 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,27 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB35210166(self): + unformatted_code = """\ +def _(): + query = ( + m.Fetch(n.Raw('monarch.BorgTask', '/proc/container/memory/usage'), { 'borg_user': borguser, 'borg_job': jobname }) + | o.Window(m.Align('5m')) | p.GroupBy(['borg_user', 'borg_job', 'borg_cell'], q.Mean())) +""" + expected_formatted_code = """\ +def _(): + query = ( + m.Fetch( + n.Raw('monarch.BorgTask', '/proc/container/memory/usage'), { + 'borg_user': borguser, + 'borg_job': jobname + }) + | o.Window(m.Align('5m')) + | p.GroupBy(['borg_user', 'borg_job', 'borg_cell'], q.Mean())) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB32167774(self): unformatted_code = """\ X = ( From f6a14b22264acef079da3d3571ab01e9c5782cbd Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 12 Oct 2017 15:58:29 -0700 Subject: [PATCH 187/719] Append a 'var arg' type to the star in a star_expr --- CHANGELOG | 1 + yapf/yapflib/subtype_assigner.py | 1 + yapftests/reformatter_buganizer_test.py | 7 +++++++ yapftests/subtype_assigner_test.py | 3 ++- 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 795b21a39..0ad370d4f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -21,6 +21,7 @@ lists from being separated when they don't need to be. - Don't place a dictionary argument on its own line if it's the last argument in the function call where that function is part of a builder-style call. +- Append the "var arg" type to a star in a star_expr. ## [0.18.0] 2017-09-18 ### Added diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 40a1f3f4d..213ce3131 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -150,6 +150,7 @@ def Visit_star_expr(self, node): # pylint: disable=invalid-name self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == '*': _AppendTokenSubtype(child, format_token.Subtype.UNARY_OPERATOR) + _AppendTokenSubtype(child, format_token.Subtype.VARARGS_STAR) def Visit_expr(self, node): # pylint: disable=invalid-name # expr ::= xor_expr ('|' xor_expr)* diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index c733981ff..bee5e72f0 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,13 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB65176185(self): + code = """\ +xx = zip(*[(a, b) for (a, b, c) in yy]) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB35210166(self): unformatted_code = """\ def _(): diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index db0e17d10..766e8decb 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -188,7 +188,8 @@ def testFunctionCallWithStarExpression(self): [('[', [format_token.Subtype.NONE]), ('a', [format_token.Subtype.NONE]), (',', [format_token.Subtype.NONE]), - ('*', {format_token.Subtype.UNARY_OPERATOR}), + ('*', {format_token.Subtype.UNARY_OPERATOR, + format_token.Subtype.VARARGS_STAR}), ('b', [format_token.Subtype.NONE]), (']', [format_token.Subtype.NONE]),], ]) # yapf: disable From 92b0f758791dea90e257424b57f5cb65966c6808 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 14 Oct 2017 15:02:31 -0700 Subject: [PATCH 188/719] Bump version to v0.19.0 --- CHANGELOG | 2 +- HACKING.rst | 4 +++- yapf/__init__.py | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0ad370d4f..49096dc19 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.19.0] UNRELEASED +## [0.19.0] 2017-10-14 ### Added - Added `SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN` that enforces a split after the opening paren of an expression that's surrounded by parens. diff --git a/HACKING.rst b/HACKING.rst index 097b69522..ee29a111b 100644 --- a/HACKING.rst +++ b/HACKING.rst @@ -21,7 +21,9 @@ Releasing a new version * Check it looks OK, install it onto a virtualenv, run tests, run yapf as a tool -* Push to PyPI: python setup.py sdist bdist_wheel upload +* Build release: python setup.py sdist bdist_wheel + +* Push to PyPI: twine upload dist/* * Test in a clean virtualenv that 'pip install yapf' works with the new version diff --git a/yapf/__init__.py b/yapf/__init__.py index 577637688..d80818592 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.18.0' +__version__ = '0.19.0' def main(argv): From 0fcaa75a51448e6f05f7b9c7551c1371ab4bcab4 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 16 Oct 2017 00:37:58 -0700 Subject: [PATCH 189/719] Split before a named assign when first arg is func call --- CHANGELOG | 5 ++++ yapf/yapflib/format_decision_state.py | 2 +- yapftests/reformatter_buganizer_test.py | 36 ++++++++++++++++++++++--- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 49096dc19..293b6f893 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,11 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.19.1] UNRELEASED +### Changed +- Take into account a named function argument when determining if we should + split before the first argument in a function call. + ## [0.19.0] 2017-10-14 ### Added - Added `SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN` that enforces a split diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 60913b4d3..c5d84feaf 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -773,7 +773,7 @@ def _IsFunctionCallWithArguments(token): if token.value == '(': token = token.next_token return token and token.value != ')' - elif token.name not in {'NAME', 'DOT'}: + elif token.name not in {'NAME', 'DOT', 'EQUAL'}: break token = token.next_token return False diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index bee5e72f0..9501850ad 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,35 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB34774905(self): + unformatted_code = """\ +x=[VarExprType(ir_name=IrName( value='x', +expr_type=UnresolvedAttrExprType( atom=UnknownExprType(), attr_name=IrName( + value='x', expr_type=UnknownExprType(), usage='UNKNOWN', fqn=None, + astn=None), usage='REF'), usage='ATTR', fqn='.x', astn=None))] +""" + expected_formatted_code = """\ +x = [ + VarExprType( + ir_name=IrName( + value='x', + expr_type=UnresolvedAttrExprType( + atom=UnknownExprType(), + attr_name=IrName( + value='x', + expr_type=UnknownExprType(), + usage='UNKNOWN', + fqn=None, + astn=None), + usage='REF'), + usage='ATTR', + fqn='.x', + astn=None)) +] +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB65176185(self): code = """\ xx = zip(*[(a, b) for (a, b, c) in yy]) @@ -1315,9 +1344,10 @@ def f(): def f(): if True: if True: - return aaaa.bbbbbbbbb(ccccccc=dddddddddddddd({ - ('eeee', 'ffffffff'): str(j) - })) + return aaaa.bbbbbbbbb( + ccccccc=dddddddddddddd({ + ('eeee', 'ffffffff'): str(j) + })) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) From f27eb6d1aa2aceb696842fdaf1c25d2d9a67f1e9 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 16 Oct 2017 02:45:46 -0700 Subject: [PATCH 190/719] Split before first argument if dict appears in arg list --- CHANGELOG | 2 + yapf/yapflib/format_decision_state.py | 25 +++++++++ yapftests/reformatter_buganizer_test.py | 67 ++++++++++++++++++------- 3 files changed, 77 insertions(+), 17 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 293b6f893..fb7a63e7e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,8 @@ ### Changed - Take into account a named function argument when determining if we should split before the first argument in a function call. +- Split before the first argument in a function call if the arguments contain a + dictionary that doesn't fit on a single line. ## [0.19.0] 2017-10-14 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index c5d84feaf..31f967a72 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -352,6 +352,10 @@ def SurroundedByParens(token): self.stack[-1].indent) return arglist_length > self.column_limit + if (current.value not in '{)' and previous.value == '(' and + self._ArgumentListHasDictionaryEntry(current)): + return True + if style.Get('SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED'): # Split before arguments in a function call or definition if the # arguments are terminated by a comma. @@ -751,6 +755,19 @@ def ImplicitStringConcatenation(tok): length += len(entry_start.value) return length + self.stack[-2].indent <= self.column_limit + def _ArgumentListHasDictionaryEntry(self, token): + if _IsArgumentToFunction(token): + while token: + if token.value == '{': + length = token.matching_bracket.total_length - token.total_length + return length + self.stack[-2].indent > self.column_limit + if token.ClosesScope(): + break + if token.OpensScope(): + token = token.matching_bracket + token = token.next_token + return False + _COMPOUND_STMTS = frozenset( {'for', 'while', 'if', 'elif', 'with', 'except', 'def', 'class'}) @@ -779,6 +796,14 @@ def _IsFunctionCallWithArguments(token): return False +def _IsArgumentToFunction(token): + bracket = unwrapped_line.IsSurroundedByBrackets(token) + if not bracket or bracket.value != '(': + return False + previous = bracket.previous_token + return previous and previous.is_name + + def _GetLengthOfSubtype(token, subtype, exclude=None): current = token while (current.next_token and subtype in current.subtypes and diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 9501850ad..3d040f8fd 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,36 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB35210351(self): + unformatted_code = """\ +def _(): + config.AnotherRuleThing( + 'the_title_to_the_thing_here', + {'monitorname': 'firefly', + 'service': ACCOUNTING_THING, + 'severity': 'the_bug', + 'monarch_module_name': alerts.TheLabel(qa_module_regexp, invert=True)}, + fanout, + alerts.AlertUsToSomething( + GetTheAlertToIt('the_title_to_the_thing_here'), + GetNotificationTemplate('your_email_here'))) +""" + expected_formatted_code = """\ +def _(): + config.AnotherRuleThing( + 'the_title_to_the_thing_here', { + 'monitorname': 'firefly', + 'service': ACCOUNTING_THING, + 'severity': 'the_bug', + 'monarch_module_name': alerts.TheLabel(qa_module_regexp, invert=True) + }, fanout, + alerts.AlertUsToSomething( + GetTheAlertToIt('the_title_to_the_thing_here'), + GetNotificationTemplate('your_email_here'))) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB34774905(self): unformatted_code = """\ x=[VarExprType(ir_name=IrName( value='x', @@ -894,20 +924,21 @@ def f(): class F(): def f(): - self.assertDictEqual(accounts, { - 'foo': { - 'account': 'foo', - 'lines': 'l1\\nl2\\nl3\\n1 line(s) were elided.' - }, - 'bar': { - 'account': 'bar', - 'lines': 'l5\\nl6\\nl7' - }, - 'wiz': { - 'account': 'wiz', - 'lines': 'l8' - } - }) + self.assertDictEqual( + accounts, { + 'foo': { + 'account': 'foo', + 'lines': 'l1\\nl2\\nl3\\n1 line(s) were elided.' + }, + 'bar': { + 'account': 'bar', + 'lines': 'l5\\nl6\\nl7' + }, + 'wiz': { + 'account': 'wiz', + 'lines': 'l8' + } + }) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -972,9 +1003,11 @@ def _(): | m.ggggggg(bbbbbbbbbbbbbbb) | m.ppppp( (1 - m.ffffffffffffffff(llllllllllllllllllllll * 1000000, m.vvv)) - * m.ddddddddddddddddd(m.vvv)), m.fffff( - m.rrr('mmmmmmmmmmmmmmmm', 'sssssssssssssssssssssss'), - dict(ffffffffffffffff, **{ + * m.ddddddddddddddddd(m.vvv)), + m.fffff( + m.rrr('mmmmmmmmmmmmmmmm', 'sssssssssssssssssssssss'), + dict( + ffffffffffffffff, **{ 'mmmmmm:ssssss': m.rrrrrrrrrrr('|'.join(iiiiiiiiiiiiii), iiiiii=True) })) From a06154469d1b1cbbe972a3623d8bed8faa0fc84f Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 16 Oct 2017 03:22:19 -0700 Subject: [PATCH 191/719] Space between ellipses and keywords Closes #464 --- CHANGELOG | 2 ++ README.rst | 7 +++++-- yapf/yapflib/unwrapped_line.py | 3 +++ yapftests/reformatter_basic_test.py | 2 ++ 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index fb7a63e7e..7dbe0a045 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,8 @@ split before the first argument in a function call. - Split before the first argument in a function call if the arguments contain a dictionary that doesn't fit on a single line. +### Fixed +- Enforce spaces between ellipses and keywords. ## [0.19.0] 2017-10-14 ### Added diff --git a/README.rst b/README.rst index 3578e2072..ae2bc74c9 100644 --- a/README.rst +++ b/README.rst @@ -90,6 +90,7 @@ Options:: usage: yapf [-h] [-v] [-d | -i] [-r | -l START-END] [-e PATTERN] [--style STYLE] [--style-help] [--no-local-style] [-p] + [-vv] [files [files ...]] Formatter for Python code. @@ -113,10 +114,12 @@ Options:: .style.yapf or setup.cfg file located in one of the parent directories of the source file (or current directory for stdin) - --style-help show style settings and exit - --no-local-style don't search for local style definition (.style.yapf) + --style-help show style settings and exit; this output can be saved + to .style.yapf to make your settings permanent + --no-local-style don't search for local style definition -p, --parallel Run yapf in parallel when formatting multiple files. Requires concurrent.futures in Python 2.X + -vv, --verbose Print out file names while processing Formatting style diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index b27de2978..21a4cc7fb 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -315,6 +315,9 @@ def _SpaceRequiredBetween(left, right): if lval == '@' and format_token.Subtype.DECORATOR in left.subtypes: # Decorators shouldn't be separated from the 'at' sign. return False + if left.is_keyword and rval == '.' or lval == '.' and right.is_keyword: + # Add space between keywords and dots. + return True if lval == '.' or rval == '.': # Don't place spaces between dots. return False diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 66ac1b215..843dd8dad 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2201,9 +2201,11 @@ def foo(): def testEllipses(self): unformatted_code = textwrap.dedent("""\ X=... + Y = X if ... else X """) expected_code = textwrap.dedent("""\ X = ... + Y = X if ... else X """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertEqual(expected_code, reformatter.Reformat(uwlines)) From d1d3cd2d78d5923ca0742994839a8eb517116b7b Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 16 Oct 2017 22:45:17 -0700 Subject: [PATCH 192/719] List comp split penalties are set after trailer penalties --- CHANGELOG | 3 +++ yapf/yapflib/split_penalty.py | 2 +- yapftests/reformatter_basic_test.py | 5 ++--- yapftests/reformatter_buganizer_test.py | 11 +++++++++++ 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 7dbe0a045..9b795b0df 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,9 @@ dictionary that doesn't fit on a single line. ### Fixed - Enforce spaces between ellipses and keywords. +- When calculating the split penalty for a "trailer", process the child nodes + afterwards because their penalties may change. For example if a list + comprehension is an argument. ## [0.19.0] 2017-10-14 ### Added diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 3770dcbef..55a71345d 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -179,7 +179,6 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name def Visit_trailer(self, node): # pylint: disable=invalid-name # trailer ::= '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME - self.DefaultNodeVisit(node) if node.children[0].value == '.': self._SetUnbreakableOnChildren(node) _SetSplitPenalty(node.children[1], DOTTED_NAME) @@ -217,6 +216,7 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name }: # Don't split an argument list with one element if at all possible. _SetStronglyConnected(node.children[1], node.children[2]) + self.DefaultNodeVisit(node) def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring # power ::= atom trailer* ['**' factor] diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 843dd8dad..f5ae90eef 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -490,13 +490,12 @@ def testNoQueueSeletionInMiddleOfLine(self): # If the queue isn't properly constructed, then a token in the middle of the # line may be selected as the one with least penalty. The tokens after that # one are then splatted at the end of the line with no formatting. - # FIXME(morbo): The formatting here isn't ideal. unformatted_code = """\ find_symbol(node.type) + "< " + " ".join(find_pattern(n) for n in node.child) + " >" """ expected_formatted_code = """\ -find_symbol( - node.type) + "< " + " ".join(find_pattern(n) for n in node.child) + " >" +find_symbol(node.type) + "< " + " ".join(find_pattern(n) + for n in node.child) + " >" """ uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 3d040f8fd..c4a54d8bb 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,17 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB67455376(self): + unformatted_code = """\ +sponge_ids.extend(invocation.id() for invocation in self._client.GetInvocationsByLabels(labels)) +""" + expected_formatted_code = """\ +sponge_ids.extend(invocation.id() + for invocation in self._client.GetInvocationsByLabels(labels)) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB35210351(self): unformatted_code = """\ def _(): From 715b84f4799370dd1fe3c903910c485f6034f1e9 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 16 Oct 2017 23:16:14 -0700 Subject: [PATCH 193/719] Don't enforce a split before a comment after a container opening. --- CHANGELOG | 2 + yapf/yapflib/format_decision_state.py | 20 +++++----- yapftests/reformatter_buganizer_test.py | 49 ++++++++++++++++++++----- 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9b795b0df..dc5078e88 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,8 @@ - When calculating the split penalty for a "trailer", process the child nodes afterwards because their penalties may change. For example if a list comprehension is an argument. +- Don't enforce a split before a comment after the opening of a container if it + doesn't it on the current line. We try hard not to move such comments around. ## [0.19.0] 2017-10-14 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 31f967a72..fee7b5417 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -408,16 +408,15 @@ def SurroundedByParens(token): return True if (previous.OpensScope() and not current.OpensScope() and + not current.is_comment and format_token.Subtype.SUBSCRIPT_BRACKET not in previous.subtypes): - if not current.is_comment: - if pprevious and not pprevious.is_keyword and not pprevious.is_name: - # We want to split if there's a comment in the container. - token = current - while token != previous.matching_bracket: - if token.is_comment: - return True - token = token.next_token - + if pprevious and not pprevious.is_keyword and not pprevious.is_name: + # We want to split if there's a comment in the container. + token = current + while token != previous.matching_bracket: + if token.is_comment: + return True + token = token.next_token if previous.value == '(': pptoken = previous.previous_token if not pptoken or not pptoken.is_name: @@ -431,7 +430,7 @@ def SurroundedByParens(token): return current.next_token != previous.matching_bracket else: # Split after the opening of a container if it doesn't fit on the - # current line or if it has a comment. + # current line. if not self._FitsOnLine(previous, previous.matching_bracket): return True @@ -756,6 +755,7 @@ def ImplicitStringConcatenation(tok): return length + self.stack[-2].indent <= self.column_limit def _ArgumentListHasDictionaryEntry(self, token): + """Check if the function argument list has a dictionary as an arg.""" if _IsArgumentToFunction(token): while token: if token.value == '{': diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index c4a54d8bb..aef6380e8 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,38 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB66011084(self): + unformatted_code = """\ +X = { +"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": # Comment 1. +([] if True else [ # Comment 2. + "bbbbbbbbbbbbbbbbbbb", # Comment 3. + "cccccccccccccccccccccccc", # Comment 4. + "ddddddddddddddddddddddddd", # Comment 5. + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", # Comment 6. + "fffffffffffffffffffffffffffffff", # Comment 7. + "ggggggggggggggggggggggggggg", # Comment 8. + "hhhhhhhhhhhhhhhhhh", # Comment 9. +]), +} +""" + expected_formatted_code = """\ +X = { + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": # Comment 1. + ([] if True else [ # Comment 2. + "bbbbbbbbbbbbbbbbbbb", # Comment 3. + "cccccccccccccccccccccccc", # Comment 4. + "ddddddddddddddddddddddddd", # Comment 5. + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", # Comment 6. + "fffffffffffffffffffffffffffffff", # Comment 7. + "ggggggggggggggggggggggggggg", # Comment 8. + "hhhhhhhhhhhhhhhhhh", # Comment 9. + ]), +} +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB67455376(self): unformatted_code = """\ sponge_ids.extend(invocation.id() for invocation in self._client.GetInvocationsByLabels(labels)) @@ -1292,15 +1324,14 @@ def testB19194420(self): self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB19073499(self): - code = textwrap.dedent("""\ - instance = ( - aaaaaaa.bbbbbbb().ccccccccccccccccc().ddddddddddd({ - 'aa': 'context!' - }).eeeeeeeeeeeeeeeeeee( - { # Inline comment about why fnord has the value 6. - 'fnord': 6 - })) - """) + code = """\ +instance = ( + aaaaaaa.bbbbbbb().ccccccccccccccccc().ddddddddddd({ + 'aa': 'context!' + }).eeeeeeeeeeeeeeeeeee({ # Inline comment about why fnord has the value 6. + 'fnord': 6 + })) +""" uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) From f673ad2136a1b33aa26d1bd17375b2c232c1acc0 Mon Sep 17 00:00:00 2001 From: Zach Langley Date: Thu, 19 Oct 2017 10:45:16 -0700 Subject: [PATCH 194/719] Make async formatting more intelligent Before Python 3.5, async was not a keyword. The formatting of Python 2 code that uses async as a module name, for example, should not treat async as a keyword. --- yapf/yapflib/reformatter.py | 9 ++++++++- yapftests/reformatter_basic_test.py | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 647cff931..7ed7a6230 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -435,6 +435,13 @@ def _FormatFirstToken(first_token, indent_depth, prev_uwline, final_lines): TWO_BLANK_LINES = 3 +def _IsClassOrDef(uwline): + if uwline.first.value in {'class', 'def'}: + return True + + return (t.name for t in uwline.tokens[:2]) == ('async', 'def') + + def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, final_lines): """Calculate the number of newlines we need to add. @@ -507,7 +514,7 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, pytree_utils.SetNodeAnnotation( first_token.node, pytree_utils.Annotation.NEWLINES, None) return NO_BLANK_LINES - elif prev_uwline.first.value in {'class', 'def', 'async'}: + elif _IsClassOrDef(prev_uwline): if not style.Get('BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'): pytree_utils.SetNodeAnnotation(first_token.node, pytree_utils.Annotation.NEWLINES, None) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index f5ae90eef..cc5d16a8f 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2328,6 +2328,27 @@ def testSplitAfterComment(self): finally: style.SetGlobalStyle(style.CreateChromiumStyle()) + def testAsyncAsNonKeyword(self): + try: + style.SetGlobalStyle(style.CreatePEP8Style()) + + # In Python 2, async may be used as a non-keyword identifier. + code = textwrap.dedent("""\ + from util import async + + + class A(object): + def foo(self): + async.run() + + def bar(self): + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines, verify=False)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + if __name__ == '__main__': unittest.main() From 7cbd97af0a5c27a153c94a58d6cbb0830d9bbfcd Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 21 Oct 2017 00:02:49 -0700 Subject: [PATCH 195/719] Improve splitting in tuples. Split if the tuple element is a function call that doesn't fit on the current line. --- CHANGELOG | 2 ++ yapf/yapflib/format_decision_state.py | 31 ++++++++++------- yapf/yapflib/yapf_api.py | 14 ++++---- yapftests/reformatter_basic_test.py | 32 +++++++++--------- yapftests/reformatter_buganizer_test.py | 45 +++++++++++++++++++++++++ yapftests/split_penalty_test.py | 5 +-- 6 files changed, 93 insertions(+), 36 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index dc5078e88..26122462a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,8 @@ split before the first argument in a function call. - Split before the first argument in a function call if the arguments contain a dictionary that doesn't fit on a single line. +- Improve splitting of elements in a tuple. We want to split if there's a + function call in the tuple that doesn't fit on the line. ### Fixed - Enforce spaces between ellipses and keywords. - When calculating the split penalty for a "trailer", process the child nodes diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index fee7b5417..de781c264 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -256,21 +256,25 @@ def SurroundedByParens(token): # # or when a string formatting syntax. func_call_or_string_format = False + tok = current.next_token if current.is_name: - tok = current.next_token while tok and (tok.is_name or tok.value == '.'): tok = tok.next_token func_call_or_string_format = tok and tok.value == '(' elif current.is_string: - tok = current.next_token while tok and tok.is_string: tok = tok.next_token func_call_or_string_format = tok and tok.value == '%' if func_call_or_string_format: open_bracket = unwrapped_line.IsSurroundedByBrackets(current) - if open_bracket and open_bracket.value in '[{': - if not self._FitsOnLine(open_bracket, open_bracket.matching_bracket): - return True + if open_bracket: + if open_bracket.value in '[{': + if not self._FitsOnLine(open_bracket, + open_bracket.matching_bracket): + return True + elif tok.value == '(': + if not self._FitsOnLine(current, tok.matching_bracket): + return True ########################################################################### # Dict/Set Splitting @@ -375,18 +379,21 @@ def SurroundedByParens(token): (opening.previous_token.is_name or opening.previous_token.value in {'*', '**'})): is_func_call = False - token = current - while token: - if token.value == '(': + opening = current + while opening: + if opening.value == '(': is_func_call = True break - if (not (token.is_name or token.value in {'*', '**'}) and - token.value != '.'): + if (not (opening.is_name or opening.value in {'*', '**'}) and + opening.value != '.'): break - token = token.next_token + opening = opening.next_token if is_func_call: - if not self._FitsOnLine(current, opening.matching_bracket): + if (not self._FitsOnLine(current, opening.matching_bracket) or + (opening.matching_bracket.next_token and + opening.matching_bracket.next_token.value != ',' and + not opening.matching_bracket.next_token.ClosesScope())): return True pprevious = previous.previous_token diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 9c2d65a36..a2c943930 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -252,15 +252,17 @@ def _MarkLinesToFormat(uwlines, lines): def _DisableYAPF(line): - return ( - re.search(DISABLE_PATTERN, line.split('\n')[0].strip(), re.IGNORECASE) or - re.search(DISABLE_PATTERN, line.split('\n')[-1].strip(), re.IGNORECASE)) + return (re.search(DISABLE_PATTERN, + line.split('\n')[0].strip(), re.IGNORECASE) or + re.search(DISABLE_PATTERN, + line.split('\n')[-1].strip(), re.IGNORECASE)) def _EnableYAPF(line): - return ( - re.search(ENABLE_PATTERN, line.split('\n')[0].strip(), re.IGNORECASE) or - re.search(ENABLE_PATTERN, line.split('\n')[-1].strip(), re.IGNORECASE)) + return (re.search(ENABLE_PATTERN, + line.split('\n')[0].strip(), re.IGNORECASE) or + re.search(ENABLE_PATTERN, + line.split('\n')[-1].strip(), re.IGNORECASE)) def _GetUnifiedDiff(before, after, filename='code'): diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index cc5d16a8f..cef399a36 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -797,15 +797,16 @@ def x(self, node, name, n=1): self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testFunctionCallContinuationLine(self): - code = textwrap.dedent("""\ - class foo: - - def bar(self, node, name, n=1): - if True: - if True: - return [(aaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb( - cccc, ddddddddddddddddddddddddddddddddddddd))] - """) + code = """\ +class foo: + + def bar(self, node, name, n=1): + if True: + if True: + return [(aaaaaaaaaa, + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb( + cccc, ddddddddddddddddddddddddddddddddddddd))] +""" uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1037,13 +1038,12 @@ def b(self): self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testTrailerOnSingleLine(self): - code = textwrap.dedent("""\ - urlpatterns = patterns('', - url(r'^$', 'homepage_view'), - url(r'^/login/$', 'login_view'), - url(r'^/login/$', 'logout_view'), - url(r'^/user/(?P\\w+)/$', 'profile_view')) - """) + code = """\ +urlpatterns = patterns('', url(r'^$', 'homepage_view'), + url(r'^/login/$', 'login_view'), + url(r'^/login/$', 'logout_view'), + url(r'^/user/(?P\\w+)/$', 'profile_view')) +""" uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index aef6380e8..db378b661 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,51 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB67935450(self): + unformatted_code = """\ +def _(): + return ( + (Gauge( + metric='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + group_by=group_by + ['metric:process_name'], + metric_filter={'metric:process_name': process_name_re}), + Gauge( + metric='bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', + group_by=group_by + ['metric:process_name'], + metric_filter={'metric:process_name': process_name_re})) + | expr.Join( + left_name='start', left_default=0, right_name='end', right_default=0) + | m.Point( + m.Cond(m.VAL['end'] != 0, m.VAL['end'], k.TimestampMicros() / + 1000000L) - m.Cond(m.VAL['start'] != 0, m.VAL['start'], + m.TimestampMicros() / 1000000L))) +""" + expected_formatted_code = """\ +def _(): + return ( + (Gauge( + metric='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + group_by=group_by + ['metric:process_name'], + metric_filter={ + 'metric:process_name': process_name_re + }), + Gauge( + metric='bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', + group_by=group_by + ['metric:process_name'], + metric_filter={ + 'metric:process_name': process_name_re + })) + | expr.Join( + left_name='start', left_default=0, right_name='end', right_default=0) + | m.Point( + m.Cond(m.VAL['end'] != 0, m.VAL['end'], + k.TimestampMicros() / 1000000L) - + m.Cond(m.VAL['start'] != 0, m.VAL['start'], + m.TimestampMicros() / 1000000L))) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB66011084(self): unformatted_code = """\ X = { diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index e57386480..deaf44479 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -61,8 +61,9 @@ def FlattenRec(tree): if pytree_utils.NodeName(tree) in pytree_utils.NONSEMANTIC_TOKENS: return [] if isinstance(tree, pytree.Leaf): - return [(tree.value, pytree_utils.GetNodeAnnotation( - tree, pytree_utils.Annotation.SPLIT_PENALTY))] + return [(tree.value, + pytree_utils.GetNodeAnnotation( + tree, pytree_utils.Annotation.SPLIT_PENALTY))] nodes = [] for node in tree.children: nodes += FlattenRec(node) From cf99a7d07197604b8c8192652a6ad92a47322eaa Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 24 Oct 2017 00:46:11 -0700 Subject: [PATCH 196/719] Use a TextIOWrapper when reading from stdin. Some systems may have different encodings (e.g., CP936 for Windows). In those cases, using "input()" doesn't work if the text isn't ASCII. Using an IO wrapper handles this. Closes #449 --- CHANGELOG | 2 ++ yapf/__init__.py | 2 ++ yapf/yapflib/py3compat.py | 5 ++++- yapftests/yapf_test.py | 21 +++++++++++++++++++-- 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 26122462a..070c45d27 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -17,6 +17,8 @@ comprehension is an argument. - Don't enforce a split before a comment after the opening of a container if it doesn't it on the current line. We try hard not to move such comments around. +- Use a TextIOWrapper when reading from stdin in Python3. This is necessary for + some encodings, like cp936, used on Windows. ## [0.19.0] 2017-10-14 ### Added diff --git a/yapf/__init__.py b/yapf/__init__.py index d80818592..38f947d1d 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -154,6 +154,8 @@ def main(argv): original_source = [] while True: + if sys.stdin.closed: + break try: # Use 'raw_input' instead of 'sys.stdin.read', because otherwise the # user will need to hit 'Ctrl-D' more than once if they're inputting diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py index 2886c384d..a54ddb7b6 100644 --- a/yapf/yapflib/py3compat.py +++ b/yapf/yapflib/py3compat.py @@ -34,7 +34,10 @@ def open_with_encoding(filename, mode, encoding, newline=''): # pylint: disable range = range ifilter = filter - raw_input = input + + def raw_input(): + wrapper = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8') + return wrapper.buffer.raw.readall().decode('utf-8') import configparser diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 490f2d4d4..bfe764de6 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -383,7 +383,11 @@ def setUpClass(cls): def tearDownClass(cls): shutil.rmtree(cls.test_tmpdir) - def assertYapfReformats(self, unformatted, expected, extra_options=None): + def assertYapfReformats(self, + unformatted, + expected, + extra_options=None, + env=None): """Check that yapf reformats the given code as expected. Invokes yapf in a subprocess, piping the unformatted code into its stdin. @@ -393,13 +397,15 @@ def assertYapfReformats(self, unformatted, expected, extra_options=None): unformatted: unformatted code - input to yapf expected: expected formatted code at the output of yapf extra_options: iterable of extra command-line options to pass to yapf + env: dict of environment variables. """ cmdline = YAPF_BINARY + (extra_options or []) p = subprocess.Popen( cmdline, stdout=subprocess.PIPE, stdin=subprocess.PIPE, - stderr=subprocess.PIPE) + stderr=subprocess.PIPE, + env=env) reformatted_code, stderrdata = p.communicate(unformatted.encode('utf-8')) self.assertEqual(stderrdata, b'') self.assertMultiLineEqual(reformatted_code.decode('utf-8'), expected) @@ -1259,6 +1265,17 @@ def testSpacingBeforeCommentsInDicts(self): expected_formatted_code, extra_options=['--style', 'chromium', '--lines', '1-1']) + @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') + def testCP936Encoding(self): + unformatted_code = 'print("äž­æ–‡")\n' + expected_formatted_code = 'print("äž­æ–‡")\n' + self.assertYapfReformats( + unformatted_code, + expected_formatted_code, + env={ + 'PYTHONIOENCODING': 'cp936' + }) + class BadInputTest(unittest.TestCase): """Test yapf's behaviour when passed bad input.""" From da430b90bf3ccb7ffba14807b2585bc26b74497c Mon Sep 17 00:00:00 2001 From: Matthew Suozzo Date: Sun, 29 Oct 2017 18:23:03 -0400 Subject: [PATCH 197/719] Fix split penalty for single-argument function calls with generators. The previous logic retained the normal penalty for splitting before the only argument of a function call when that argument was a generator expression such as 'f(a for a in x)'. This caused formatting irregularities where generators were squeezed towards the end of the line instead of being reflowed onto the next one. This change removes those penalties so that single-argument generators are considered normal function arguments. --- CHANGELOG | 2 ++ yapf/yapflib/split_penalty.py | 9 +++++++-- yapftests/split_penalty_test.py | 17 +++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 070c45d27..34210ef9f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,6 +19,8 @@ doesn't it on the current line. We try hard not to move such comments around. - Use a TextIOWrapper when reading from stdin in Python3. This is necessary for some encodings, like cp936, used on Windows. +- Remove the penalty for a split before the first argument in a function call + where the only argument is a generator expression. ## [0.19.0] 2017-10-14 ### Added diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 55a71345d..8ac078082 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -190,8 +190,13 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name if name in {'argument', 'comparison'}: # Don't split an argument list with one element if at all possible. _SetStronglyConnected(node.children[1]) - _SetSplitPenalty( - _FirstChildNode(node.children[1]), ONE_ELEMENT_ARGUMENT) + if (len(node.children[1].children) > 1 and + pytree_utils.NodeName(node.children[1].children[1]) == 'comp_for'): + # Don't penalize spliting before a comp_for expression. + _SetSplitPenalty(_FirstChildNode(node.children[1]), 0) + else: + _SetSplitPenalty( + _FirstChildNode(node.children[1]), ONE_ELEMENT_ARGUMENT) elif (pytree_utils.NodeName(node.children[0]) == 'LSQB' and len(node.children[1].children) > 2 and (name.endswith('_test') or name.endswith('_expr'))): diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index deaf44479..1c8bf4af9 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -237,6 +237,23 @@ def testFuncCalls(self): (')', VERY_STRONGLY_CONNECTED), ]) + # Test single generator argument. + code = 'max(i for i in xrange(10))\n' + tree = self._ParseAndComputePenalties(code) + self._CheckPenalties(tree, [ + ('max', None), + ('(', UNBREAKABLE), + ('i', 0), + ('for', 0), + ('i', STRONGLY_CONNECTED), + ('in', STRONGLY_CONNECTED), + ('xrange', STRONGLY_CONNECTED), + ('(', UNBREAKABLE), + ('10', STRONGLY_CONNECTED), + (')', VERY_STRONGLY_CONNECTED), + (')', VERY_STRONGLY_CONNECTED), + ]) + if __name__ == '__main__': unittest.main() From ee6fb89f1adb71d97af9a7bef225d0bebc440ef3 Mon Sep 17 00:00:00 2001 From: Matthew Suozzo Date: Sun, 29 Oct 2017 19:36:10 -0400 Subject: [PATCH 198/719] Improve formatting on list/dict/set comprehensions. Terminology reference: [loop_var for loop_var in a_list if loop_var] ^ ^ ^ ^ ^ ^ \-expr-/ \------comp_for------/ \-comp_if-/ Implements the following preferences: - Try to keep comprehensions on a single line. - Prefer splitting at comp_if when comp_for was split as well. - Try to avoid splitting at comp_for when expr exactly matches the loop variable. - This keeps the (often short) clauses together: [a for a in ...]. --- CHANGELOG | 3 + yapf/yapflib/format_decision_state.py | 141 +++++++++++++++++++++++++- yapf/yapflib/format_token.py | 1 + yapf/yapflib/style.py | 6 ++ yapf/yapflib/subtype_assigner.py | 6 ++ yapftests/reformatter_basic_test.py | 60 ++++++++++- yapftests/subtype_assigner_test.py | 10 +- 7 files changed, 219 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 34210ef9f..f956896d8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,9 @@ dictionary that doesn't fit on a single line. - Improve splitting of elements in a tuple. We want to split if there's a function call in the tuple that doesn't fit on the line. +- Improve splitting of comprehensions and generators. Prefer to keep + comprehensions on a single line but if a line-break is required, prefer to + split complex expressions and 'if' clauses onto their own lines. ### Fixed - Enforce spaces between ellipses and keywords. - When calculating the split penalty for a "trailer", process the child nodes diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index de781c264..efeb2d3cb 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -49,6 +49,8 @@ class FormatDecisionState(object): previous: The previous format decision state in the decision tree. stack: A stack (of _ParenState) keeping track of properties applying to parenthesis levels. + comp_stack: A stack (of _ComprehensionState) keeping track of properties + applying to comprehensions. ignore_stack_for_comparison: Ignore the stack of _ParenState for state comparison. """ @@ -71,6 +73,7 @@ def __init__(self, line, first_indent): self.lowest_level_on_line = 0 self.ignore_stack_for_comparison = False self.stack = [_ParenState(first_indent, first_indent)] + self.comp_stack = [] self.first_indent = first_indent self.newline = False self.previous = None @@ -90,6 +93,7 @@ def Clone(self): new.newline = self.newline new.previous = self.previous new.stack = [state.Clone() for state in self.stack] + new.comp_stack = [state.Clone() for state in self.comp_stack] return new def __eq__(self, other): @@ -102,7 +106,8 @@ def __eq__(self, other): self.start_of_line_level == other.start_of_line_level and self.lowest_level_on_line == other.lowest_level_on_line and (self.ignore_stack_for_comparison or - other.ignore_stack_for_comparison or self.stack == other.stack)) + other.ignore_stack_for_comparison or + self.stack == other.stack and self.comp_stack == other.comp_stack)) def __ne__(self, other): return not self == other @@ -498,6 +503,9 @@ def AddTokenToState(self, newline, dry_run, must_split=False): else: self._AddTokenOnCurrentLine(dry_run) + if style.Get('SPLIT_COMPLEX_COMPREHENSIONS'): + penalty += self._CalculateComprehensionState(newline) + return self.MoveStateToNextToken() + penalty def _AddTokenOnCurrentLine(self, dry_run): @@ -637,6 +645,73 @@ def _GetNewlineColumn(self): return top_of_stack.indent + def _CalculateComprehensionState(self, newline): + """Makes required changes to comprehension state. + + Args: + newline: Whether the current token is to be added on a newline. + + Returns: + The penalty for the token-newline combination given the current + comprehension state. + """ + current = self.next_token + previous = current.previous_token + top_of_stack = self.comp_stack[-1] if self.comp_stack else None + penalty = 0 + + if top_of_stack is not None: + # Check if the token terminates the current comprehension. + if current == top_of_stack.closing_bracket: + last = self.comp_stack.pop() + # Lightly penalize comprehensions that are split across multiple lines. + if last.has_interior_split: + penalty += 2 * style.Get('SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT') + 20 + + return penalty + + if newline: + top_of_stack.has_interior_split = True + + if (format_token.Subtype.COMP_EXPR in current.subtypes and + format_token.Subtype.COMP_EXPR not in previous.subtypes): + self.comp_stack.append(_ComprehensionState(current)) + + return penalty + + if (current.value == 'for' and + format_token.Subtype.COMP_FOR in current.subtypes): + if top_of_stack.for_token is not None: + # Treat nested comprehensions like normal comp_if expressions. + # Example: + # my_comp = [ + # a.qux + b.qux + # for a in foo + # --> for b in bar <-- + # if a.zut + b.zut + # ] + if (top_of_stack.has_split_at_for != newline and + (top_of_stack.has_split_at_for or + not top_of_stack.HasTrivialExpr())): + penalty += split_penalty.UNBREAKABLE + else: + top_of_stack.for_token = current + top_of_stack.has_split_at_for = newline + + # Try to keep trivial expressions on the same line as the comp_for. + if newline and top_of_stack.HasTrivialExpr(): + penalty += split_penalty.STRONGLY_CONNECTED + + if (format_token.Subtype.COMP_IF in current.subtypes and + format_token.Subtype.COMP_IF not in previous.subtypes): + # Penalize breaking at comp_if when it doesn't match the newline structure + # in the rest of the comprehension. + if (top_of_stack.has_split_at_for != newline and + (top_of_stack.has_split_at_for or not top_of_stack.HasTrivialExpr())): + penalty += split_penalty.UNBREAKABLE + + return penalty + def MoveStateToNextToken(self): """Calculate format decision state information and move onto the next token. @@ -915,3 +990,67 @@ def __ne__(self, other): def __hash__(self, *args, **kwargs): return hash((self.indent, self.last_space, self.closing_scope_indent, self.split_before_closing_bracket, self.num_line_splits)) + + +class _ComprehensionState(object): + """Maintains the state of list comprehension line-break decisions. + + A stack of _ComprehensionState objects are kept to ensure that list + comprehensions are wrapped with well-defined rules. + + Attributes: + expr_token: The first token in the comprehension. + for_token: The first 'for' token of the comprehension. + has_split_at_for: Whether there is a newline immediately before the + for_token. + has_interior_split: Whether there is a newline within the comprehension. + That is, a split somewhere after expr_token or before closing_bracket. + """ + + def __init__(self, expr_token): + self.expr_token = expr_token + self.for_token = None + self.has_split_at_for = False + self.has_interior_split = False + + def HasTrivialExpr(self): + """Returns whether the comp_expr is identical to the first loop variable. + + Example: [a for a in my_list] + """ + # First verify that the comp_expr is one token long, then check that it + # exactly matches the first loop variable. + return ( + self.expr_token.next_token.value == 'for' and + self.expr_token.value == self.expr_token.next_token.next_token.value) + + @property + def opening_bracket(self): + return self.expr_token.previous_token + + @property + def closing_bracket(self): + return self.opening_bracket.matching_bracket + + def Clone(self): + clone = _ComprehensionState(self.expr_token) + clone.for_token = self.for_token + clone.has_split_at_for = self.has_split_at_for + clone.has_interior_split = self.has_interior_split + return clone + + def __repr__(self): + return ('[opening_bracket::%s, for_token::%s, has_split_at_for::%s,' + ' has_interior_split::%s, has_trivial_expr::%s]' % + (self.opening_bracket, self.for_token, self.has_split_at_for, + self.has_interior_split, self.HasTrivialExpr())) + + def __eq__(self, other): + return hash(self) == hash(other) + + def __ne__(self, other): + return not self == other + + def __hash__(self, *args, **kwargs): + return hash((self.expr_token, self.for_token, self.has_split_at_for, + self.has_interior_split)) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 88952762f..85af6212d 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -49,6 +49,7 @@ class Subtype(object): DICTIONARY_KEY_PART = 12 DICTIONARY_VALUE = 13 DICT_SET_GENERATOR = 14 + COMP_EXPR = 21 COMP_FOR = 15 COMP_IF = 16 FUNC_DEF = 17 diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 8f30ab034..79a5f8529 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -178,6 +178,9 @@ def method(): after."""), SPLIT_BEFORE_NAMED_ASSIGNS=textwrap.dedent("""\ Split named assignments onto individual lines."""), + SPLIT_COMPLEX_COMPREHENSIONS=textwrap.dedent("""\ + Set to True to prefer splitting list comprehensions and generators + when they have non-trivial expressions and/or filter clauses."""), SPLIT_PENALTY_AFTER_OPENING_BRACKET=textwrap.dedent("""\ The penalty for splitting right after the opening bracket."""), SPLIT_PENALTY_AFTER_UNARY_OPERATOR=textwrap.dedent("""\ @@ -243,6 +246,7 @@ def CreatePEP8Style(): SPLIT_BEFORE_FIRST_ARGUMENT=False, SPLIT_BEFORE_LOGICAL_OPERATOR=True, SPLIT_BEFORE_NAMED_ASSIGNS=True, + SPLIT_COMPLEX_COMPREHENSIONS=False, SPLIT_PENALTY_AFTER_OPENING_BRACKET=30, SPLIT_PENALTY_AFTER_UNARY_OPERATOR=10000, SPLIT_PENALTY_BEFORE_IF_EXPR=0, @@ -266,6 +270,7 @@ def CreateGoogleStyle(): style['SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET'] = False style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False style['SPLIT_BEFORE_BITWISE_OPERATOR'] = False + style['SPLIT_COMPLEX_COMPREHENSIONS'] = True return style @@ -368,6 +373,7 @@ def _BoolConverter(s): SPLIT_BEFORE_FIRST_ARGUMENT=_BoolConverter, SPLIT_BEFORE_LOGICAL_OPERATOR=_BoolConverter, SPLIT_BEFORE_NAMED_ASSIGNS=_BoolConverter, + SPLIT_COMPLEX_COMPREHENSIONS=_BoolConverter, SPLIT_PENALTY_AFTER_OPENING_BRACKET=int, SPLIT_PENALTY_AFTER_UNARY_OPERATOR=int, SPLIT_PENALTY_BEFORE_IF_EXPR=int, diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 213ce3131..f24dbbc5e 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -304,6 +304,12 @@ def Visit_varargslist(self, node): # pylint: disable=invalid-name def Visit_comp_for(self, node): # pylint: disable=invalid-name # comp_for ::= 'for' exprlist 'in' testlist_safe [comp_iter] _AppendSubtypeRec(node, format_token.Subtype.COMP_FOR) + # Mark the previous node as COMP_EXPR unless this is a nested comprehension + # as these will have the outer comprehension as their previous node. + attr = pytree_utils.GetNodeAnnotation(node.parent, + pytree_utils.Annotation.SUBTYPE) + if not attr or format_token.Subtype.COMP_FOR not in attr: + _AppendSubtypeRec(node.parent.children[0], format_token.Subtype.COMP_EXPR) self.DefaultNodeVisit(node) def Visit_comp_if(self, node): # pylint: disable=invalid-name diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index cef399a36..2dfa84b1f 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -457,6 +457,60 @@ def given(y): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testListComprehensionPreferOneLine(self): + unformatted_code = textwrap.dedent("""\ + def given(y): + long_variable_name = [ + long_var_name + 1 + for long_var_name in () + if long_var_name == 2] + """) + expected_formatted_code = textwrap.dedent("""\ + def given(y): + long_variable_name = [ + long_var_name + 1 for long_var_name in () if long_var_name == 2 + ] + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testListComprehensionPreferThreeLinesForLineWrap(self): + unformatted_code = textwrap.dedent("""\ + def given(y): + long_variable_name = [ + long_var_name + 1 + for long_var_name, number_two in () + if long_var_name == 2 and number_two == 3] + """) + expected_formatted_code = textwrap.dedent("""\ + def given(y): + long_variable_name = [ + long_var_name + 1 + for long_var_name, number_two in () + if long_var_name == 2 and number_two == 3 + ] + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testListComprehensionPreferNoBreakForTrivialExpression(self): + unformatted_code = textwrap.dedent("""\ + def given(y): + long_variable_name = [ + long_var_name + for long_var_name, number_two in () + if long_var_name == 2 and number_two == 3] + """) + expected_formatted_code = textwrap.dedent("""\ + def given(y): + long_variable_name = [ + long_var_name for long_var_name, number_two in () + if long_var_name == 2 and number_two == 3 + ] + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testOpeningAndClosingBrackets(self): unformatted_code = """\ foo( (1, ) ) @@ -887,7 +941,8 @@ def f(): if True: if True: python_files.extend( - os.path.join(filename, f) for f in os.listdir(filename) + os.path.join(filename, f) + for f in os.listdir(filename) if IsPythonFile(os.path.join(filename, f))) """) uwlines = yapf_test_helper.ParseAndUnwrap(code) @@ -1221,7 +1276,8 @@ def testDictSetGenerator(self): code = textwrap.dedent("""\ foo = { variable: 'hello world. How are you today?' - for variable in fnord if variable != 37 + for variable in fnord + if variable != 37 } """) uwlines = yapf_test_helper.ParseAndUnwrap(code) diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index 766e8decb..746b8c813 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -111,11 +111,11 @@ def foo(strs): (':', [format_token.Subtype.NONE])], [('return', [format_token.Subtype.NONE]), ('{', [format_token.Subtype.NONE]), - ('s', [format_token.Subtype.NONE]), - ('.', [format_token.Subtype.NONE]), - ('lower', [format_token.Subtype.NONE]), - ('(', [format_token.Subtype.NONE]), - (')', [format_token.Subtype.NONE]), + ('s', {format_token.Subtype.COMP_EXPR}), + ('.', {format_token.Subtype.COMP_EXPR}), + ('lower', {format_token.Subtype.COMP_EXPR}), + ('(', {format_token.Subtype.COMP_EXPR}), + (')', {format_token.Subtype.COMP_EXPR}), ('for', {format_token.Subtype.DICT_SET_GENERATOR, format_token.Subtype.COMP_FOR}), ('s', {format_token.Subtype.COMP_FOR}), From e88568e32f5ecb893f8f9aee11f65e646f40635f Mon Sep 17 00:00:00 2001 From: Matthew Suozzo Date: Tue, 31 Oct 2017 00:33:38 -0400 Subject: [PATCH 199/719] Ran YAPF on YAPF. --- yapf/yapflib/file_resources.py | 3 ++- yapf/yapflib/pytree_unwrapper.py | 3 ++- yapftests/pytree_unwrapper_test.py | 6 ++++-- yapftests/subtype_assigner_test.py | 3 ++- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 021764ef4..063161b48 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -121,7 +121,8 @@ def _FindPythonFiles(filenames, recursive, exclude): # TODO(morbo): Look into a version of os.walk that can handle recursion. python_files.extend( os.path.join(dirpath, f) - for dirpath, _, filelist in os.walk(filename) for f in filelist + for dirpath, _, filelist in os.walk(filename) + for f in filelist if IsPythonFile(os.path.join(dirpath, f))) else: raise errors.YapfError( diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index 31df6b90f..68248ab48 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -333,7 +333,8 @@ def _DetermineMustSplitAnnotation(node): if not _ContainsComments(node): token = next(node.parent.leaves()) if token.value == '(': - if sum(1 for ch in node.children + if sum(1 + for ch in node.children if pytree_utils.NodeName(ch) == 'COMMA') < 2: return if (not isinstance(node.children[-1], pytree.Leaf) or diff --git a/yapftests/pytree_unwrapper_test.py b/yapftests/pytree_unwrapper_test.py index ab634a57e..03a93f003 100644 --- a/yapftests/pytree_unwrapper_test.py +++ b/yapftests/pytree_unwrapper_test.py @@ -34,7 +34,8 @@ def _CheckUnwrappedLines(self, uwlines, list_of_expected): actual = [] for uwl in uwlines: filtered_values = [ - ft.value for ft in uwl.tokens + ft.value + for ft in uwl.tokens if ft.name not in pytree_utils.NONSEMANTIC_TOKENS ] actual.append((uwl.depth, filtered_values)) @@ -299,7 +300,8 @@ def _CheckMatchingBrackets(self, uwlines, list_of_expected): """ actual = [] for uwl in uwlines: - filtered_values = [(ft, ft.matching_bracket) for ft in uwl.tokens + filtered_values = [(ft, ft.matching_bracket) + for ft in uwl.tokens if ft.name not in pytree_utils.NONSEMANTIC_TOKENS] if filtered_values: actual.append(filtered_values) diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index 746b8c813..9dd1050fd 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -34,7 +34,8 @@ def _CheckFormatTokenSubtypes(self, uwlines, list_of_expected): """ actual = [] for uwl in uwlines: - filtered_values = [(ft.value, ft.subtypes) for ft in uwl.tokens + filtered_values = [(ft.value, ft.subtypes) + for ft in uwl.tokens if ft.name not in pytree_utils.NONSEMANTIC_TOKENS] if filtered_values: actual.append(filtered_values) From 4f906d244754f0a1000d152a8b56f76ed7b8245c Mon Sep 17 00:00:00 2001 From: Matthew Suozzo Date: Tue, 31 Oct 2017 00:54:45 -0400 Subject: [PATCH 200/719] Reduce the penalty for spltiting a trivial expr. STRONGLY_CONNECTED resulted in a few unfortunate biases like the toy example below: x = [ var for var in sorted( looooooooooooooooooong) if var ] versus the preferable: x = [ var for var in sorted(looooooooooooooooooong) if var ] --- yapf/yapflib/format_decision_state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index efeb2d3cb..afb5e0e11 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -700,7 +700,7 @@ def _CalculateComprehensionState(self, newline): # Try to keep trivial expressions on the same line as the comp_for. if newline and top_of_stack.HasTrivialExpr(): - penalty += split_penalty.STRONGLY_CONNECTED + penalty += split_penalty.CONNECTED if (format_token.Subtype.COMP_IF in current.subtypes and format_token.Subtype.COMP_IF not in previous.subtypes): From ae65b541caa4443305d412defe0596cb1b868e16 Mon Sep 17 00:00:00 2001 From: Matthew Suozzo Date: Wed, 1 Nov 2017 17:26:47 -0400 Subject: [PATCH 201/719] Redefine expr 'triviality' as being a single token. The previous definition of "exactly matching the loop var" was unsightly for short expressions such as: length = sum(1 for var_name in gen if var_name) --- yapf/yapflib/format_decision_state.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index afb5e0e11..80728e6e0 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -1014,15 +1014,8 @@ def __init__(self, expr_token): self.has_interior_split = False def HasTrivialExpr(self): - """Returns whether the comp_expr is identical to the first loop variable. - - Example: [a for a in my_list] - """ - # First verify that the comp_expr is one token long, then check that it - # exactly matches the first loop variable. - return ( - self.expr_token.next_token.value == 'for' and - self.expr_token.value == self.expr_token.next_token.next_token.value) + """Returns whether the comp_expr is "trivial" i.e. is a single token.""" + return self.expr_token.next_token.value == 'for' @property def opening_bracket(self): From 6154b4db3eda6e1bedebda14c7b2c49e3815de62 Mon Sep 17 00:00:00 2001 From: Matthew Suozzo Date: Wed, 1 Nov 2017 17:38:37 -0400 Subject: [PATCH 202/719] Update docs for SPLIT_COMPLEX_COMPREHENSION. --- README.rst | 21 +++++++++++++++++++++ yapf/yapflib/style.py | 25 +++++++++++++++++++------ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index ae2bc74c9..8e155fd8f 100644 --- a/README.rst +++ b/README.rst @@ -461,6 +461,27 @@ Knobs ``SPLIT_BEFORE_NAMED_ASSIGNS`` Split named assignments onto individual lines. +``SPLIT_COMPLEX_COMPREHENSION`` + For list comprehensions and generator expressions with multiple clauses + (e.g mutiple "for" calls, "if" filter expressions) and which need to be + reflowed, split each clause onto its own line. For example: + + .. code-block:: python + + result = [ + a_var + b_var for a_var in xrange(1000) for b_var in xrange(1000) + if a_var % b_var] + + would reformat to something like: + + .. code-block:: python + + result = [ + a_var + b_var + for a_var in xrange(1000) + for b_var in xrange(1000) + if a_var % b_var] + ``SPLIT_PENALTY_AFTER_OPENING_BRACKET`` The penalty for splitting right after the opening bracket. diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 79a5f8529..9a03d040e 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -178,9 +178,22 @@ def method(): after."""), SPLIT_BEFORE_NAMED_ASSIGNS=textwrap.dedent("""\ Split named assignments onto individual lines."""), - SPLIT_COMPLEX_COMPREHENSIONS=textwrap.dedent("""\ - Set to True to prefer splitting list comprehensions and generators - when they have non-trivial expressions and/or filter clauses."""), + SPLIT_COMPLEX_COMPREHENSION=textwrap.dedent("""\ + Set to True to split list comprehensions and generators that have + non-trivial expressions and multiple clauses before each of these + clauses. For example: + + result = [ + a_long_var + 100 for a_long_var in xrange(1000) + if a_long_var % 10] + + would reformat to something like: + + result = [ + a_long_var + 100 + for a_long_var in xrange(1000) + if a_long_var % 10] + """), SPLIT_PENALTY_AFTER_OPENING_BRACKET=textwrap.dedent("""\ The penalty for splitting right after the opening bracket."""), SPLIT_PENALTY_AFTER_UNARY_OPERATOR=textwrap.dedent("""\ @@ -246,7 +259,7 @@ def CreatePEP8Style(): SPLIT_BEFORE_FIRST_ARGUMENT=False, SPLIT_BEFORE_LOGICAL_OPERATOR=True, SPLIT_BEFORE_NAMED_ASSIGNS=True, - SPLIT_COMPLEX_COMPREHENSIONS=False, + SPLIT_COMPLEX_COMPREHENSION=False, SPLIT_PENALTY_AFTER_OPENING_BRACKET=30, SPLIT_PENALTY_AFTER_UNARY_OPERATOR=10000, SPLIT_PENALTY_BEFORE_IF_EXPR=0, @@ -270,7 +283,7 @@ def CreateGoogleStyle(): style['SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET'] = False style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False style['SPLIT_BEFORE_BITWISE_OPERATOR'] = False - style['SPLIT_COMPLEX_COMPREHENSIONS'] = True + style['SPLIT_COMPLEX_COMPREHENSION'] = True return style @@ -373,7 +386,7 @@ def _BoolConverter(s): SPLIT_BEFORE_FIRST_ARGUMENT=_BoolConverter, SPLIT_BEFORE_LOGICAL_OPERATOR=_BoolConverter, SPLIT_BEFORE_NAMED_ASSIGNS=_BoolConverter, - SPLIT_COMPLEX_COMPREHENSIONS=_BoolConverter, + SPLIT_COMPLEX_COMPREHENSION=_BoolConverter, SPLIT_PENALTY_AFTER_OPENING_BRACKET=int, SPLIT_PENALTY_AFTER_UNARY_OPERATOR=int, SPLIT_PENALTY_BEFORE_IF_EXPR=int, From 0f8567a662ed4bcf4a7e894f65279bfb8a04e071 Mon Sep 17 00:00:00 2001 From: Matthew Suozzo Date: Wed, 1 Nov 2017 17:40:57 -0400 Subject: [PATCH 203/719] Add `SPLIT_PENALTY_COMPREHENSION` flag. Also: Remove the coarse flag on the comprehension state calculation and make the flags determine whether/which penalties are added. I've set the new flag's value to 2100 for Google as that seems to be a pretty strong bias towards keeping everything on the same line (but not too strong that it upsets common cases). 80 might be too high for PEP8 but I think 0 penalty results in some pretty lousy formatting. --- README.rst | 3 +++ yapf/yapflib/format_decision_state.py | 14 ++++++++------ yapf/yapflib/style.py | 6 ++++++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 8e155fd8f..96a648d48 100644 --- a/README.rst +++ b/README.rst @@ -495,6 +495,9 @@ Knobs The penalty of splitting the line around the ``&``, ``|``, and ``^`` operators. +``SPLIT_PENALTY_COMPREHENSION`` + The penalty for splitting a list comprehension or generator expression. + ``SPLIT_PENALTY_EXCESS_CHARACTER`` The penalty for characters over the column limit. diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 80728e6e0..e9ae54f97 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -503,8 +503,7 @@ def AddTokenToState(self, newline, dry_run, must_split=False): else: self._AddTokenOnCurrentLine(dry_run) - if style.Get('SPLIT_COMPLEX_COMPREHENSIONS'): - penalty += self._CalculateComprehensionState(newline) + penalty += self._CalculateComprehensionState(newline) return self.MoveStateToNextToken() + penalty @@ -666,7 +665,7 @@ def _CalculateComprehensionState(self, newline): last = self.comp_stack.pop() # Lightly penalize comprehensions that are split across multiple lines. if last.has_interior_split: - penalty += 2 * style.Get('SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT') + 20 + penalty += style.Get('SPLIT_PENALTY_COMPREHENSION') return penalty @@ -690,7 +689,8 @@ def _CalculateComprehensionState(self, newline): # --> for b in bar <-- # if a.zut + b.zut # ] - if (top_of_stack.has_split_at_for != newline and + if (style.Get('SPLIT_COMPLEX_COMPREHENSIONS') and + top_of_stack.has_split_at_for != newline and (top_of_stack.has_split_at_for or not top_of_stack.HasTrivialExpr())): penalty += split_penalty.UNBREAKABLE @@ -699,14 +699,16 @@ def _CalculateComprehensionState(self, newline): top_of_stack.has_split_at_for = newline # Try to keep trivial expressions on the same line as the comp_for. - if newline and top_of_stack.HasTrivialExpr(): + if (style.Get('SPLIT_COMPLEX_COMPREHENSIONS') and + newline and top_of_stack.HasTrivialExpr()): penalty += split_penalty.CONNECTED if (format_token.Subtype.COMP_IF in current.subtypes and format_token.Subtype.COMP_IF not in previous.subtypes): # Penalize breaking at comp_if when it doesn't match the newline structure # in the rest of the comprehension. - if (top_of_stack.has_split_at_for != newline and + if (style.Get('SPLIT_COMPLEX_COMPREHENSIONS') and + top_of_stack.has_split_at_for != newline and (top_of_stack.has_split_at_for or not top_of_stack.HasTrivialExpr())): penalty += split_penalty.UNBREAKABLE diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 9a03d040e..948c2fd38 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -203,6 +203,9 @@ def method(): SPLIT_PENALTY_BITWISE_OPERATOR=textwrap.dedent("""\ The penalty of splitting the line around the '&', '|', and '^' operators."""), + SPLIT_PENALTY_COMPREHENSION=textwrap.dedent("""\ + The penalty for splitting a list comprehension or generator + expression."""), SPLIT_PENALTY_EXCESS_CHARACTER=textwrap.dedent("""\ The penalty for characters over the column limit."""), SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=textwrap.dedent("""\ @@ -264,6 +267,7 @@ def CreatePEP8Style(): SPLIT_PENALTY_AFTER_UNARY_OPERATOR=10000, SPLIT_PENALTY_BEFORE_IF_EXPR=0, SPLIT_PENALTY_BITWISE_OPERATOR=300, + SPLIT_PENALTY_COMPREHENSION=80, SPLIT_PENALTY_EXCESS_CHARACTER=4500, SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=30, SPLIT_PENALTY_IMPORT_NAMES=0, @@ -284,6 +288,7 @@ def CreateGoogleStyle(): style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False style['SPLIT_BEFORE_BITWISE_OPERATOR'] = False style['SPLIT_COMPLEX_COMPREHENSION'] = True + style['SPLIT_PENALTY_COMPREHENSION'] = 2100 return style @@ -391,6 +396,7 @@ def _BoolConverter(s): SPLIT_PENALTY_AFTER_UNARY_OPERATOR=int, SPLIT_PENALTY_BEFORE_IF_EXPR=int, SPLIT_PENALTY_BITWISE_OPERATOR=int, + SPLIT_PENALTY_COMPREHENSION=int, SPLIT_PENALTY_EXCESS_CHARACTER=int, SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=int, SPLIT_PENALTY_IMPORT_NAMES=int, From 808767d208f0971218332b9437d1fd933006b6cb Mon Sep 17 00:00:00 2001 From: Matthew Suozzo Date: Wed, 1 Nov 2017 17:52:28 -0400 Subject: [PATCH 204/719] Updated CHANGELOG --- CHANGELOG | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f956896d8..fa127c85f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,11 @@ # This project adheres to [Semantic Versioning](http://semver.org/). ## [0.19.1] UNRELEASED +### Added +- Improve splitting of comprehensions and generators. Add + `SPLIT_PENALTY_COMPREHENSION` knob to control preference for keeping + comprehensions on a single line and `SPLIT_COMPLEX_COMPREHENSION` to enable + splitting each clause of complex comprehensions onto its own line. ### Changed - Take into account a named function argument when determining if we should split before the first argument in a function call. @@ -10,9 +15,6 @@ dictionary that doesn't fit on a single line. - Improve splitting of elements in a tuple. We want to split if there's a function call in the tuple that doesn't fit on the line. -- Improve splitting of comprehensions and generators. Prefer to keep - comprehensions on a single line but if a line-break is required, prefer to - split complex expressions and 'if' clauses onto their own lines. ### Fixed - Enforce spaces between ellipses and keywords. - When calculating the split penalty for a "trailer", process the child nodes From cc7823a41dea17677050bea3758f53a6b5090670 Mon Sep 17 00:00:00 2001 From: Matthew Suozzo Date: Wed, 1 Nov 2017 17:55:56 -0400 Subject: [PATCH 205/719] Fix typos in style flag names. --- yapf/yapflib/format_decision_state.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index e9ae54f97..616234a67 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -689,7 +689,7 @@ def _CalculateComprehensionState(self, newline): # --> for b in bar <-- # if a.zut + b.zut # ] - if (style.Get('SPLIT_COMPLEX_COMPREHENSIONS') and + if (style.Get('SPLIT_COMPLEX_COMPREHENSION') and top_of_stack.has_split_at_for != newline and (top_of_stack.has_split_at_for or not top_of_stack.HasTrivialExpr())): @@ -699,7 +699,7 @@ def _CalculateComprehensionState(self, newline): top_of_stack.has_split_at_for = newline # Try to keep trivial expressions on the same line as the comp_for. - if (style.Get('SPLIT_COMPLEX_COMPREHENSIONS') and + if (style.Get('SPLIT_COMPLEX_COMPREHENSION') and newline and top_of_stack.HasTrivialExpr()): penalty += split_penalty.CONNECTED @@ -707,7 +707,7 @@ def _CalculateComprehensionState(self, newline): format_token.Subtype.COMP_IF not in previous.subtypes): # Penalize breaking at comp_if when it doesn't match the newline structure # in the rest of the comprehension. - if (style.Get('SPLIT_COMPLEX_COMPREHENSIONS') and + if (style.Get('SPLIT_COMPLEX_COMPREHENSION') and top_of_stack.has_split_at_for != newline and (top_of_stack.has_split_at_for or not top_of_stack.HasTrivialExpr())): penalty += split_penalty.UNBREAKABLE From 0b2c3ef4c2cd4c07e7f218bf3c00dfbfb451d5e5 Mon Sep 17 00:00:00 2001 From: Matthew Suozzo Date: Wed, 1 Nov 2017 17:56:43 -0400 Subject: [PATCH 206/719] Ran YAPF on YAPF. --- yapf/yapflib/format_decision_state.py | 4 ++-- yapf/yapflib/pytree_unwrapper.py | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 616234a67..8d18c5446 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -699,8 +699,8 @@ def _CalculateComprehensionState(self, newline): top_of_stack.has_split_at_for = newline # Try to keep trivial expressions on the same line as the comp_for. - if (style.Get('SPLIT_COMPLEX_COMPREHENSION') and - newline and top_of_stack.HasTrivialExpr()): + if (style.Get('SPLIT_COMPLEX_COMPREHENSION') and newline and + top_of_stack.HasTrivialExpr()): penalty += split_penalty.CONNECTED if (format_token.Subtype.COMP_IF in current.subtypes and diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index 68248ab48..31df6b90f 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -333,8 +333,7 @@ def _DetermineMustSplitAnnotation(node): if not _ContainsComments(node): token = next(node.parent.leaves()) if token.value == '(': - if sum(1 - for ch in node.children + if sum(1 for ch in node.children if pytree_utils.NodeName(ch) == 'COMMA') < 2: return if (not isinstance(node.children[-1], pytree.Leaf) or From 4bb7c4c1b07c25fe7d11eb544816d61be5745013 Mon Sep 17 00:00:00 2001 From: Matthew Suozzo Date: Wed, 1 Nov 2017 22:42:27 -0400 Subject: [PATCH 207/719] Fix tests and add a new one. --- yapftests/reformatter_basic_test.py | 18 ++++++++++++++++-- yapftests/reformatter_buganizer_test.py | 4 ++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 2dfa84b1f..aa237e147 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -474,6 +474,20 @@ def given(y): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testListComprehensionPreferOneLineOverArithmeticSplit(self): + unformatted_code = textwrap.dedent("""\ + def given(used_identifiers): + return (sum(len(identifier) + for identifier in used_identifiers) / len(used_identifiers)) + """) + expected_formatted_code = textwrap.dedent("""\ + def given(used_identifiers): + return (sum(len(identifier) for identifier in used_identifiers) / + len(used_identifiers)) + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testListComprehensionPreferThreeLinesForLineWrap(self): unformatted_code = textwrap.dedent("""\ def given(y): @@ -548,8 +562,8 @@ def testNoQueueSeletionInMiddleOfLine(self): find_symbol(node.type) + "< " + " ".join(find_pattern(n) for n in node.child) + " >" """ expected_formatted_code = """\ -find_symbol(node.type) + "< " + " ".join(find_pattern(n) - for n in node.child) + " >" +find_symbol(node.type) + "< " + " ".join( + find_pattern(n) for n in node.child) + " >" """ uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index db378b661..ae9be4772 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -279,8 +279,8 @@ def testB65241516(self): def testB37460004(self): code = textwrap.dedent("""\ - assert all(s not in (_SENTINEL, None) for s in - nested_schemas), 'Nested schemas should never contain None/_SENTINEL' + assert all(s not in (_SENTINEL, None) for s in nested_schemas + ), 'Nested schemas should never contain None/_SENTINEL' """) uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) From c9a62b63e761da84ac45235c41b125cc754365a9 Mon Sep 17 00:00:00 2001 From: mlimber Date: Thu, 9 Nov 2017 13:53:22 -0500 Subject: [PATCH 208/719] Grammatical tweak --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 96a648d48..8102e3f2e 100644 --- a/README.rst +++ b/README.rst @@ -537,7 +537,7 @@ YAPF tries very hard to get the formatting correct. But for some code, it won't be as good as hand-formatting. In particular, large data literals may become horribly disfigured under YAPF. -The reason for this is many-fold. But in essence YAPF is simply a tool to help +The reasons for this are manyfold. In short, YAPF is simply a tool to help with development. It will format things to coincide with the style guide, but that may not equate with readability. From 3eb5bc03e3042a08c66ab890eacabed70ec708c2 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 14 Nov 2017 23:45:50 -0800 Subject: [PATCH 209/719] Bump version to v0.20.0 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index fa127c85f..be1ffb147 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.19.1] UNRELEASED +## [0.20.0] 2017-11-14 ### Added - Improve splitting of comprehensions and generators. Add `SPLIT_PENALTY_COMPREHENSION` knob to control preference for keeping diff --git a/yapf/__init__.py b/yapf/__init__.py index 38f947d1d..ea41a0dce 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.19.0' +__version__ = '0.20.0' def main(argv): From 659a0eadaacefe1798f3c9371ea2bfc9c795be76 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 18 Nov 2017 16:07:39 -0800 Subject: [PATCH 210/719] Default 'verify' to False. --- yapf/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index ea41a0dce..7a0f17673 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -203,7 +203,7 @@ def FormatFiles(filenames, no_local_style=False, in_place=False, print_diff=False, - verify=True, + verify=False, parallel=False, verbose=False): """Format a list of files. @@ -253,7 +253,7 @@ def _FormatFile(filename, no_local_style=False, in_place=False, print_diff=False, - verify=True, + verify=False, verbose=False): if verbose: print('Reformatting %s' % filename) From 18d7878fc7cc1becf41d285b460d188db41fc287 Mon Sep 17 00:00:00 2001 From: Tommy Lutz Date: Thu, 23 Nov 2017 19:20:29 -0500 Subject: [PATCH 211/719] Update vim plugin instructions. --- plugins/README.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/README.rst b/plugins/README.rst index 550aa5dc7..4bcad86ba 100644 --- a/plugins/README.rst +++ b/plugins/README.rst @@ -54,7 +54,8 @@ directory: .. code-block:: bash # From the root of your git project. - curl -o https://raw.githubusercontent.com/google/yapf/master/plugins/pre-commit.sh + curl -o pre-commit.sh https://raw.githubusercontent.com/google/yapf/master/plugins/pre-commit.sh + chmod a+x pre-commit.sh mv pre-commit.sh .git/hooks/pre-commit ========== From 4b4f5b51c52b6108bbf9ff6e278fdf687f047cad Mon Sep 17 00:00:00 2001 From: Piotr Gabryjeluk Date: Wed, 6 Dec 2017 11:07:41 -0800 Subject: [PATCH 212/719] Flip INDENT_DICTIONARY_VALUE for Facebook style With INDENT_DICTIONARY_VALUE=False the dictionaries with long values are formatted in a very bad way `cat test.py` conf = { 'first_key': True, 'second_key': [], 'third_key': 'Beautiful is better than ugly.' 'Explicit is better than implicit.' 'Simple is better than complex.' 'Complex is better than complicated.' } `cat style.yapf` [style] BASED_ON_STYLE=pep8 `yapf test.py` conf = { 'first_key': True, 'second_key': [], 'third_key': 'Beautiful is better than ugly.' 'Explicit is better than implicit.' 'Simple is better than complex.' 'Complex is better than complicated.' } Notice how the first key/value pair is split into two lines, while the second key/value pair is not. While it's somewhat understandable the way the third key/value pair is treated, there's no sensible way to explain the splitting the first key/value pair. Now when you flip INDENT_DICTIONARY_VALUE: `cat style.yapf` [style] BASED_ON_STYLE=pep8 INDENT_DICTIONARY_VALUE=True `yapf test.py` conf = { 'first_key': True, 'second_key': [], 'third_key': 'Beautiful is better than ugly.' 'Explicit is better than implicit.' 'Simple is better than complex.' 'Complex is better than complicated.' } Much better isn't it? --- yapf/yapflib/style.py | 1 + 1 file changed, 1 insertion(+) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 948c2fd38..5451f8c20 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -308,6 +308,7 @@ def CreateFacebookStyle(): style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False style['COLUMN_LIMIT'] = 80 style['DEDENT_CLOSING_BRACKETS'] = True + style['INDENT_DICTIONARY_VALUE'] = True style['JOIN_MULTIPLE_LINES'] = False style['SPACES_BEFORE_COMMENT'] = 2 style['SPLIT_PENALTY_AFTER_OPENING_BRACKET'] = 0 From 965bbdb27206004adf5abd66420eb7f5577892e9 Mon Sep 17 00:00:00 2001 From: "Nathaniel J. Smith" Date: Sat, 9 Dec 2017 19:59:07 -0800 Subject: [PATCH 213/719] Fix checking for 'async def' The old code was comparing a generator object against a tuple, which will never be true. Also it was using token.name, instead of token.value, for some reason. Fixes #484 --- yapf/yapflib/reformatter.py | 2 +- yapftests/reformatter_python3_test.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 7ed7a6230..299fef8db 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -439,7 +439,7 @@ def _IsClassOrDef(uwline): if uwline.first.value in {'class', 'def'}: return True - return (t.name for t in uwline.tokens[:2]) == ('async', 'def') + return [t.value for t in uwline.tokens[:2]] == ['async', 'def'] def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index c6a3e99dd..6ed1bbbaf 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -209,6 +209,17 @@ async def foo(): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testAsyncFunctionsNested(self): + if sys.version_info[1] < 5: + return + code = textwrap.dedent("""\ + async def outer(): + async def inner(): + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testKeepTypesIntact(self): if sys.version_info[1] < 5: return From 5b44429bcf1493e2007d24ec557611ab31e18944 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 17 Dec 2017 23:58:02 -0800 Subject: [PATCH 214/719] Don't add space between None and a dot. Closes #487 --- CHANGELOG | 4 ++++ yapf/yapflib/unwrapped_line.py | 2 +- yapftests/reformatter_python3_test.py | 7 +++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index be1ffb147..e190fa650 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.20.1] UNRELEASED +### Fixed +- Don't treat 'None' as a keyword if calling a function on it, like '__ne__()'. + ## [0.20.0] 2017-11-14 ### Added - Improve splitting of comprehensions and generators. Add diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 21a4cc7fb..781f6f3c6 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -317,7 +317,7 @@ def _SpaceRequiredBetween(left, right): return False if left.is_keyword and rval == '.' or lval == '.' and right.is_keyword: # Add space between keywords and dots. - return True + return lval != 'None' if lval == '.' or rval == '.': # Don't place spaces between dots. return False diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index c6a3e99dd..f9ce8572e 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -181,6 +181,13 @@ def testMatrixMultiplication(self): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testNoneKeyword(self): + code = """\ +None.__ne__() +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testAsyncWithPrecedingComment(self): if sys.version_info[1] < 5: return From 1403afcbcb2fbccbea6232531b824f44eb6fb7d5 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 19 Dec 2017 13:43:45 -0800 Subject: [PATCH 215/719] Remove deadcode handled by the comprehension state --- yapf/yapflib/format_decision_state.py | 17 -------- yapftests/reformatter_buganizer_test.py | 54 ++++++++----------------- 2 files changed, 17 insertions(+), 54 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 8d18c5446..2737951d0 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -446,23 +446,6 @@ def SurroundedByParens(token): if not self._FitsOnLine(previous, previous.matching_bracket): return True - ########################################################################### - # List Comprehension Splitting - if (format_token.Subtype.COMP_FOR in current.subtypes and - format_token.Subtype.COMP_FOR not in previous.subtypes): - # Split at the beginning of a list comprehension. - length = _GetLengthOfSubtype(current, format_token.Subtype.COMP_FOR, - format_token.Subtype.COMP_IF) - if length + self.column > self.column_limit: - return True - - if (format_token.Subtype.COMP_IF in current.subtypes and - format_token.Subtype.COMP_IF not in previous.subtypes): - # Split at the beginning of an if expression. - length = _GetLengthOfSubtype(current, format_token.Subtype.COMP_IF) - if length + self.column > self.column_limit: - return True - ########################################################################### # Original Formatting Splitting # These checks rely upon the original formatting. This is in order to diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index ae9be4772..eda0fbe8f 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -286,43 +286,23 @@ def testB37460004(self): self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB36806207(self): - unformatted_code = textwrap.dedent("""\ - def _(): - linearity_data = [[row] for row in [ - "%.1f mm" % (np.mean(linearity_values["pos_error"]) * 1000.0), - "%.1f mm" % (np.max(linearity_values["pos_error"]) * 1000.0), - "%.1f mm" % (np.mean(linearity_values["pos_error_chunk_mean"]) * 1000.0), - "%.1f mm" % (np.max(linearity_values["pos_error_chunk_max"]) * 1000.0), - "%.1f deg" % math.degrees(np.mean(linearity_values["rot_noise"])), - "%.1f deg" % math.degrees(np.max(linearity_values["rot_noise"])), - "%.1f deg" % math.degrees(np.mean(linearity_values["rot_drift"])), - "%.1f deg" % math.degrees(np.max(linearity_values["rot_drift"])), - "%.1f%%" % (np.max(linearity_values["pos_discontinuity"]) * 100.0), - "%.1f%%" % (np.max(linearity_values["rot_discontinuity"]) * 100.0) - ]] - """) - expected_code = textwrap.dedent("""\ - def _(): - linearity_data = [ - [row] - for row in [ - "%.1f mm" % (np.mean(linearity_values["pos_error"]) * 1000.0), - "%.1f mm" % (np.max(linearity_values["pos_error"]) * 1000.0), - "%.1f mm" % ( - np.mean(linearity_values["pos_error_chunk_mean"]) * 1000.0), - "%.1f mm" % ( - np.max(linearity_values["pos_error_chunk_max"]) * 1000.0), - "%.1f deg" % math.degrees(np.mean(linearity_values["rot_noise"])), - "%.1f deg" % math.degrees(np.max(linearity_values["rot_noise"])), - "%.1f deg" % math.degrees(np.mean(linearity_values["rot_drift"])), - "%.1f deg" % math.degrees(np.max(linearity_values["rot_drift"])), - "%.1f%%" % (np.max(linearity_values["pos_discontinuity"]) * 100.0), - "%.1f%%" % (np.max(linearity_values["rot_discontinuity"]) * 100.0) - ] - ] - """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + code = """\ +def _(): + linearity_data = [[row] for row in [ + "%.1f mm" % (np.mean(linearity_values["pos_error"]) * 1000.0), + "%.1f mm" % (np.max(linearity_values["pos_error"]) * 1000.0), + "%.1f mm" % (np.mean(linearity_values["pos_error_chunk_mean"]) * 1000.0), + "%.1f mm" % (np.max(linearity_values["pos_error_chunk_max"]) * 1000.0), + "%.1f deg" % math.degrees(np.mean(linearity_values["rot_noise"])), + "%.1f deg" % math.degrees(np.max(linearity_values["rot_noise"])), + "%.1f deg" % math.degrees(np.mean(linearity_values["rot_drift"])), + "%.1f deg" % math.degrees(np.max(linearity_values["rot_drift"])), + "%.1f%%" % (np.max(linearity_values["pos_discontinuity"]) * 100.0), + "%.1f%%" % (np.max(linearity_values["rot_discontinuity"]) * 100.0) + ]] +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB36215507(self): code = textwrap.dedent("""\ From 44f65d5d2cf931c80d69923a7ce31171b2e931a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Padilla?= Date: Tue, 19 Dec 2017 16:59:52 -0500 Subject: [PATCH 216/719] Add online demo to README --- README.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.rst b/README.rst index 8102e3f2e..7aeecdbd6 100644 --- a/README.rst +++ b/README.rst @@ -36,6 +36,8 @@ The ultimate goal is that the code YAPF produces is as good as the code that a programmer would write if they were following the style guide. It takes away some of the drudgery of maintaining your code. +Try out YAPF with this `online demo `_. + .. footer:: YAPF is not an official Google product (experimental or otherwise), it is From fb2e5f21b611117e4cca64809d25907e6696ada0 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 19 Dec 2017 14:03:17 -0800 Subject: [PATCH 217/719] Move _ComprehensionState to its own module. No functionality change. --- yapf/yapflib/format_decision_state.py | 219 ++++++++++---------------- yapf/yapflib/object_state.py | 80 ++++++++++ 2 files changed, 161 insertions(+), 138 deletions(-) create mode 100644 yapf/yapflib/object_state.py diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 2737951d0..078db49c7 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -27,6 +27,7 @@ """ from yapf.yapflib import format_token +from yapf.yapflib import object_state from yapf.yapflib import split_penalty from yapf.yapflib import style from yapf.yapflib import unwrapped_line @@ -49,7 +50,7 @@ class FormatDecisionState(object): previous: The previous format decision state in the decision tree. stack: A stack (of _ParenState) keeping track of properties applying to parenthesis levels. - comp_stack: A stack (of _ComprehensionState) keeping track of properties + comp_stack: A stack (of ComprehensionState) keeping track of properties applying to comprehensions. ignore_stack_for_comparison: Ignore the stack of _ParenState for state comparison. @@ -587,45 +588,61 @@ def _AddTokenOnNewline(self, dry_run, must_split): return penalty + 10 - def _GetNewlineColumn(self): - """Return the new column on the newline.""" - current = self.next_token - previous = current.previous_token - top_of_stack = self.stack[-1] + def MoveStateToNextToken(self): + """Calculate format decision state information and move onto the next token. - if current.spaces_required_before > 2 or self.line.disable: - return current.spaces_required_before + Before moving onto the next token, we first calculate the format decision + state given the current token and its formatting decisions. Then the format + decision state is set up so that the next token can be added. + Returns: + The penalty for the number of characters over the column limit. + """ + current = self.next_token + if not current.OpensScope() and not current.ClosesScope(): + self.lowest_level_on_line = min(self.lowest_level_on_line, + self.paren_level) + + # If we encounter an opening bracket, we add a level to our stack to prepare + # for the subsequent tokens. if current.OpensScope(): - return top_of_stack.indent if self.paren_level else self.first_indent + last = self.stack[-1] + new_indent = style.Get('CONTINUATION_INDENT_WIDTH') + last.last_space - if current.ClosesScope(): - if (previous.OpensScope() or - (previous.is_comment and previous.previous_token is not None and - previous.previous_token.OpensScope())): - return max(0, - top_of_stack.indent - style.Get('CONTINUATION_INDENT_WIDTH')) - return top_of_stack.closing_scope_indent + self.stack.append(_ParenState(new_indent, self.stack[-1].last_space)) + self.paren_level += 1 - if (previous and previous.is_string and current.is_string and - format_token.Subtype.DICTIONARY_VALUE in current.subtypes): - return previous.column + # If we encounter a closing bracket, we can remove a level from our + # parenthesis stack. + if len(self.stack) > 1 and current.ClosesScope(): + if format_token.Subtype.DICTIONARY_KEY_PART in current.subtypes: + self.stack[-2].last_space = self.stack[-2].indent + else: + self.stack[-2].last_space = self.stack[-1].last_space + self.stack.pop() + self.paren_level -= 1 - if style.Get('INDENT_DICTIONARY_VALUE'): - if previous and (previous.value == ':' or previous.is_pseudo_paren): - if format_token.Subtype.DICTIONARY_VALUE in current.subtypes: - return top_of_stack.indent + is_multiline_string = current.is_string and '\n' in current.value + if is_multiline_string: + # This is a multiline string. Only look at the first line. + self.column += len(current.value.split('\n')[0]) + elif not current.is_pseudo_paren: + self.column += len(current.value) - if (_IsCompoundStatement(self.line.first) and - (not style.Get('DEDENT_CLOSING_BRACKETS') or - style.Get('SPLIT_BEFORE_FIRST_ARGUMENT'))): - token_indent = ( - len(self.line.first.whitespace_prefix.split('\n')[-1]) + - style.Get('INDENT_WIDTH')) - if token_indent == top_of_stack.indent: - return top_of_stack.indent + style.Get('CONTINUATION_INDENT_WIDTH') + self.next_token = self.next_token.next_token - return top_of_stack.indent + # Calculate the penalty for overflowing the column limit. + penalty = 0 + if not current.is_pylint_comment and self.column > self.column_limit: + excess_characters = self.column - self.column_limit + penalty += style.Get('SPLIT_PENALTY_EXCESS_CHARACTER') * excess_characters + + if is_multiline_string: + # If this is a multiline string, the column is actually the + # end of the last line in the string. + self.column = len(current.value.split('\n')[-1]) + + return penalty def _CalculateComprehensionState(self, newline): """Makes required changes to comprehension state. @@ -657,8 +674,7 @@ def _CalculateComprehensionState(self, newline): if (format_token.Subtype.COMP_EXPR in current.subtypes and format_token.Subtype.COMP_EXPR not in previous.subtypes): - self.comp_stack.append(_ComprehensionState(current)) - + self.comp_stack.append(object_state.ComprehensionState(current)) return penalty if (current.value == 'for' and @@ -697,61 +713,45 @@ def _CalculateComprehensionState(self, newline): return penalty - def MoveStateToNextToken(self): - """Calculate format decision state information and move onto the next token. - - Before moving onto the next token, we first calculate the format decision - state given the current token and its formatting decisions. Then the format - decision state is set up so that the next token can be added. - - Returns: - The penalty for the number of characters over the column limit. - """ + def _GetNewlineColumn(self): + """Return the new column on the newline.""" current = self.next_token - if not current.OpensScope() and not current.ClosesScope(): - self.lowest_level_on_line = min(self.lowest_level_on_line, - self.paren_level) - - # If we encounter an opening bracket, we add a level to our stack to prepare - # for the subsequent tokens. - if current.OpensScope(): - last = self.stack[-1] - new_indent = style.Get('CONTINUATION_INDENT_WIDTH') + last.last_space + previous = current.previous_token + top_of_stack = self.stack[-1] - self.stack.append(_ParenState(new_indent, self.stack[-1].last_space)) - self.paren_level += 1 + if current.spaces_required_before > 2 or self.line.disable: + return current.spaces_required_before - # If we encounter a closing bracket, we can remove a level from our - # parenthesis stack. - if len(self.stack) > 1 and current.ClosesScope(): - if format_token.Subtype.DICTIONARY_KEY_PART in current.subtypes: - self.stack[-2].last_space = self.stack[-2].indent - else: - self.stack[-2].last_space = self.stack[-1].last_space - self.stack.pop() - self.paren_level -= 1 + if current.OpensScope(): + return top_of_stack.indent if self.paren_level else self.first_indent - is_multiline_string = current.is_string and '\n' in current.value - if is_multiline_string: - # This is a multiline string. Only look at the first line. - self.column += len(current.value.split('\n')[0]) - elif not current.is_pseudo_paren: - self.column += len(current.value) + if current.ClosesScope(): + if (previous.OpensScope() or + (previous.is_comment and previous.previous_token is not None and + previous.previous_token.OpensScope())): + return max(0, + top_of_stack.indent - style.Get('CONTINUATION_INDENT_WIDTH')) + return top_of_stack.closing_scope_indent - self.next_token = self.next_token.next_token + if (previous and previous.is_string and current.is_string and + format_token.Subtype.DICTIONARY_VALUE in current.subtypes): + return previous.column - # Calculate the penalty for overflowing the column limit. - penalty = 0 - if not current.is_pylint_comment and self.column > self.column_limit: - excess_characters = self.column - self.column_limit - penalty += style.Get('SPLIT_PENALTY_EXCESS_CHARACTER') * excess_characters + if style.Get('INDENT_DICTIONARY_VALUE'): + if previous and (previous.value == ':' or previous.is_pseudo_paren): + if format_token.Subtype.DICTIONARY_VALUE in current.subtypes: + return top_of_stack.indent - if is_multiline_string: - # If this is a multiline string, the column is actually the - # end of the last line in the string. - self.column = len(current.value.split('\n')[-1]) + if (_IsCompoundStatement(self.line.first) and + (not style.Get('DEDENT_CLOSING_BRACKETS') or + style.Get('SPLIT_BEFORE_FIRST_ARGUMENT'))): + token_indent = ( + len(self.line.first.whitespace_prefix.split('\n')[-1]) + + style.Get('INDENT_WIDTH')) + if token_indent == top_of_stack.indent: + return top_of_stack.indent + style.Get('CONTINUATION_INDENT_WIDTH') - return penalty + return top_of_stack.indent def _FitsOnLine(self, start, end): """Determines if line between start and end can fit on the current line.""" @@ -975,60 +975,3 @@ def __ne__(self, other): def __hash__(self, *args, **kwargs): return hash((self.indent, self.last_space, self.closing_scope_indent, self.split_before_closing_bracket, self.num_line_splits)) - - -class _ComprehensionState(object): - """Maintains the state of list comprehension line-break decisions. - - A stack of _ComprehensionState objects are kept to ensure that list - comprehensions are wrapped with well-defined rules. - - Attributes: - expr_token: The first token in the comprehension. - for_token: The first 'for' token of the comprehension. - has_split_at_for: Whether there is a newline immediately before the - for_token. - has_interior_split: Whether there is a newline within the comprehension. - That is, a split somewhere after expr_token or before closing_bracket. - """ - - def __init__(self, expr_token): - self.expr_token = expr_token - self.for_token = None - self.has_split_at_for = False - self.has_interior_split = False - - def HasTrivialExpr(self): - """Returns whether the comp_expr is "trivial" i.e. is a single token.""" - return self.expr_token.next_token.value == 'for' - - @property - def opening_bracket(self): - return self.expr_token.previous_token - - @property - def closing_bracket(self): - return self.opening_bracket.matching_bracket - - def Clone(self): - clone = _ComprehensionState(self.expr_token) - clone.for_token = self.for_token - clone.has_split_at_for = self.has_split_at_for - clone.has_interior_split = self.has_interior_split - return clone - - def __repr__(self): - return ('[opening_bracket::%s, for_token::%s, has_split_at_for::%s,' - ' has_interior_split::%s, has_trivial_expr::%s]' % - (self.opening_bracket, self.for_token, self.has_split_at_for, - self.has_interior_split, self.HasTrivialExpr())) - - def __eq__(self, other): - return hash(self) == hash(other) - - def __ne__(self, other): - return not self == other - - def __hash__(self, *args, **kwargs): - return hash((self.expr_token, self.for_token, self.has_split_at_for, - self.has_interior_split)) diff --git a/yapf/yapflib/object_state.py b/yapf/yapflib/object_state.py new file mode 100644 index 000000000..dded7c423 --- /dev/null +++ b/yapf/yapflib/object_state.py @@ -0,0 +1,80 @@ +# Copyright 2017 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Represents the state of Python objects being formatted. + +Objects (e.g., list comprehensions, dictionaries, etc.) have specific +requirements on how they're formatted. These state objects keep track of these +requirements. +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + + +class ComprehensionState(object): + """Maintains the state of list comprehension formatting decisions. + + A stack of ComprehensionState objects are kept to ensure that list + comprehensions are wrapped with well-defined rules. + + Attributes: + expr_token: The first token in the comprehension. + for_token: The first 'for' token of the comprehension. + has_split_at_for: Whether there is a newline immediately before the + for_token. + has_interior_split: Whether there is a newline within the comprehension. + That is, a split somewhere after expr_token or before closing_bracket. + """ + + def __init__(self, expr_token): + self.expr_token = expr_token + self.for_token = None + self.has_split_at_for = False + self.has_interior_split = False + + def HasTrivialExpr(self): + """Returns whether the comp_expr is "trivial" i.e. is a single token.""" + return self.expr_token.next_token.value == 'for' + + @property + def opening_bracket(self): + return self.expr_token.previous_token + + @property + def closing_bracket(self): + return self.opening_bracket.matching_bracket + + def Clone(self): + clone = ComprehensionState(self.expr_token) + clone.for_token = self.for_token + clone.has_split_at_for = self.has_split_at_for + clone.has_interior_split = self.has_interior_split + return clone + + def __repr__(self): + return ('[opening_bracket::%s, for_token::%s, has_split_at_for::%s,' + ' has_interior_split::%s, has_trivial_expr::%s]' % + (self.opening_bracket, self.for_token, self.has_split_at_for, + self.has_interior_split, self.HasTrivialExpr())) + + def __eq__(self, other): + return hash(self) == hash(other) + + def __ne__(self, other): + return not self == other + + def __hash__(self, *args, **kwargs): + return hash((self.expr_token, self.for_token, self.has_split_at_for, + self.has_interior_split)) From 526fbe7c2ea13d12eb4cf973c3e49d5232ccaf4e Mon Sep 17 00:00:00 2001 From: Peter Ludemann Date: Wed, 20 Dec 2017 19:54:27 -0800 Subject: [PATCH 218/719] fix --help for where style file is found --- README.rst | 7 ++++--- yapf/__init__.py | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 7aeecdbd6..4d4237cba 100644 --- a/README.rst +++ b/README.rst @@ -113,9 +113,10 @@ Options:: --style STYLE specify formatting style: either a style name (for example "pep8" or "google"), or the name of a file with style settings. The default is pep8 unless a - .style.yapf or setup.cfg file located in one of the - parent directories of the source file (or current - directory for stdin) + .style.yapf or setup.cfg file located in the same + directory as the source or one of its parent + directories (for stdin, the current directory is + used). --style-help show style settings and exit; this output can be saved to .style.yapf to make your settings permanent --no-local-style don't search for local style definition diff --git a/yapf/__init__.py b/yapf/__init__.py index 7a0f17673..cc820e49d 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -99,9 +99,10 @@ def main(argv): action='store', help=('specify formatting style: either a style name (for example "pep8" ' 'or "google"), or the name of a file with style settings. The ' - 'default is pep8 unless a %s or %s file located in one of the ' - 'parent directories of the source file (or current directory for ' - 'stdin)' % (style.LOCAL_STYLE, style.SETUP_CONFIG))) + 'default is pep8 unless a %s or %s file located in the same ' + 'directory as the source or one of its parent directories ' + '(for stdin, the current directory is used).' % + (style.LOCAL_STYLE, style.SETUP_CONFIG))) parser.add_argument( '--style-help', action='store_true', From 48b4f04d9821d956c872a6d711ee92bd46774519 Mon Sep 17 00:00:00 2001 From: Ronald Eddy Jr Date: Mon, 25 Dec 2017 22:38:41 -0800 Subject: [PATCH 219/719] Docs: Update HTTP -> HTTPS URL updated to use HTTPS protocol where appropriate to improve security and privacy. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 4d4237cba..28706589c 100644 --- a/README.rst +++ b/README.rst @@ -3,7 +3,7 @@ YAPF ==== .. image:: https://badge.fury.io/py/yapf.svg - :target: http://badge.fury.io/py/yapf + :target: https://badge.fury.io/py/yapf :alt: PyPI version .. image:: https://travis-ci.org/google/yapf.svg?branch=master From 89e3403571613d9b4032d494f8f34eec491c31e4 Mon Sep 17 00:00:00 2001 From: Wenfeng CAI Date: Tue, 9 Jan 2018 10:33:03 +0800 Subject: [PATCH 220/719] Remove command definition in Vim autoload script It seems that commands can't be defined in autoload scripts of Vim 8. --- plugins/vim/autoload/yapf.vim | 9 --------- 1 file changed, 9 deletions(-) diff --git a/plugins/vim/autoload/yapf.vim b/plugins/vim/autoload/yapf.vim index b5e94dc41..bbb0f19b8 100644 --- a/plugins/vim/autoload/yapf.vim +++ b/plugins/vim/autoload/yapf.vim @@ -20,13 +20,6 @@ " map :call yapf#YAPF() " imap :call yapf#YAPF() " -" Alternatively, you can call the command YAPF. If you omit the range, -" it will reformat the whole buffer. -" -" example: -" :YAPF " formats whole buffer -" :'<,'>YAPF " formats lines selected in visual mode -" function! yapf#YAPF() range " Determine range to format. let l:line_ranges = a:firstline . '-' . a:lastline @@ -54,5 +47,3 @@ function! yapf#YAPF() range " Reset cursor to first line of the formatted range. call cursor(a:firstline, 1) endfunction - -command! -range=% YAPF ,call yapf#YAPF() From 46a12cc146bae82b1b325362b53bbdd8d2e467ff Mon Sep 17 00:00:00 2001 From: Wenfeng CAI Date: Tue, 9 Jan 2018 10:34:39 +0800 Subject: [PATCH 221/719] Add command to a new file of Vim plugin --- plugins/vim/plugin/yapf.vim | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 plugins/vim/plugin/yapf.vim diff --git a/plugins/vim/plugin/yapf.vim b/plugins/vim/plugin/yapf.vim new file mode 100644 index 000000000..e2cc7fd2c --- /dev/null +++ b/plugins/vim/plugin/yapf.vim @@ -0,0 +1,25 @@ +" Copyright 2015 Google Inc. All Rights Reserved. +" +" Licensed under the Apache License, Version 2.0 (the "License"); +" you may not use this file except in compliance with the License. +" You may obtain a copy of the License at +" +" http://www.apache.org/licenses/LICENSE-2.0 +" +" Unless required by applicable law or agreed to in writing, software +" distributed under the License is distributed on an "AS IS" BASIS, +" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +" See the License for the specific language governing permissions and +" limitations under the License. +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +" VIM command for YAPF support +" +" Place this script in your ~/.vim/plugin directory. You can call the +" command YAPF. If you omit the range, it will reformat the whole +" buffer. +" +" example: +" :YAPF " formats whole buffer +" :'<,'>YAPF " formats lines selected in visual mode + +command! -range=% YAPF ,call yapf#YAPF() From d27aec9307c4ec8f0318962a89e4656680138ca4 Mon Sep 17 00:00:00 2001 From: Wenfeng CAI Date: Tue, 9 Jan 2018 10:38:16 +0800 Subject: [PATCH 222/719] Sync comments with plugins/README.rst --- plugins/vim/autoload/yapf.vim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/vim/autoload/yapf.vim b/plugins/vim/autoload/yapf.vim index bbb0f19b8..ad3e7fc90 100644 --- a/plugins/vim/autoload/yapf.vim +++ b/plugins/vim/autoload/yapf.vim @@ -17,8 +17,8 @@ " Place this script in your ~/.vim/autoload directory. You can add accessors to " ~/.vimrc, e.g.: " -" map :call yapf#YAPF() -" imap :call yapf#YAPF() +" map :call yapf#YAPF() +" imap :call yapf#YAPF() " function! yapf#YAPF() range " Determine range to format. From fd773f2c554221bdb081d239a409b04828a9323b Mon Sep 17 00:00:00 2001 From: Wenfeng CAI Date: Tue, 9 Jan 2018 10:48:20 +0800 Subject: [PATCH 223/719] Update documents for Vim plugin command --- plugins/README.rst | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/plugins/README.rst b/plugins/README.rst index 4bcad86ba..f7657cc8a 100644 --- a/plugins/README.rst +++ b/plugins/README.rst @@ -11,8 +11,9 @@ found here: https://github.com/paetzke/py-yapf.el VIM === -The ``vim`` plugin allows you to reformat a range of code. Place it into the -``.vim/autoload`` directory or use a plugin manager like Plug or Vundle: +The ``vim`` plugin allows you to reformat a range of code. Copy ``plugin`` and +``autoload`` directories into your ~/.vim or use ``:packadd`` in Vim 8. Or use +a plugin manager like Plug or Vundle: .. code-block:: vim @@ -30,6 +31,16 @@ You can add key bindings in the ``.vimrc`` file: map :call yapf#YAPF() imap :call yapf#YAPF() +Alternatively, you can call the command ``YAPF``. If you omit the range, it +will reformat the whole buffer. + +example: + +.. code-block:: vim + + :YAPF " formats whole buffer + :'<,'>YAPF " formats lines selected in visual mode + Sublime Text ============ From 5fb69e3798ce6ac835c4e4f7be83c16b4b425b6f Mon Sep 17 00:00:00 2001 From: Petter Strandmark Date: Wed, 10 Jan 2018 21:42:37 +0100 Subject: [PATCH 224/719] Fix formatting with use_tabs=True. There are two issues when setting use_tabs=True: 1) The indent_width then makes no sense as a single tab per indentation is always desired. 2) Aligning things vertically after the indentation should never be done with tabs. The current setting assumes that a tab has the same width as a a single space and breaks the following code spectacularly: def test(): my_module.call_function("1234567890", "1234567890", "1234567890", "1234567890", "1234567890") For example, clang-format still uses spaces for vertical alignment when using tabs for indentation. --- CHANGELOG | 2 ++ yapf/yapflib/format_token.py | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e190fa650..bac20a1ca 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,8 @@ ## [0.20.1] UNRELEASED ### Fixed - Don't treat 'None' as a keyword if calling a function on it, like '__ne__()'. +- use_tabs=True always uses a single tab per indentation level; spaces are + used for aligning vertically after that. ## [0.20.0] 2017-11-14 ### Added diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 85af6212d..7e02c9fc1 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -122,11 +122,11 @@ def AddWhitespacePrefix(self, newlines_before, spaces=0, indent_level=0): spaces: (int) The number of spaces to place before the token. indent_level: (int) The indentation level. """ - indent_char = '\t' if style.Get('USE_TABS') else ' ' - token_indent_char = indent_char if newlines_before > 0 else ' ' - indent_before = ( - indent_char * indent_level * style.Get('INDENT_WIDTH') + - token_indent_char * spaces) + if style.Get('USE_TABS'): + indent_before = '\t' * indent_level + ' ' * spaces + else: + indent_before = ( + ' ' * indent_level * style.Get('INDENT_WIDTH') + ' ' * spaces) if self.is_comment: comment_lines = [s.lstrip() for s in self.value.splitlines()] From 04a1ec2b58a51e56d60b5b89bd0d1b55820b1f6a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 13 Jan 2018 21:53:14 -0800 Subject: [PATCH 225/719] Relax split penalty of ending bracket in if stmt The dedent_closing_bracket knob requires that it be allow to split the closing bracket of and if statement. Closes #495 --- CHANGELOG | 2 ++ yapf/yapflib/split_penalty.py | 2 +- yapf/yapflib/unwrapped_line.py | 5 +++-- yapftests/pytree_unwrapper_test.py | 4 ++-- yapftests/reformatter_facebook_test.py | 15 +++++++++++++++ 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e190fa650..bb534a084 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -30,6 +30,8 @@ some encodings, like cp936, used on Windows. - Remove the penalty for a split before the first argument in a function call where the only argument is a generator expression. +- Relax the split of a paren at the end of an if statement. With + `dedent_closing_brackets` option requires that it be able to split there. ## [0.19.0] 2017-10-14 ### Added diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 8ac078082..135ed1166 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -421,7 +421,7 @@ def Visit_atom(self, node): # pylint: disable=invalid-name if node.children[0].value == '(': if node.children[-1].value == ')': if pytree_utils.NodeName(node.parent) == 'if_stmt': - _SetSplitPenalty(node.children[-1], UNBREAKABLE) + _SetSplitPenalty(node.children[-1], STRONGLY_CONNECTED) else: if len(node.children) > 2: _SetSplitPenalty(_FirstChildNode(node.children[1]), EXPR) diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 781f6f3c6..4ae4749a4 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -271,8 +271,9 @@ def _SpaceRequiredBetween(left, right): # A typed argument should have a space after the colon. return True if left.is_string: - if (rval == '=' and format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in - right.subtypes): + if (rval == '=' and + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in right.subtypes + ): # If there is a type hint, then we don't want to add a space between the # equal sign and the hint. return False diff --git a/yapftests/pytree_unwrapper_test.py b/yapftests/pytree_unwrapper_test.py index 03a93f003..86b256d9f 100644 --- a/yapftests/pytree_unwrapper_test.py +++ b/yapftests/pytree_unwrapper_test.py @@ -318,12 +318,12 @@ def _CheckMatchingBrackets(self, uwlines, list_of_expected): def testFunctionDef(self): code = textwrap.dedent("""\ - def foo(a, b={'hello': ['w','d']}, c=[42, 37]): + def foo(a, b=['w','d'], c=[42, 37]): pass """) uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckMatchingBrackets(uwlines, [ - [(2, 24), (7, 15), (10, 14), (19, 23)], + [(2, 20), (7, 11), (15, 19)], [], ]) diff --git a/yapftests/reformatter_facebook_test.py b/yapftests/reformatter_facebook_test.py index 953d290aa..2bf84331e 100644 --- a/yapftests/reformatter_facebook_test.py +++ b/yapftests/reformatter_facebook_test.py @@ -412,6 +412,21 @@ def foo(): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testIfStmtClosingBracket(self): + unformatted_code = """\ +if (isinstance(value , (StopIteration , StopAsyncIteration )) and exc.__cause__ is value_asdfasdfasdfasdfsafsafsafdasfasdfs): + return False +""" + expected_formatted_code = """\ +if ( + isinstance(value, (StopIteration, StopAsyncIteration)) and + exc.__cause__ is value_asdfasdfasdfasdfsafsafsafdasfasdfs +): + return False +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From 29776aa79938575ba9b9d4c1c8ef4ba090d5aa01 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 13 Jan 2018 22:04:00 -0800 Subject: [PATCH 226/719] Bump version to v0.20.1 --- CHANGELOG | 6 +++--- yapf/__init__.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ed646e360..29d87c2f7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,11 +2,13 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.20.1] UNRELEASED +## [0.20.1] 2018-01-13 ### Fixed - Don't treat 'None' as a keyword if calling a function on it, like '__ne__()'. - use_tabs=True always uses a single tab per indentation level; spaces are used for aligning vertically after that. +- Relax the split of a paren at the end of an if statement. With + `dedent_closing_brackets` option requires that it be able to split there. ## [0.20.0] 2017-11-14 ### Added @@ -32,8 +34,6 @@ some encodings, like cp936, used on Windows. - Remove the penalty for a split before the first argument in a function call where the only argument is a generator expression. -- Relax the split of a paren at the end of an if statement. With - `dedent_closing_brackets` option requires that it be able to split there. ## [0.19.0] 2017-10-14 ### Added diff --git a/yapf/__init__.py b/yapf/__init__.py index cc820e49d..55c56916a 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.20.0' +__version__ = '0.20.1' def main(argv): From 41e562f0d36efaaea9efd14f6d31717b74b7e638 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 14 Jan 2018 16:49:35 -0800 Subject: [PATCH 227/719] Remove extraneous copyright year. --- setup.py | 2 +- yapf/__init__.py | 2 +- yapf/__main__.py | 2 +- yapf/yapflib/__init__.py | 2 +- yapf/yapflib/blank_line_calculator.py | 2 +- yapf/yapflib/comment_splicer.py | 2 +- yapf/yapflib/continuation_splicer.py | 2 +- yapf/yapflib/errors.py | 2 +- yapf/yapflib/file_resources.py | 2 +- yapf/yapflib/format_decision_state.py | 2 +- yapf/yapflib/format_token.py | 2 +- yapf/yapflib/line_joiner.py | 2 +- yapf/yapflib/py3compat.py | 2 +- yapf/yapflib/pytree_unwrapper.py | 2 +- yapf/yapflib/pytree_utils.py | 2 +- yapf/yapflib/pytree_visitor.py | 2 +- yapf/yapflib/reformatter.py | 2 +- yapf/yapflib/split_penalty.py | 2 +- yapf/yapflib/style.py | 2 +- yapf/yapflib/subtype_assigner.py | 2 +- yapf/yapflib/unwrapped_line.py | 2 +- yapf/yapflib/verifier.py | 2 +- yapf/yapflib/yapf_api.py | 2 +- yapftests/__init__.py | 2 +- yapftests/blank_line_calculator_test.py | 2 +- yapftests/comment_splicer_test.py | 2 +- yapftests/file_resources_test.py | 2 +- yapftests/format_decision_state_test.py | 2 +- yapftests/format_token_test.py | 2 +- yapftests/line_joiner_test.py | 2 +- yapftests/main_test.py | 2 +- yapftests/pytree_unwrapper_test.py | 2 +- yapftests/pytree_utils_test.py | 2 +- yapftests/pytree_visitor_test.py | 2 +- yapftests/reformatter_basic_test.py | 2 +- yapftests/reformatter_buganizer_test.py | 2 +- yapftests/reformatter_facebook_test.py | 2 +- yapftests/reformatter_pep8_test.py | 2 +- yapftests/reformatter_python3_test.py | 2 +- yapftests/reformatter_style_config_test.py | 2 +- yapftests/reformatter_verify_test.py | 2 +- yapftests/split_penalty_test.py | 2 +- yapftests/style_test.py | 2 +- yapftests/subtype_assigner_test.py | 2 +- yapftests/unwrapped_line_test.py | 2 +- yapftests/yapf_test.py | 2 +- yapftests/yapf_test_helper.py | 2 +- 47 files changed, 47 insertions(+), 47 deletions(-) diff --git a/setup.py b/setup.py index 7d677b290..da4bf0907 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/__init__.py b/yapf/__init__.py index 55c56916a..51e01933d 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/__main__.py b/yapf/__main__.py index 2ebc7a635..f1d0e322d 100644 --- a/yapf/__main__.py +++ b/yapf/__main__.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/__init__.py b/yapf/yapflib/__init__.py index 80217ac4a..e7522b2ca 100644 --- a/yapf/yapflib/__init__.py +++ b/yapf/yapflib/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/blank_line_calculator.py b/yapf/yapflib/blank_line_calculator.py index bcd7a867a..4c62e8be6 100644 --- a/yapf/yapflib/blank_line_calculator.py +++ b/yapf/yapflib/blank_line_calculator.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index f374eea07..8717394f0 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/continuation_splicer.py b/yapf/yapflib/continuation_splicer.py index 74ea1a0cb..3b542de23 100644 --- a/yapf/yapflib/continuation_splicer.py +++ b/yapf/yapflib/continuation_splicer.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/errors.py b/yapf/yapflib/errors.py index aa8f3eada..3946275c8 100644 --- a/yapf/yapflib/errors.py +++ b/yapf/yapflib/errors.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 063161b48..a84d28352 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 078db49c7..66f12dc94 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 7e02c9fc1..d225853b0 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/line_joiner.py b/yapf/yapflib/line_joiner.py index 860fce788..84346c268 100644 --- a/yapf/yapflib/line_joiner.py +++ b/yapf/yapflib/line_joiner.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py index a54ddb7b6..4bb8ebeb1 100644 --- a/yapf/yapflib/py3compat.py +++ b/yapf/yapflib/py3compat.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index 31df6b90f..a81ccd468 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/pytree_utils.py b/yapf/yapflib/pytree_utils.py index 417bdb11e..08048d870 100644 --- a/yapf/yapflib/pytree_utils.py +++ b/yapf/yapflib/pytree_utils.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/pytree_visitor.py b/yapf/yapflib/pytree_visitor.py index 3f1ab0b71..49da05660 100644 --- a/yapf/yapflib/pytree_visitor.py +++ b/yapf/yapflib/pytree_visitor.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 299fef8db..58a72591a 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 135ed1166..df6bd88eb 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 5451f8c20..02b6d0b31 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index f24dbbc5e..4fec1e98f 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 4ae4749a4..c5e2f5c51 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/verifier.py b/yapf/yapflib/verifier.py index b16aefb88..bcbe6fb6b 100644 --- a/yapf/yapflib/verifier.py +++ b/yapf/yapflib/verifier.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index a2c943930..7f174337f 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/__init__.py b/yapftests/__init__.py index 80217ac4a..e7522b2ca 100644 --- a/yapftests/__init__.py +++ b/yapftests/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/blank_line_calculator_test.py b/yapftests/blank_line_calculator_test.py index 3bdff94b3..2a27a2f89 100644 --- a/yapftests/blank_line_calculator_test.py +++ b/yapftests/blank_line_calculator_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/comment_splicer_test.py b/yapftests/comment_splicer_test.py index 5abe4508f..aacc8882c 100644 --- a/yapftests/comment_splicer_test.py +++ b/yapftests/comment_splicer_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index adfdae769..be7f32847 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/format_decision_state_test.py b/yapftests/format_decision_state_test.py index 0c31b6882..612296008 100644 --- a/yapftests/format_decision_state_test.py +++ b/yapftests/format_decision_state_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index ff1d01555..b3c0dc2aa 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/line_joiner_test.py b/yapftests/line_joiner_test.py index 518ea0887..6501bc883 100644 --- a/yapftests/line_joiner_test.py +++ b/yapftests/line_joiner_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/main_test.py b/yapftests/main_test.py index 508c02c26..138853ceb 100644 --- a/yapftests/main_test.py +++ b/yapftests/main_test.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/pytree_unwrapper_test.py b/yapftests/pytree_unwrapper_test.py index 86b256d9f..f95f3666c 100644 --- a/yapftests/pytree_unwrapper_test.py +++ b/yapftests/pytree_unwrapper_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/pytree_utils_test.py b/yapftests/pytree_utils_test.py index db5d36357..3b9fde7f0 100644 --- a/yapftests/pytree_utils_test.py +++ b/yapftests/pytree_utils_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/pytree_visitor_test.py b/yapftests/pytree_visitor_test.py index c86ffc960..1908249d4 100644 --- a/yapftests/pytree_visitor_test.py +++ b/yapftests/pytree_visitor_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index aa237e147..be8ede644 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1,4 +1,4 @@ -# Copyright 2016-2017 Google Inc. All Rights Reserved. +# Copyright 2016 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index eda0fbe8f..3689e6893 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -1,4 +1,4 @@ -# Copyright 2016-2017 Google Inc. All Rights Reserved. +# Copyright 2016 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/reformatter_facebook_test.py b/yapftests/reformatter_facebook_test.py index 2bf84331e..289aa8534 100644 --- a/yapftests/reformatter_facebook_test.py +++ b/yapftests/reformatter_facebook_test.py @@ -1,4 +1,4 @@ -# Copyright 2016-2017 Google Inc. All Rights Reserved. +# Copyright 2016 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index e47ec400a..e4d7ac1d2 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -1,4 +1,4 @@ -# Copyright 2016-2017 Google Inc. All Rights Reserved. +# Copyright 2016 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index fc604b1c0..62b0a8cf8 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -1,4 +1,4 @@ -# Copyright 2016-2017 Google Inc. All Rights Reserved. +# Copyright 2016 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/reformatter_style_config_test.py b/yapftests/reformatter_style_config_test.py index 8cf3fb055..5afd805b4 100644 --- a/yapftests/reformatter_style_config_test.py +++ b/yapftests/reformatter_style_config_test.py @@ -1,4 +1,4 @@ -# Copyright 2016-2017 Google Inc. All Rights Reserved. +# Copyright 2016 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/reformatter_verify_test.py b/yapftests/reformatter_verify_test.py index a585c3b84..1b3d5b080 100644 --- a/yapftests/reformatter_verify_test.py +++ b/yapftests/reformatter_verify_test.py @@ -1,4 +1,4 @@ -# Copyright 2016-2017 Google Inc. All Rights Reserved. +# Copyright 2016 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index 1c8bf4af9..7d500daa0 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 583b80cef..7c3f9747e 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index 9dd1050fd..8daead94c 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/unwrapped_line_test.py b/yapftests/unwrapped_line_test.py index 310b51bbd..90be1a13a 100644 --- a/yapftests/unwrapped_line_test.py +++ b/yapftests/unwrapped_line_test.py @@ -1,4 +1,4 @@ -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index bfe764de6..df06dc0e2 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright 2015-2017 Google Inc. All Rights Reserved. +# Copyright 2015 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/yapftests/yapf_test_helper.py b/yapftests/yapf_test_helper.py index 95edd29b4..53357a2b1 100644 --- a/yapftests/yapf_test_helper.py +++ b/yapftests/yapf_test_helper.py @@ -1,4 +1,4 @@ -# Copyright 2016-2017 Google Inc. All Rights Reserved. +# Copyright 2016 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. From fc1a8847b2684a349f215555c07a27c70372101a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 14 Jan 2018 17:43:10 -0800 Subject: [PATCH 228/719] Use tabs when constructing continuation line. Closes #505 --- CHANGELOG | 4 ++ yapf/yapflib/format_decision_state.py | 16 ++++---- yapftests/yapf_test.py | 56 +++++++++++++++++++-------- 3 files changed, 53 insertions(+), 23 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 29d87c2f7..16ad1e2d8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.20.2] UNRELEASED +### Fixed +- Use tabs when constructing a continuation line when `USE_TABS` is enabled. + ## [0.20.1] 2018-01-13 ### Fixed - Don't treat 'None' as a keyword if calling a function on it, like '__ne__()'. diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 66f12dc94..24626a156 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -43,7 +43,6 @@ class FormatDecisionState(object): column: The number of used columns in the current line. next_token: The next token to be formatted. paren_level: The level of nesting inside (), [], and {}. - start_of_line_level: The paren_level at the start of this line. lowest_level_on_line: The lowest paren_level on the current line. newline: Indicates if a newline is added along the edge to this format decision state node. @@ -70,7 +69,6 @@ def __init__(self, line, first_indent): self.column = first_indent self.line = line self.paren_level = 0 - self.start_of_line_level = 0 self.lowest_level_on_line = 0 self.ignore_stack_for_comparison = False self.stack = [_ParenState(first_indent, first_indent)] @@ -87,7 +85,7 @@ def Clone(self): new.column = self.column new.line = self.line new.paren_level = self.paren_level - new.start_of_line_level = self.start_of_line_level + new.line.depth = self.line.depth new.lowest_level_on_line = self.lowest_level_on_line new.ignore_stack_for_comparison = self.ignore_stack_for_comparison new.first_indent = self.first_indent @@ -104,7 +102,7 @@ def __eq__(self, other): return (self.next_token == other.next_token and self.column == other.column and self.paren_level == other.paren_level and - self.start_of_line_level == other.start_of_line_level and + self.line.depth == other.line.depth and self.lowest_level_on_line == other.lowest_level_on_line and (self.ignore_stack_for_comparison or other.ignore_stack_for_comparison or @@ -115,7 +113,7 @@ def __ne__(self, other): def __hash__(self): return hash((self.next_token, self.column, self.paren_level, - self.start_of_line_level, self.lowest_level_on_line)) + self.line.depth, self.lowest_level_on_line)) def __repr__(self): return ('column::%d, next_token::%s, paren_level::%d, stack::[\n\t%s' % @@ -544,11 +542,15 @@ def _AddTokenOnNewline(self, dry_run, must_split): self.column = self._GetNewlineColumn() if not dry_run: - current.AddWhitespacePrefix(newlines_before=1, spaces=self.column) + indent_level = self.line.depth + spaces = self.column + if spaces: + spaces -= indent_level * style.Get('INDENT_WIDTH') + current.AddWhitespacePrefix( + newlines_before=1, spaces=spaces, indent_level=indent_level) if not current.is_comment: self.stack[-1].last_space = self.column - self.start_of_line_level = self.paren_level self.lowest_level_on_line = self.paren_level if (previous.OpensScope() or diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index df06dc0e2..0ae6a0dcc 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1157,22 +1157,46 @@ def testTrailingCommentsWithDisabledFormatting(self): extra_options=['--lines', '1-1', '--style', 'chromium']) def testUseTabs(self): - unformatted_code = textwrap.dedent("""\ - def foo_function(): - if True: - pass - """) - expected_formatted_code = textwrap.dedent("""\ - def foo_function(): - if True: - pass - """) - style_contents = textwrap.dedent(u'''\ - [style] - based_on_style = chromium - USE_TABS = true - INDENT_WIDTH=1 - ''') + unformatted_code = """\ +def foo_function(): + if True: + pass +""" + expected_formatted_code = """\ +def foo_function(): + if True: + pass +""" + style_contents = u"""\ +[style] +based_on_style = chromium +USE_TABS = true +INDENT_WIDTH=1 +""" + with utils.TempFileContents(self.test_tmpdir, style_contents) as stylepath: + self.assertYapfReformats( + unformatted_code, + expected_formatted_code, + extra_options=['--style={0}'.format(stylepath)]) + + def testUseTabsWith(self): + unformatted_code = """\ +def f(): + return ['hello', 'world',] +""" + expected_formatted_code = """\ +def f(): + return [ + 'hello', + 'world', + ] +""" + style_contents = u"""\ +[style] +based_on_style = chromium +USE_TABS = true +INDENT_WIDTH=1 +""" with utils.TempFileContents(self.test_tmpdir, style_contents) as stylepath: self.assertYapfReformats( unformatted_code, From 84cbb94f5aa5be3ab12bda3ac5488f9c0a078260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Padilla?= Date: Tue, 16 Jan 2018 12:26:33 -0500 Subject: [PATCH 229/719] Update online demo URL My Heroku account was recently running out of free dyno hours pretty quickly --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 28706589c..250ef3fb7 100644 --- a/README.rst +++ b/README.rst @@ -36,7 +36,7 @@ The ultimate goal is that the code YAPF produces is as good as the code that a programmer would write if they were following the style guide. It takes away some of the drudgery of maintaining your code. -Try out YAPF with this `online demo `_. +Try out YAPF with this `online demo `_. .. footer:: From 1bdcb52717209580e7c855eab2af76f86e69a39e Mon Sep 17 00:00:00 2001 From: delirious-lettuce Date: Tue, 16 Jan 2018 20:38:46 -0700 Subject: [PATCH 230/719] Fix typos: `funciton` | `function` `calcuation` | `calculation` `spliting` | `splitting` `opertor` | `operator` `separted` | `separated` `sucessfully` | `successfully` `Oudented` | `Outdented` `Oparator` | `Operator` `simplifed` | `simplified` `ourselfs` | `ourselves` `documenation` | `documentation` `excetion` | `exception` `mutliple` | `multiple` `curent` | `current` `mutiple` | `multiple` --- CHANGELOG | 6 +++--- HACKING.rst | 2 +- README.rst | 2 +- yapf/yapflib/continuation_splicer.py | 2 +- yapf/yapflib/format_decision_state.py | 2 +- yapf/yapflib/split_penalty.py | 2 +- yapf/yapflib/unwrapped_line.py | 4 ++-- yapf/yapflib/yapf_api.py | 2 +- yapftests/reformatter_pep8_test.py | 2 +- yapftests/reformatter_python3_test.py | 2 +- yapftests/utils.py | 4 ++-- 11 files changed, 15 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 16ad1e2d8..7e91453a6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,7 +12,7 @@ - use_tabs=True always uses a single tab per indentation level; spaces are used for aligning vertically after that. - Relax the split of a paren at the end of an if statement. With - `dedent_closing_brackets` option requires that it be able to split there. + `dedent_closing_brackets` option requires that it be able to split there. ## [0.20.0] 2017-11-14 ### Added @@ -95,7 +95,7 @@ ## [0.16.3] 2017-07-13 ### Changed -- Add filename information to a ParseError excetion. +- Add filename information to a ParseError exception. ### Fixed - A token that ends in a continuation marker may have more than one newline in it, thus changing its "lineno" value. This can happen if multiple @@ -180,7 +180,7 @@ ## [0.15.0] 2017-01-12 ### Added - Keep type annotations intact as much as possible. Don't try to split the over - mutliple lines. + multiple lines. ### Fixed - When determining if each element in a dictionary can fit on a single line, we are skipping dictionary entries. However, we need to ignore comments in our diff --git a/HACKING.rst b/HACKING.rst index ee29a111b..eb1618032 100644 --- a/HACKING.rst +++ b/HACKING.rst @@ -5,7 +5,7 @@ To run YAPF on all of YAPF:: $ PYTHONPATH=$PWD/yapf python -m yapf -i -r . -To run YAPF on just the files changed in the curent git branch:: +To run YAPF on just the files changed in the current git branch:: $ PYTHONPATH=$PWD/yapf python -m yapf -i $(git diff --name-only @{upstream}) diff --git a/README.rst b/README.rst index 28706589c..c01a00384 100644 --- a/README.rst +++ b/README.rst @@ -466,7 +466,7 @@ Knobs ``SPLIT_COMPLEX_COMPREHENSION`` For list comprehensions and generator expressions with multiple clauses - (e.g mutiple "for" calls, "if" filter expressions) and which need to be + (e.g multiple "for" calls, "if" filter expressions) and which need to be reflowed, split each clause onto its own line. For example: .. code-block:: python diff --git a/yapf/yapflib/continuation_splicer.py b/yapf/yapflib/continuation_splicer.py index 3b542de23..b86188cb5 100644 --- a/yapf/yapflib/continuation_splicer.py +++ b/yapf/yapflib/continuation_splicer.py @@ -16,7 +16,7 @@ The "backslash-newline" continuation marker is shoved into the node's prefix. Pull them out and make it into nodes of their own. - SpliceContinuations(): the main funciton exported by this module. + SpliceContinuations(): the main function exported by this module. """ from lib2to3 import pytree diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 24626a156..f29002156 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -798,7 +798,7 @@ def ImplicitStringConcatenation(tok): format_token.Subtype.DICTIONARY_VALUE in current.subtypes) or ImplicitStringConcatenation(current)): # A dictionary entry that cannot fit on a single line shouldn't matter - # to this calcuation. If it can't fit on a single line, then the + # to this calculation. If it can't fit on a single line, then the # opening should be on the same line as the key and the rest on # newlines after it. But the other entries should be on single lines # if possible. diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index df6bd88eb..9fae32791 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -192,7 +192,7 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name _SetStronglyConnected(node.children[1]) if (len(node.children[1].children) > 1 and pytree_utils.NodeName(node.children[1].children[1]) == 'comp_for'): - # Don't penalize spliting before a comp_for expression. + # Don't penalize splitting before a comp_for expression. _SetSplitPenalty(_FirstChildNode(node.children[1]), 0) else: _SetSplitPenalty( diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index c5e2f5c51..e7e82c79d 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -282,7 +282,7 @@ def _SpaceRequiredBetween(left, right): # or dot should have a space after it. return True if left.is_binary_op and lval != '**' and _IsUnaryOperator(right): - # Space between the binary opertor and the unary operator. + # Space between the binary operator and the unary operator. return True if left.is_keyword and _IsUnaryOperator(right): # Handle things like "not -3 < x". @@ -324,7 +324,7 @@ def _SpaceRequiredBetween(left, right): return False if ((lval == '(' and rval == ')') or (lval == '[' and rval == ']') or (lval == '{' and rval == '}')): - # Empty objects shouldn't be separted by spaces. + # Empty objects shouldn't be separated by spaces. return False if (lval in pytree_utils.OPENING_BRACKETS and rval in pytree_utils.OPENING_BRACKETS): diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 7f174337f..271e3a591 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -68,7 +68,7 @@ def FormatFile(filename, Returns: Tuple of (reformatted_code, encoding, changed). reformatted_code is None if - the file is sucessfully written to (having used in_place). reformatted_code + the file is successfully written to (having used in_place). reformatted_code is a diff if print_diff is True. Raises: diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index e4d7ac1d2..a6f736f7a 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -88,7 +88,7 @@ def testSpaceBetweenEndingCommandAndClosingBracket(self): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - def testContinuedNonOudentedLine(self): + def testContinuedNonOutdentedLine(self): code = textwrap.dedent("""\ class eld(d): if str(geom.geom_type).upper( diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index 62b0a8cf8..f5988f1dd 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -116,7 +116,7 @@ async def main(): uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines, verify=False)) - def testNoSpacesAroundPowerOparator(self): + def testNoSpacesAroundPowerOperator(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig( diff --git a/yapftests/utils.py b/yapftests/utils.py index 0d4cbff0d..268b8c43a 100644 --- a/yapftests/utils.py +++ b/yapftests/utils.py @@ -34,13 +34,13 @@ def stdout_redirector(stream): # pylint: disable=invalid-name # NamedTemporaryFile is useless because on Windows the temporary file would be # created with O_TEMPORARY, which would not allow the file to be opened a # second time, even by the same process, unless the same flag is used. -# Thus we provide a simplifed version ourselfs. +# Thus we provide a simplified version ourselves. # # Note: returns a tuple of (io.file_obj, file_path), instead of a file_obj with # a .name attribute # # Note: `buffering` is set to -1 despite documentation of NamedTemporaryFile -# says None. This is probably a problem with the python documenation. +# says None. This is probably a problem with the python documentation. @contextlib.contextmanager def NamedTempFile(mode='w+b', buffering=-1, From cb3d682454b1c33c1c0b149dc040bd2d5092c4c6 Mon Sep 17 00:00:00 2001 From: Caio Ariede Date: Wed, 24 Jan 2018 11:53:55 -0200 Subject: [PATCH 231/719] Ignore files earlier --- yapf/yapflib/file_resources.py | 34 +++++++++++++------- yapftests/file_resources_test.py | 55 ++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 11 deletions(-) diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index a84d28352..5468ced43 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -114,31 +114,43 @@ def LineEnding(lines): def _FindPythonFiles(filenames, recursive, exclude): """Find all Python files.""" + if exclude and any(e.startswith('./') for e in exclude): + raise errors.YapfError("path in '--exclude' should not start with ./") + python_files = [] for filename in filenames: + if filename != '.' and exclude and IsIgnored(filename, exclude): + continue if os.path.isdir(filename): if recursive: # TODO(morbo): Look into a version of os.walk that can handle recursion. - python_files.extend( - os.path.join(dirpath, f) - for dirpath, _, filelist in os.walk(filename) - for f in filelist - if IsPythonFile(os.path.join(dirpath, f))) + excluded_dirs = [] + for dirpath, _, filelist in os.walk(filename): + if dirpath != '.' and exclude and IsIgnored(dirpath, exclude): + excluded_dirs.append(dirpath) + continue + elif any(dirpath.startswith(e) for e in excluded_dirs): + continue + for f in filelist: + filepath = os.path.join(dirpath, f) + if exclude and IsIgnored(filepath, exclude): + continue + if IsPythonFile(filepath): + python_files.append(filepath) else: raise errors.YapfError( "directory specified without '--recursive' flag: %s" % filename) elif os.path.isfile(filename): python_files.append(filename) - if exclude: - return [ - f for f in python_files - if not any(fnmatch.fnmatch(f, p) for p in exclude) - ] - return python_files +def IsIgnored(path, exclude): + """Return True if filename matches any patterns in exclude.""" + return any(fnmatch.fnmatch(path.lstrip('./'), e.rstrip('/')) for e in exclude) + + def IsPythonFile(filename): """Return True if filename is a Python file.""" if os.path.splitext(filename)[1] == '.py': diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index be7f32847..4440e074b 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -62,9 +62,11 @@ class GetCommandLineFilesTest(unittest.TestCase): def setUp(self): self.test_tmpdir = tempfile.mkdtemp() + self.old_dir = os.getcwd() def tearDown(self): shutil.rmtree(self.test_tmpdir) + os.chdir(self.old_dir) def _make_test_dir(self, name): fullpath = os.path.normpath(os.path.join(self.test_tmpdir, name)) @@ -136,6 +138,43 @@ def test_recursive_find_in_dir_with_exclude(self): os.path.join(tdir2, 'testfile2.py'), ])) + def test_find_with_excluded_dirs(self): + tdir1 = self._make_test_dir('test1') + tdir2 = self._make_test_dir('test2/testinner/') + tdir3 = self._make_test_dir('test3/foo/bar/bas/xxx') + files = [ + os.path.join(tdir1, 'testfile1.py'), + os.path.join(tdir2, 'testfile2.py'), + os.path.join(tdir3, 'testfile3.py'), + ] + _touch_files(files) + + os.chdir(self.test_tmpdir) + + found = sorted( + file_resources.GetCommandLineFiles( + ['test1', 'test2', 'test3'], + recursive=True, + exclude=[ + 'test1', + 'test2/testinner/', + ])) + + self.assertEqual(found, ['test3/foo/bar/bas/xxx/testfile3.py']) + + found = sorted( + file_resources.GetCommandLineFiles( + ['.'], recursive=True, exclude=[ + 'test1', + 'test3', + ])) + + self.assertEqual(found, ['./test2/testinner/testfile2.py']) + + def test_find_with_excluded_current_dir(self): + with self.assertRaises(errors.YapfError): + file_resources.GetCommandLineFiles([], False, exclude=['./z']) + class IsPythonFileTest(unittest.TestCase): @@ -180,6 +219,22 @@ def test_with_invalid_encoding(self): self.assertFalse(file_resources.IsPythonFile(file1)) +class IsIgnoredTest(unittest.TestCase): + + def test_root_path(self): + self.assertTrue(file_resources.IsIgnored('media', ['media'])) + self.assertFalse(file_resources.IsIgnored('media', ['media/*'])) + + def test_sub_path(self): + self.assertTrue(file_resources.IsIgnored('media/a', ['*/a'])) + self.assertTrue(file_resources.IsIgnored('media/b', ['media/*'])) + self.assertTrue(file_resources.IsIgnored('media/b/c', ['*/*/c'])) + + def test_trailing_slash(self): + self.assertTrue(file_resources.IsIgnored('z', ['z'])) + self.assertTrue(file_resources.IsIgnored('z', ['z/'])) + + class BufferedByteStream(object): def __init__(self): From 34285c59d454716c063a08eda4e7c26157013ba1 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 24 Jan 2018 11:19:24 -0800 Subject: [PATCH 232/719] Update with recent changes. --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 7e91453a6..e7086b56f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,8 @@ # This project adheres to [Semantic Versioning](http://semver.org/). ## [0.20.2] UNRELEASED +### Changed +- Improve the speed at which files are excluded by ignoring them earlier. ### Fixed - Use tabs when constructing a continuation line when `USE_TABS` is enabled. From 44dfdc50fec5cdb43480823dc459fe5a433db2ef Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 24 Jan 2018 12:35:26 -0800 Subject: [PATCH 233/719] Don't split after an unpacking op in a dict entry. Closes #504 --- CHANGELOG | 3 +++ yapf/yapflib/subtype_assigner.py | 37 +++++++++++++++------------ yapftests/reformatter_python3_test.py | 24 +++++++++++++++++ 3 files changed, 47 insertions(+), 17 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e7086b56f..0bb3857f7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,9 @@ - Improve the speed at which files are excluded by ignoring them earlier. ### Fixed - Use tabs when constructing a continuation line when `USE_TABS` is enabled. +- A dictionary entry may not end in a colon, but may be an "unpacking" + operation: `**foo`. Take that into accound and don't split after the + unpacking operator. ## [0.20.1] 2018-01-13 ### Fixed diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 4fec1e98f..8d3b7f44e 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -80,28 +80,31 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name if not comp_for and dict_maker: last_was_colon = False + unpacking = False for child in node.children: - if dict_maker: - if pytree_utils.NodeName(child) == 'DOUBLESTAR': + if pytree_utils.NodeName(child) == 'DOUBLESTAR': + _AppendFirstLeafTokenSubtype(child, + format_token.Subtype.KWARGS_STAR_STAR) + if last_was_colon: + if style.Get('INDENT_DICTIONARY_VALUE'): + _InsertPseudoParentheses(child) + else: _AppendFirstLeafTokenSubtype(child, - format_token.Subtype.KWARGS_STAR_STAR) - if last_was_colon: - if style.Get('INDENT_DICTIONARY_VALUE'): - _InsertPseudoParentheses(child) - else: - _AppendFirstLeafTokenSubtype( - child, format_token.Subtype.DICTIONARY_VALUE) - elif ( - child is not None and - (isinstance(child, pytree.Node) or - (not child.value.startswith('#') and child.value not in '{:,'))): - # Mark the first leaf of a key entry as a DICTIONARY_KEY. We - # normally want to split before them if the dictionary cannot exist - # on a single line. + format_token.Subtype.DICTIONARY_VALUE) + elif (isinstance(child, pytree.Node) or + (not child.value.startswith('#') and child.value not in '{:,')): + # Mark the first leaf of a key entry as a DICTIONARY_KEY. We + # normally want to split before them if the dictionary cannot exist + # on a single line. + if not unpacking or _GetFirstLeafNode(child).value == '**': _AppendFirstLeafTokenSubtype(child, format_token.Subtype.DICTIONARY_KEY) - _AppendSubtypeRec(child, format_token.Subtype.DICTIONARY_KEY_PART) + _AppendSubtypeRec(child, format_token.Subtype.DICTIONARY_KEY_PART) last_was_colon = pytree_utils.NodeName(child) == 'COLON' + if pytree_utils.NodeName(child) == 'DOUBLESTAR': + unpacking = True + elif last_was_colon: + unpacking = False def Visit_expr_stmt(self, node): # pylint: disable=invalid-name # expr_stmt ::= testlist_star_expr (augassign (yield_expr|testlist) diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index f5988f1dd..fa68c6610 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -330,6 +330,30 @@ def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): finally: style.SetGlobalStyle(style.CreatePEP8Style()) + def testDictUnpacking(self): + if sys.version_info[1] < 5: + return + unformatted_code = """\ +class Foo: + def foo(self): + foofoofoofoofoofoofoofoo('foofoofoofoofoo', { + + 'foo': 'foo', + + **foofoofoo + }) +""" + expected_formatted_code = """\ +class Foo: + def foo(self): + foofoofoofoofoofoofoofoo('foofoofoofoofoo', { + 'foo': 'foo', + **foofoofoo + }) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From e8113755f7a3d5ceaa73771df078545008296455 Mon Sep 17 00:00:00 2001 From: isabelacalinoiu Date: Wed, 24 Jan 2018 17:32:09 +0100 Subject: [PATCH 234/719] # This is a combination of 4 commits. # This is the 1st commit message: Allow single-line dictionaries. # The commit message #2 will be skipped: # Update reformatter_basic_test.py # The commit message #3 will be skipped: # Update reformatter_buganizer_test.py # The commit message #4 will be skipped: # Update reformatter_basic_test.py --- yapf/yapflib/format_decision_state.py | 22 +++++++++++++----- yapftests/reformatter_basic_test.py | 6 ++--- yapftests/reformatter_buganizer_test.py | 30 ++++++++++++++++++++----- 3 files changed, 44 insertions(+), 14 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index f29002156..689eba6f3 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -293,14 +293,13 @@ def SurroundedByParens(token): # This is a dictionary that's an argument to a function. if (self._FitsOnLine(previous, previous.matching_bracket) and previous.matching_bracket.next_token and - not previous.matching_bracket.next_token.ClosesScope() and (not opening.matching_bracket.next_token or - opening.matching_bracket.next_token.value != '.')): + opening.matching_bracket.next_token.value != '.') and + _ScopeHasNoCommas(previous)): # Don't split before the key if: # - The dictionary fits on a line, and - # - The dictionary brackets don't have a closing scope after - # them, and - # - The function call isn't part of a builder-style call. + # - The function call isn't part of a builder-style call and + # - The dictionary has one entry and no trailing comma return False return True @@ -931,6 +930,19 @@ def _IsSingleElementTuple(token): return num_commas == 1 +def _ScopeHasNoCommas(token): + close = token.matching_bracket + token = token.next_token + while token != close: + if token.value == ',': + return False + if token.OpensScope(): + token = token.matching_bracket + else: + token = token.next_token + return True + + class _ParenState(object): """Maintains the state of the bracket enclosures. diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index be8ede644..b2bd834c8 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2115,9 +2115,9 @@ def testDictionaryElementsOnOneLine(self): code = textwrap.dedent("""\ class _(): - @mock.patch.dict(os.environ, { - 'HTTP_' + xsrf._XSRF_TOKEN_HEADER.replace('-', '_'): 'atoken' - }) + @mock.patch.dict( + os.environ, + {'HTTP_' + xsrf._XSRF_TOKEN_HEADER.replace('-', '_'): 'atoken'}) def _(): pass diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 3689e6893..0d9f1142e 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -53,15 +53,11 @@ def _(): (Gauge( metric='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', group_by=group_by + ['metric:process_name'], - metric_filter={ - 'metric:process_name': process_name_re - }), + metric_filter={'metric:process_name': process_name_re}), Gauge( metric='bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', group_by=group_by + ['metric:process_name'], - metric_filter={ - 'metric:process_name': process_name_re - })) + metric_filter={'metric:process_name': process_name_re})) | expr.Join( left_name='start', left_default=0, right_name='end', right_default=0) | m.Point( @@ -1741,6 +1737,28 @@ def testB13900309(self): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB67935687(self): + code = textwrap.dedent("""\ + Fetch( + Raw('monarch.BorgTask', '/union/row_operator_action_delay'), + {'borg_user': self.borg_user}) + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + unformatted_code = textwrap.dedent("""\ + shelf_renderer.expand_text = text.translate_to_unicode( + expand_text % { + 'creator': creator + }) + """) + expected_formatted_code = textwrap.dedent("""\ + shelf_renderer.expand_text = text.translate_to_unicode( + expand_text % {'creator': creator}) + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From 94fac9837296e4e273a72e98e6cb4f0967b53f67 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 25 Jan 2018 22:22:31 -0800 Subject: [PATCH 235/719] Allow single-line dictionaries. --- CHANGELOG | 1 + yapf/yapflib/format_decision_state.py | 1 + yapftests/reformatter_basic_test.py | 2 +- yapftests/reformatter_buganizer_test.py | 2 +- yapftests/style_test.py | 10 ++++------ yapftests/yapf_test.py | 4 +--- 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0bb3857f7..c7cd81298 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,7 @@ ## [0.20.2] UNRELEASED ### Changed - Improve the speed at which files are excluded by ignoring them earlier. +- Allow dictionaries to stay on a single line if they only have one entry ### Fixed - Use tabs when constructing a continuation line when `USE_TABS` is enabled. - A dictionary entry may not end in a colon, but may be an "unpacking" diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 689eba6f3..0d022d444 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -931,6 +931,7 @@ def _IsSingleElementTuple(token): def _ScopeHasNoCommas(token): + """Check if the scope has no commas.""" close = token.matching_bracket token = token.next_token while token != close: diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index b2bd834c8..a1ca77946 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2116,7 +2116,7 @@ def testDictionaryElementsOnOneLine(self): class _(): @mock.patch.dict( - os.environ, + os.environ, {'HTTP_' + xsrf._XSRF_TOKEN_HEADER.replace('-', '_'): 'atoken'}) def _(): pass diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 0d9f1142e..e04c9621f 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -1759,6 +1759,6 @@ def testB67935687(self): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - + if __name__ == '__main__': unittest.main() diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 7c3f9747e..13b96717f 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -225,13 +225,11 @@ def testDefaultBasedOnStyle(self): def testDefaultBasedOnStyleBadDict(self): self.assertRaisesRegexp(style.StyleConfigError, 'Unknown style option', - style.CreateStyleFromConfig, { - 'based_on_styl': 'pep8' - }) + style.CreateStyleFromConfig, + {'based_on_styl': 'pep8'}) self.assertRaisesRegexp(style.StyleConfigError, 'not a valid', - style.CreateStyleFromConfig, { - 'INDENT_WIDTH': 'FOUR' - }) + style.CreateStyleFromConfig, + {'INDENT_WIDTH': 'FOUR'}) class StyleFromCommandLine(unittest.TestCase): diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 0ae6a0dcc..5f3d3fc64 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1296,9 +1296,7 @@ def testCP936Encoding(self): self.assertYapfReformats( unformatted_code, expected_formatted_code, - env={ - 'PYTHONIOENCODING': 'cp936' - }) + env={'PYTHONIOENCODING': 'cp936'}) class BadInputTest(unittest.TestCase): From 33167986946cec3096f071a38c3dc119125dee38 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 26 Jan 2018 15:08:07 -0800 Subject: [PATCH 236/719] Update to specify Python 3.6.4 --- README.rst | 3 ++- setup.py | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 085182f15..21d06920e 100644 --- a/README.rst +++ b/README.rst @@ -78,7 +78,8 @@ possible to run: Python versions =============== -YAPF supports Python 2.7 and 3.4.1+. +YAPF supports Python 2.7 and 3.6.4+. (Note that some Python 3 features may fail +to parse with Python versions before 3.6.4.) YAPF requires the code it formats to be valid Python for the version YAPF itself runs under. Therefore, if you format Python 3 code with YAPF, run YAPF itself diff --git a/setup.py b/setup.py index da4bf0907..21e94707d 100644 --- a/setup.py +++ b/setup.py @@ -60,8 +60,7 @@ def run(self): 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Quality Assurance', ], From 89fe8ac20d5a205dc2b781d7134043214465859c Mon Sep 17 00:00:00 2001 From: Matt Goldberg Date: Sat, 27 Jan 2018 19:30:26 -0800 Subject: [PATCH 237/719] gets the default style when the --style-help flag is passed --- yapf/__init__.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 51e01933d..caa43cf4a 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -133,8 +133,12 @@ def main(argv): print('yapf {}'.format(__version__)) return 0 + style_config = args.style + if args.style_help: - style.SetGlobalStyle(style.CreateStyleFromConfig(args.style)) + if style_config is None and not args.no_local_style: + style_config = file_resources.GetDefaultStyleForDir(os.getcwd()) + style.SetGlobalStyle(style.CreateStyleFromConfig(style_config)) print('[style]') for option, docstring in sorted(style.Help().items()): for line in docstring.splitlines(): @@ -166,7 +170,6 @@ def main(argv): except EOFError: break - style_config = args.style if style_config is None and not args.no_local_style: style_config = file_resources.GetDefaultStyleForDir(os.getcwd()) From 940e314609cacaa4b1bcc388b31146181b256357 Mon Sep 17 00:00:00 2001 From: Alan Du Date: Tue, 30 Jan 2018 18:30:26 -0500 Subject: [PATCH 238/719] Expand list of allowable string prefixes --- yapf/yapflib/format_token.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index d225853b0..98417a270 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -273,9 +273,18 @@ def is_string(self): @property @py3compat.lru_cache() def is_multiline_string(self): + if py3compat.PY3: + prefix = "(" + prefix += "r|u|R|U|f|F|fr|Fr|fR|FR|rf|rF|Rf|RF" # strings + prefix += "|b|B|br|Br|bR|BR|rb|rB|Rb|RB" # bytes + prefix += ")?" + else: + prefix = "[uUbB]?[rR]?" + + regex = r'^{prefix}(?P"""|\'\'\').*(?P=delim)$'.format( + prefix=prefix) return (self.is_string and - re.match(r'^[uUbB]?[rR]?(?P"""|\'\'\').*(?P=delim)$', - self.value, re.DOTALL) is not None) + re.match(regex, self.value, re.DOTALL) is not None) @property @py3compat.lru_cache() From 0d7a6b1c573e03fb82803168fcae9884da617988 Mon Sep 17 00:00:00 2001 From: Alan Du Date: Tue, 30 Jan 2018 23:47:16 -0500 Subject: [PATCH 239/719] Add a test case --- yapftests/format_token_test.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index b3c0dc2aa..9f879946e 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -19,6 +19,7 @@ from lib2to3.pgen2 import token from yapf.yapflib import format_token +from yapf.yapflib import py3compat class FormatTokenTest(unittest.TestCase): @@ -32,6 +33,16 @@ def testSimple(self): self.assertEqual("FormatToken(name=COMMENT, value=# A comment)", str(tok)) self.assertTrue(tok.is_comment) + def testIsMultilineString(self): + tok = format_token.FormatToken(pytree.Leaf(token.STRING, '"""hello"""')) + self.assertTrue(tok.is_multiline_string) + + tok = format_token.FormatToken(pytree.Leaf(token.STRING, 'r"""hello"""')) + self.assertTrue(tok.is_multiline_string) + + tok = format_token.FormatToken(pytree.Leaf(token.STRING, 'f"""hello"""')) + self.assertEqual(py3compat.PY3, tok.is_multiline_string) + if __name__ == "__main__": unittest.main() From ba583fc3b07df5b5e49caee6456da186bcde8211 Mon Sep 17 00:00:00 2001 From: Alan Du Date: Wed, 31 Jan 2018 00:05:55 -0500 Subject: [PATCH 240/719] YAPF --- yapf/yapflib/format_token.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 98417a270..d86c16d5b 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -281,8 +281,7 @@ def is_multiline_string(self): else: prefix = "[uUbB]?[rR]?" - regex = r'^{prefix}(?P"""|\'\'\').*(?P=delim)$'.format( - prefix=prefix) + regex = r'^{prefix}(?P"""|\'\'\').*(?P=delim)$'.format(prefix=prefix) return (self.is_string and re.match(regex, self.value, re.DOTALL) is not None) From 3d87248c7d6761f44fcddfc28f097488f5632c6f Mon Sep 17 00:00:00 2001 From: Alan Du Date: Wed, 31 Jan 2018 11:39:39 -0500 Subject: [PATCH 241/719] Move Python 3 test --- yapftests/format_token_test.py | 4 ---- yapftests/reformatter_python3_test.py | 13 +++++++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index 9f879946e..f7b613bce 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -19,7 +19,6 @@ from lib2to3.pgen2 import token from yapf.yapflib import format_token -from yapf.yapflib import py3compat class FormatTokenTest(unittest.TestCase): @@ -40,9 +39,6 @@ def testIsMultilineString(self): tok = format_token.FormatToken(pytree.Leaf(token.STRING, 'r"""hello"""')) self.assertTrue(tok.is_multiline_string) - tok = format_token.FormatToken(pytree.Leaf(token.STRING, 'f"""hello"""')) - self.assertEqual(py3compat.PY3, tok.is_multiline_string) - if __name__ == "__main__": unittest.main() diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index fa68c6610..7ff01ebaf 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -354,6 +354,19 @@ def foo(self): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testMultilineFormatString(self): + if sys.version_info[1] < 6: + return + code = """\ +# yapf: disable +(f''' + ''') +# yapf: enable +""" + # https://github.com/google/yapf/issues/513 + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From de22a0f73f87115bdb06d3567800c5ed01b1b929 Mon Sep 17 00:00:00 2001 From: Matt Goldberg Date: Wed, 31 Jan 2018 09:17:56 -0800 Subject: [PATCH 242/719] four spaces -> two spaces of indentation --- yapf/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index caa43cf4a..abf59fc7e 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -137,7 +137,7 @@ def main(argv): if args.style_help: if style_config is None and not args.no_local_style: - style_config = file_resources.GetDefaultStyleForDir(os.getcwd()) + style_config = file_resources.GetDefaultStyleForDir(os.getcwd()) style.SetGlobalStyle(style.CreateStyleFromConfig(style_config)) print('[style]') for option, docstring in sorted(style.Help().items()): From 0fbedc17ab55f814c686c4e04fcc9d850b10cdf8 Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Wed, 31 Jan 2018 09:57:45 -0500 Subject: [PATCH 243/719] Support python2 unicode strings in CreateStyleFromConfig Closes #517 --- yapf/yapflib/py3compat.py | 2 ++ yapf/yapflib/style.py | 2 +- yapftests/style_test.py | 8 ++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py index 4bb8ebeb1..c66d6c681 100644 --- a/yapf/yapflib/py3compat.py +++ b/yapf/yapflib/py3compat.py @@ -98,8 +98,10 @@ def EncodeAndWriteToStdout(s, encoding='utf-8'): if PY3: + basestring = str unicode = str # pylint: disable=redefined-builtin,invalid-name else: + basestring = basestring def unicode(s): # pylint: disable=invalid-name """Force conversion of s to unicode.""" diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 02b6d0b31..e4df1ba2c 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -438,7 +438,7 @@ def GlobalStyles(): return _GLOBAL_STYLE_FACTORY() if isinstance(style_config, dict): config = _CreateConfigParserFromConfigDict(style_config) - elif isinstance(style_config, str): + elif isinstance(style_config, py3compat.basestring): style_factory = _STYLE_NAME_TO_FACTORY.get(style_config.lower()) if style_factory is not None: return style_factory() diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 13b96717f..7f9a715e4 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -254,6 +254,14 @@ def testDefaultBasedOnStyleNotStrict(self): self.assertTrue(_LooksLikeChromiumStyle(cfg)) self.assertEqual(cfg['INDENT_WIDTH'], 2) + def testDefaultBasedOnExplicitlyUnicodeTypeString(self): + cfg = style.CreateStyleFromConfig(u'{}') + self.assertIsInstance(cfg, dict) + + def testDefaultBasedOnDetaultTypeString(self): + cfg = style.CreateStyleFromConfig('{}') + self.assertIsInstance(cfg, dict) + def testDefaultBasedOnStyleBadString(self): self.assertRaisesRegexp(style.StyleConfigError, 'Unknown style option', style.CreateStyleFromConfig, From d2e9d03b9b17fda747ddde0fbdc81b48c9b36dbc Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 12 Feb 2018 13:22:47 -0800 Subject: [PATCH 244/719] Bump version to v0.20.2 --- yapf/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index abf59fc7e..d8fd680f6 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.20.1' +__version__ = '0.20.2' def main(argv): From cc3fea56e9c4ab47a1ef8a57f03c27b7ac68e72a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 12 Feb 2018 13:22:47 -0800 Subject: [PATCH 245/719] Bump version to v0.20.2 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c7cd81298..e83d3ab0f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.20.2] UNRELEASED +## [0.20.2] 2018-02-12 ### Changed - Improve the speed at which files are excluded by ignoring them earlier. - Allow dictionaries to stay on a single line if they only have one entry diff --git a/yapf/__init__.py b/yapf/__init__.py index abf59fc7e..d8fd680f6 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.20.1' +__version__ = '0.20.2' def main(argv): From 11ea6e18d4668b7d1ab6a19f8822909f28cf2b36 Mon Sep 17 00:00:00 2001 From: Patryk Zawadzki Date: Tue, 13 Feb 2018 16:31:25 +0100 Subject: [PATCH 246/719] Introduce a SPLIT_BEFORE_ENDING_BRACKET knob This controls whether closing brackets get a separate line in multiline literals. The default is enabled: foo = { 'a': 1 } However it can now be disabled: foo = { 'a': 1} --- CHANGELOG | 6 ++++++ README.rst | 4 ++++ yapf/yapflib/format_decision_state.py | 3 ++- yapf/yapflib/style.py | 5 +++++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index e83d3ab0f..67a7440f6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,12 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.20.3] UNRELEASED +### Added +- Introduce a new option of formatting multiline literals. Add + `SPLIT_BEFORE_CLOSING_BRACKET` knob to control whether closing bracket should + get their own line. + ## [0.20.2] 2018-02-12 ### Changed - Improve the speed at which files are excluded by ignoring them earlier. diff --git a/README.rst b/README.rst index 21d06920e..86ab6c68f 100644 --- a/README.rst +++ b/README.rst @@ -439,6 +439,10 @@ Knobs Set to ``True`` to prefer splitting before ``&``, ``|`` or ``^`` rather than after. +``SPLIT_BEFORE_CLOSING_BRACKET`` + Split before the closing bracket if a list or dict literal doesn't fit on + a single line. + ``SPLIT_BEFORE_DICT_SET_GENERATOR`` Split before a dictionary or set generator (comp_for). For example, note the split before the ``for``: diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 0d022d444..ce360df36 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -177,7 +177,8 @@ def MustSplit(self): if not previous: return False - if self.stack[-1].split_before_closing_bracket and current.value in '}]': + if (self.stack[-1].split_before_closing_bracket and + current.value in '}]' and style.Get('SPLIT_BEFORE_CLOSING_BRACKET')): # Split before the closing bracket if we can. return current.node_split_penalty != split_penalty.UNBREAKABLE diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index e4df1ba2c..f8865375c 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -158,6 +158,9 @@ def method(): SPLIT_BEFORE_BITWISE_OPERATOR=textwrap.dedent("""\ Set to True to prefer splitting before '&', '|' or '^' rather than after."""), + SPLIT_BEFORE_CLOSING_BRACKET=textwrap.dedent("""\ + Split before the closing bracket if a list or dict literal doesn't fit on + a single line."""), SPLIT_BEFORE_DICT_SET_GENERATOR=textwrap.dedent("""\ Split before a dictionary or set generator (comp_for). For example, note the split before the 'for': @@ -257,6 +260,7 @@ def CreatePEP8Style(): SPACES_BEFORE_COMMENT=2, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False, SPLIT_BEFORE_BITWISE_OPERATOR=True, + SPLIT_BEFORE_CLOSING_BRACKET=True, SPLIT_BEFORE_DICT_SET_GENERATOR=True, SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=False, SPLIT_BEFORE_FIRST_ARGUMENT=False, @@ -387,6 +391,7 @@ def _BoolConverter(s): SPACES_BEFORE_COMMENT=int, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter, SPLIT_BEFORE_BITWISE_OPERATOR=_BoolConverter, + SPLIT_BEFORE_CLOSING_BRACKET=_BoolConverter, SPLIT_BEFORE_DICT_SET_GENERATOR=_BoolConverter, SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=_BoolConverter, SPLIT_BEFORE_FIRST_ARGUMENT=_BoolConverter, From 1dcc932367887e4feab3b3ec982d3036cc3fb75d Mon Sep 17 00:00:00 2001 From: Markus Gerstel Date: Wed, 14 Feb 2018 17:07:35 +0000 Subject: [PATCH 247/719] Add knob BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION to modify the number of blank lines around top level function and class definitions. Closes #527 --- CHANGELOG | 2 ++ README.rst | 13 +++++++++++++ yapf/yapflib/blank_line_calculator.py | 3 ++- yapf/yapflib/reformatter.py | 9 +++++---- yapf/yapflib/style.py | 5 +++++ 5 files changed, 27 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 67a7440f6..25c7e0f44 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,8 @@ - Introduce a new option of formatting multiline literals. Add `SPLIT_BEFORE_CLOSING_BRACKET` knob to control whether closing bracket should get their own line. +- Add 'BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION' knob to control the number + of blank lines between top-level function and class definitions. ## [0.20.2] 2018-02-12 ### Changed diff --git a/README.rst b/README.rst index 86ab6c68f..79adc36cf 100644 --- a/README.rst +++ b/README.rst @@ -325,6 +325,19 @@ Knobs ``BLANK_LINE_BEFORE_CLASS_DOCSTRING`` Insert a blank line before a class-level docstring. +``BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION`` + Sets the number of desired blank lines surrounding top-level function and + class definitions. For example: + + .. code-block:: python + + class Foo: + pass + # <------ having two blank lines here + # <------ is the default setting + class Bar: + pass + ``COALESCE_BRACKETS`` Do not split consecutive brackets. Only relevant when ``DEDENT_CLOSING_BRACKETS`` is set. For example: diff --git a/yapf/yapflib/blank_line_calculator.py b/yapf/yapflib/blank_line_calculator.py index 4c62e8be6..0880a8039 100644 --- a/yapf/yapflib/blank_line_calculator.py +++ b/yapf/yapflib/blank_line_calculator.py @@ -27,6 +27,7 @@ from yapf.yapflib import py3compat from yapf.yapflib import pytree_utils from yapf.yapflib import pytree_visitor +from yapf.yapflib import style _NO_BLANK_LINES = 1 _ONE_BLANK_LINE = 2 @@ -155,7 +156,7 @@ def _GetNumNewlines(self, node): if self.last_was_decorator: return _NO_BLANK_LINES elif self._IsTopLevel(node): - return _TWO_BLANK_LINES + return 1 + style.Get('BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION') return _ONE_BLANK_LINE def _SetNumNewlines(self, node, num_newlines): diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 58a72591a..a4965ab33 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -479,9 +479,9 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, prev_last_token = prev_uwline.last if prev_last_token.is_docstring: if (not indent_depth and first_token.value in {'class', 'def', 'async'}): - # Separate a class or function from the module-level docstring with two - # blank lines. - return TWO_BLANK_LINES + # Separate a class or function from the module-level docstring with + # appropriate number of blank lines. + return 1 + style.Get('BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION') if _NoBlankLinesBeforeCurrentToken(prev_last_token.value, first_token, prev_last_token): return NO_BLANK_LINES @@ -509,7 +509,8 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, if final_lines[index - 1].first.value == '@': final_lines[index].first.AdjustNewlinesBefore(NO_BLANK_LINES) else: - prev_last_token.AdjustNewlinesBefore(TWO_BLANK_LINES) + prev_last_token.AdjustNewlinesBefore( + 1 + style.Get('BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION')) if first_token.newlines is not None: pytree_utils.SetNodeAnnotation( first_token.node, pytree_utils.Annotation.NEWLINES, None) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index f8865375c..057b7b984 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -71,6 +71,9 @@ def method(): ..."""), BLANK_LINE_BEFORE_CLASS_DOCSTRING=textwrap.dedent("""\ Insert a blank line before a class-level docstring."""), + BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=textwrap.dedent("""\ + Number of blank lines surrounding top-level function and class + definitions."""), COALESCE_BRACKETS=textwrap.dedent("""\ Do not split consecutive brackets. Only relevant when dedent_closing_brackets is set. For example: @@ -243,6 +246,7 @@ def CreatePEP8Style(): ALLOW_SPLIT_BEFORE_DICT_VALUE=True, BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=False, BLANK_LINE_BEFORE_CLASS_DOCSTRING=False, + BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=2, COALESCE_BRACKETS=False, COLUMN_LIMIT=79, CONTINUATION_INDENT_WIDTH=4, @@ -374,6 +378,7 @@ def _BoolConverter(s): ALLOW_SPLIT_BEFORE_DICT_VALUE=_BoolConverter, BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=_BoolConverter, BLANK_LINE_BEFORE_CLASS_DOCSTRING=_BoolConverter, + BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=int, COALESCE_BRACKETS=_BoolConverter, COLUMN_LIMIT=int, CONTINUATION_INDENT_WIDTH=int, From c17e4dfb9a9ade10237585541f8fee8e817bd420 Mon Sep 17 00:00:00 2001 From: Yinyin L Date: Mon, 5 Mar 2018 02:04:34 +0800 Subject: [PATCH 248/719] Added `CONTINUATION_ALIGN_STYLE` knob For choosing continuation alignment style when `USE_TABS` is enabled. --- CHANGELOG | 2 ++ README.rst | 14 +++++++++ yapf/yapflib/format_token.py | 29 +++++++++++++++++- yapf/yapflib/style.py | 29 ++++++++++++++++++ yapftests/format_token_test.py | 42 +++++++++++++++++++++++++ yapftests/style_test.py | 14 +++++++++ yapftests/yapf_test.py | 56 ++++++++++++++++++++++++++++++++++ 7 files changed, 185 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 67a7440f6..87bc3e7a3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,8 @@ - Introduce a new option of formatting multiline literals. Add `SPLIT_BEFORE_CLOSING_BRACKET` knob to control whether closing bracket should get their own line. +- Added `CONTINUATION_ALIGN_STYLE` knob to choose continuation alignment style + when `USE_TABS` is enabled. ## [0.20.2] 2018-02-12 ### Changed diff --git a/README.rst b/README.rst index 86ab6c68f..7e4bd3d84 100644 --- a/README.rst +++ b/README.rst @@ -351,6 +351,20 @@ Knobs ``COLUMN_LIMIT`` The column limit (or max line-length) +``CONTINUATION_ALIGN_STYLE`` + The style for continuation alignment. Possible values are: + + - SPACE: Use spaces for continuation alignment. This is default behavior. + - FIXED: Use fixed number (CONTINUATION_INDENT_WIDTH) of columns + (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs) for continuation + alignment. + - VALIGN-RIGHT: Vertically align continuation lines with indent characters. + Slightly right (one more indent character) if cannot vertically align + continuation lines with indent characters. + + For options ``FIXED``, and ``VALIGN-RIGHT`` are only available when + ``USE_TABS`` is enabled. + ``CONTINUATION_INDENT_WIDTH`` Indent width used for line continuations. diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index d86c16d5b..474e9b124 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -58,6 +58,28 @@ class Subtype(object): TYPED_NAME_ARG_LIST = 20 +def _TabbedContinuationAlignPadding(spaces, align_style, tab_width, + continuation_indent_width): + """Build padding string for continuation alignment in tabbed indentation. + + Arguments: + spaces: (int) The number of spaces to place before the token for alignment. + align_style: (str) The alignment style for continuation lines. + tab_width: (int) Number of columns of each tab character. + continuation_indent_width: (int) Indent columns for line continuations. + + Returns: + A padding string for alignment with style specified by align_style option. + """ + if align_style == 'FIXED': + if spaces > 0: + return '\t' * int(continuation_indent_width / tab_width) + return '' + elif align_style == 'VALIGN-RIGHT': + return '\t' * int((spaces + tab_width - 1) / tab_width) + return ' ' * spaces + + class FormatToken(object): """A wrapper around pytree Leaf nodes. @@ -123,7 +145,12 @@ def AddWhitespacePrefix(self, newlines_before, spaces=0, indent_level=0): indent_level: (int) The indentation level. """ if style.Get('USE_TABS'): - indent_before = '\t' * indent_level + ' ' * spaces + if newlines_before > 0: + indent_before = '\t' * indent_level + _TabbedContinuationAlignPadding( + spaces, style.Get('CONTINUATION_ALIGN_STYLE'), + style.Get('INDENT_WIDTH'), style.Get('CONTINUATION_INDENT_WIDTH')) + else: + indent_before = '\t' * indent_level + ' ' * spaces else: indent_before = ( ' ' * indent_level * style.Get('INDENT_WIDTH') + ' ' * spaces) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index f8865375c..9950f8110 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -90,6 +90,21 @@ def method(): })"""), COLUMN_LIMIT=textwrap.dedent("""\ The column limit."""), + CONTINUATION_ALIGN_STYLE=textwrap.dedent("""\ + The style for continuation alignment. Possible values are: + + - SPACE: Use spaces for continuation alignment. This is default behavior. + - FIXED: Use fixed number (CONTINUATION_INDENT_WIDTH) of columns + (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs) for continuation + alignment. + - LESS: Slightly left if cannot vertically align continuation lines with + indent characters. + - VALIGN-RIGHT: Vertically align continuation lines with indent + characters. Slightly right (one more indent character) if cannot + vertically align continuation lines with indent characters. + + For options FIXED, and VALIGN-RIGHT are only available when USE_TABS is + enabled."""), CONTINUATION_INDENT_WIDTH=textwrap.dedent("""\ Indent width used for line continuations."""), DEDENT_CLOSING_BRACKETS=textwrap.dedent("""\ @@ -245,6 +260,7 @@ def CreatePEP8Style(): BLANK_LINE_BEFORE_CLASS_DOCSTRING=False, COALESCE_BRACKETS=False, COLUMN_LIMIT=79, + CONTINUATION_ALIGN_STYLE='SPACE', CONTINUATION_INDENT_WIDTH=4, DEDENT_CLOSING_BRACKETS=False, EACH_DICT_ENTRY_ON_SEPARATE_LINE=True, @@ -345,6 +361,18 @@ def _GetStyleFactory(style): return None +def _ContinuationAlignStyleStringConverter(s): + """Option value converter for a continuation align style string.""" + accepted_styles = ('SPACE', 'FIXED', 'VALIGN-RIGHT') + if s: + r = s.upper() + if r not in accepted_styles: + raise ValueError("unknown continuation align style: %r" % (s,)) + else: + r = accepted_styles[0] + return r + + def _StringListConverter(s): """Option value converter for a comma-separated list of strings.""" return [part.strip() for part in s.split(',')] @@ -376,6 +404,7 @@ def _BoolConverter(s): BLANK_LINE_BEFORE_CLASS_DOCSTRING=_BoolConverter, COALESCE_BRACKETS=_BoolConverter, COLUMN_LIMIT=int, + CONTINUATION_ALIGN_STYLE=_ContinuationAlignStyleStringConverter, CONTINUATION_INDENT_WIDTH=int, DEDENT_CLOSING_BRACKETS=_BoolConverter, EACH_DICT_ENTRY_ON_SEPARATE_LINE=_BoolConverter, diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index f7b613bce..3adad4ebb 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -21,6 +21,48 @@ from yapf.yapflib import format_token +class TabbedContinuationAlignPaddingTest(unittest.TestCase): + + def testSpace(self): + align_style = 'SPACE' + + pad = format_token._TabbedContinuationAlignPadding(0, align_style, 2, 4) + self.assertEqual(pad, '') + + pad = format_token._TabbedContinuationAlignPadding(2, align_style, 2, 4) + self.assertEqual(pad, ' ' * 2) + + pad = format_token._TabbedContinuationAlignPadding(5, align_style, 2, 4) + self.assertEqual(pad, ' ' * 5) + + def testFixed(self): + align_style = 'FIXED' + + pad = format_token._TabbedContinuationAlignPadding(0, align_style, 4, 8) + self.assertEqual(pad, '') + + pad = format_token._TabbedContinuationAlignPadding(2, align_style, 4, 8) + self.assertEqual(pad, "\t" * 2) + + pad = format_token._TabbedContinuationAlignPadding(5, align_style, 4, 8) + self.assertEqual(pad, "\t" * 2) + + def testVAlignRight(self): + align_style = 'VALIGN-RIGHT' + + pad = format_token._TabbedContinuationAlignPadding(0, align_style, 4, 8) + self.assertEqual(pad, '') + + pad = format_token._TabbedContinuationAlignPadding(2, align_style, 4, 8) + self.assertEqual(pad, "\t") + + pad = format_token._TabbedContinuationAlignPadding(4, align_style, 4, 8) + self.assertEqual(pad, "\t") + + pad = format_token._TabbedContinuationAlignPadding(5, align_style, 4, 8) + self.assertEqual(pad, "\t" * 2) + + class FormatTokenTest(unittest.TestCase): def testSimple(self): diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 7f9a715e4..694cefaa1 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -26,6 +26,20 @@ class UtilsTest(unittest.TestCase): + def testContinuationAlignStyleStringConverter(self): + self.assertEqual(style._ContinuationAlignStyleStringConverter(''), 'SPACE') + self.assertEqual( + style._ContinuationAlignStyleStringConverter('space'), 'SPACE') + self.assertEqual( + style._ContinuationAlignStyleStringConverter('fixed'), 'FIXED') + self.assertEqual( + style._ContinuationAlignStyleStringConverter('valign-right'), + 'VALIGN-RIGHT') + with self.assertRaises(ValueError) as ctx: + style._ContinuationAlignStyleStringConverter('blahblah') + self.assertTrue( + "unknown continuation align style: 'blahblah'" in str(ctx.exception)) + def testStringListConverter(self): self.assertEqual(style._StringListConverter('foo, bar'), ['foo', 'bar']) self.assertEqual(style._StringListConverter('foo,bar'), ['foo', 'bar']) diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 5f3d3fc64..6df28b60d 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1196,6 +1196,62 @@ def f(): based_on_style = chromium USE_TABS = true INDENT_WIDTH=1 +""" + with utils.TempFileContents(self.test_tmpdir, style_contents) as stylepath: + self.assertYapfReformats( + unformatted_code, + expected_formatted_code, + extra_options=['--style={0}'.format(stylepath)]) + + def testUseTabsContinuationAlignStyleFixed(self): + unformatted_code = """\ +def foo_function(arg1, arg2, arg3): + return ['hello', 'world',] +""" + expected_formatted_code = """\ +def foo_function(arg1, arg2, + arg3): + return [ + 'hello', + 'world', + ] +""" + style_contents = u"""\ +[style] +based_on_style = chromium +USE_TABS = true +COLUMN_LIMIT=32 +INDENT_WIDTH=4 +CONTINUATION_INDENT_WIDTH=8 +CONTINUATION_ALIGN_STYLE = fixed +""" + with utils.TempFileContents(self.test_tmpdir, style_contents) as stylepath: + self.assertYapfReformats( + unformatted_code, + expected_formatted_code, + extra_options=['--style={0}'.format(stylepath)]) + + def testUseTabsContinuationAlignStyleVAlignRight(self): + unformatted_code = """\ +def foo_function(arg1, arg2, arg3): + return ['hello', 'world',] +""" + expected_formatted_code = """\ +def foo_function(arg1, arg2, + arg3): + return [ + 'hello', + 'world', + ] +""" + style_contents = u"""\ +[style] +based_on_style = chromium +USE_TABS = true +COLUMN_LIMIT=32 +INDENT_WIDTH=4 +CONTINUATION_INDENT_WIDTH=8 +CONTINUATION_ALIGN_STYLE = valign-right """ with utils.TempFileContents(self.test_tmpdir, style_contents) as stylepath: self.assertYapfReformats( From 80585cd2db018f779add005789639646c253d2c3 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 14 Mar 2018 23:59:49 -0700 Subject: [PATCH 249/719] Don't split ellipses. Closes #533 --- CHANGELOG | 2 ++ yapf/yapflib/format_decision_state.py | 3 +++ yapf/yapflib/unwrapped_line.py | 3 ++- yapftests/reformatter_python3_test.py | 11 +++++++++++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 87bc3e7a3..486c64fd5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,8 @@ get their own line. - Added `CONTINUATION_ALIGN_STYLE` knob to choose continuation alignment style when `USE_TABS` is enabled. +### Fixed +- Don't split ellipses. ## [0.20.2] 2018-02-12 ### Changed diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index ce360df36..832d67a89 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -161,6 +161,9 @@ def CanSplit(self, must_split): if not style.Get('ALLOW_SPLIT_BEFORE_DICT_VALUE'): return False + if previous and previous.value == '.' and current.value == '.': + return False + return current.can_break_before def MustSplit(self): diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index e7e82c79d..92b986ebf 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -255,7 +255,8 @@ def _SpaceRequiredBetween(left, right): if lval == '.' and rval == 'import': # Space after the '.' in an import statement. return True - if lval == '=' and rval == '.': + if (lval == '=' and rval == '.' and + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN not in left.subtypes): # Space between equal and '.' as in "X = ...". return True if ((right.is_keyword or right.is_name) and diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index 7ff01ebaf..9be6528d5 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -367,6 +367,17 @@ def testMultilineFormatString(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testEllipses(self): + if sys.version_info[1] < 6: + return + code = """\ +def dirichlet(x12345678901234567890123456789012345678901234567890=...) -> None: + return +""" + # https://github.com/google/yapf/issues/533 + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From 67166429f797f4f67cc5bec275785d6569102eed Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 18 Mar 2018 20:42:05 -0700 Subject: [PATCH 250/719] Bump version to v0.21.0 --- CHANGELOG | 2 +- HACKING.rst | 2 +- yapf/__init__.py | 2 +- yapf/yapflib/format_token.py | 11 ++++++----- yapf/yapflib/style.py | 2 +- yapftests/format_token_test.py | 16 ++++++++-------- yapftests/style_test.py | 4 ++-- 7 files changed, 20 insertions(+), 19 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6b47b3267..147f1a0ef 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.20.3] UNRELEASED +## [0.21.0] 2018-03-18 ### Added - Introduce a new option of formatting multiline literals. Add `SPLIT_BEFORE_CLOSING_BRACKET` knob to control whether closing bracket should diff --git a/HACKING.rst b/HACKING.rst index eb1618032..cc27c5ac7 100644 --- a/HACKING.rst +++ b/HACKING.rst @@ -13,7 +13,7 @@ Releasing a new version ----------------------- * Run tests: python setup.py test - [don't forget to run with Python 2.7 and 3.4] + [don't forget to run with Python 2.7 and 3.6] * Bump version in yapf/__init__.py diff --git a/yapf/__init__.py b/yapf/__init__.py index d8fd680f6..0322b31ab 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.20.2' +__version__ = '0.21.0' def main(argv): diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 474e9b124..14899e90d 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -300,13 +300,14 @@ def is_string(self): @property @py3compat.lru_cache() def is_multiline_string(self): + """A multiline string.""" if py3compat.PY3: - prefix = "(" - prefix += "r|u|R|U|f|F|fr|Fr|fR|FR|rf|rF|Rf|RF" # strings - prefix += "|b|B|br|Br|bR|BR|rb|rB|Rb|RB" # bytes - prefix += ")?" + prefix = '(' + prefix += 'r|u|R|U|f|F|fr|Fr|fR|FR|rf|rF|Rf|RF' # strings + prefix += '|b|B|br|Br|bR|BR|rb|rB|Rb|RB' # bytes + prefix += ')?' else: - prefix = "[uUbB]?[rR]?" + prefix = '[uUbB]?[rR]?' regex = r'^{prefix}(?P"""|\'\'\').*(?P=delim)$'.format(prefix=prefix) return (self.is_string and diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 02e0f9419..5f2fdacd8 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -371,7 +371,7 @@ def _ContinuationAlignStyleStringConverter(s): if s: r = s.upper() if r not in accepted_styles: - raise ValueError("unknown continuation align style: %r" % (s,)) + raise ValueError('unknown continuation align style: %r' % (s,)) else: r = accepted_styles[0] return r diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index 3adad4ebb..7dfb82a56 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -42,10 +42,10 @@ def testFixed(self): self.assertEqual(pad, '') pad = format_token._TabbedContinuationAlignPadding(2, align_style, 4, 8) - self.assertEqual(pad, "\t" * 2) + self.assertEqual(pad, '\t' * 2) pad = format_token._TabbedContinuationAlignPadding(5, align_style, 4, 8) - self.assertEqual(pad, "\t" * 2) + self.assertEqual(pad, '\t' * 2) def testVAlignRight(self): align_style = 'VALIGN-RIGHT' @@ -54,13 +54,13 @@ def testVAlignRight(self): self.assertEqual(pad, '') pad = format_token._TabbedContinuationAlignPadding(2, align_style, 4, 8) - self.assertEqual(pad, "\t") + self.assertEqual(pad, '\t') pad = format_token._TabbedContinuationAlignPadding(4, align_style, 4, 8) - self.assertEqual(pad, "\t") + self.assertEqual(pad, '\t') pad = format_token._TabbedContinuationAlignPadding(5, align_style, 4, 8) - self.assertEqual(pad, "\t" * 2) + self.assertEqual(pad, '\t' * 2) class FormatTokenTest(unittest.TestCase): @@ -70,8 +70,8 @@ def testSimple(self): self.assertEqual("FormatToken(name=STRING, value='hello world')", str(tok)) self.assertTrue(tok.is_string) - tok = format_token.FormatToken(pytree.Leaf(token.COMMENT, "# A comment")) - self.assertEqual("FormatToken(name=COMMENT, value=# A comment)", str(tok)) + tok = format_token.FormatToken(pytree.Leaf(token.COMMENT, '# A comment')) + self.assertEqual('FormatToken(name=COMMENT, value=# A comment)', str(tok)) self.assertTrue(tok.is_comment) def testIsMultilineString(self): @@ -82,5 +82,5 @@ def testIsMultilineString(self): self.assertTrue(tok.is_multiline_string) -if __name__ == "__main__": +if __name__ == '__main__': unittest.main() diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 694cefaa1..833efaf9c 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -37,8 +37,8 @@ def testContinuationAlignStyleStringConverter(self): 'VALIGN-RIGHT') with self.assertRaises(ValueError) as ctx: style._ContinuationAlignStyleStringConverter('blahblah') - self.assertTrue( - "unknown continuation align style: 'blahblah'" in str(ctx.exception)) + self.assertIn( + "unknown continuation align style: 'blahblah'", str(ctx.exception)) def testStringListConverter(self): self.assertEqual(style._StringListConverter('foo, bar'), ['foo', 'bar']) From c9c9e982f44cc2f3027f05cf0ae18d677cedc0b7 Mon Sep 17 00:00:00 2001 From: Dan Porter Date: Thu, 22 Mar 2018 12:52:16 +0000 Subject: [PATCH 251/719] Knob to enforce blank line between module docstring and modeline/shebang This commit adds functionality to allow the placement of a newline between the module's docstring, and the modeline/shebang if it exists. Fixes #208. --- CHANGELOG | 5 +++ README.rst | 3 ++ yapf/yapflib/reformatter.py | 4 +++ yapf/yapflib/style.py | 4 +++ yapftests/reformatter_basic_test.py | 53 +++++++++++++++++++++++++++++ 5 files changed, 69 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 147f1a0ef..0129ac793 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,11 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## Unreleased +### Added +- The `BLANK_LINE_BEFORE_MODULE_DOCSTRING` knob adds a blank line before a + module's docstring. + ## [0.21.0] 2018-03-18 ### Added - Introduce a new option of formatting multiline literals. Add diff --git a/README.rst b/README.rst index 3b43d2941..ccc74d97f 100644 --- a/README.rst +++ b/README.rst @@ -322,6 +322,9 @@ Knobs def method(): pass +``BLANK_LINE_BEFORE_MODULE_DOCSTRING`` + Insert a blank line before a module docstring. + ``BLANK_LINE_BEFORE_CLASS_DOCSTRING`` Insert a blank line before a class-level docstring. diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index a4965ab33..0485d7e79 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -473,6 +473,10 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, style.Get('BLANK_LINE_BEFORE_CLASS_DOCSTRING')): # Enforce a blank line before a class's docstring. return ONE_BLANK_LINE + elif (prev_uwline.first.value.startswith('#') and + style.Get('BLANK_LINE_BEFORE_MODULE_DOCSTRING')): + # Enforce a blank line before a module's docstring. + return ONE_BLANK_LINE # The docstring shouldn't have a newline before it. return NO_BLANK_LINES diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 5f2fdacd8..7fd2177fa 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -71,6 +71,8 @@ def method(): ..."""), BLANK_LINE_BEFORE_CLASS_DOCSTRING=textwrap.dedent("""\ Insert a blank line before a class-level docstring."""), + BLANK_LINE_BEFORE_MODULE_DOCSTRING=textwrap.dedent("""\ + Insert a blank line before a module docstring."""), BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=textwrap.dedent("""\ Number of blank lines surrounding top-level function and class definitions."""), @@ -261,6 +263,7 @@ def CreatePEP8Style(): ALLOW_SPLIT_BEFORE_DICT_VALUE=True, BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=False, BLANK_LINE_BEFORE_CLASS_DOCSTRING=False, + BLANK_LINE_BEFORE_MODULE_DOCSTRING=False, BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=2, COALESCE_BRACKETS=False, COLUMN_LIMIT=79, @@ -406,6 +409,7 @@ def _BoolConverter(s): ALLOW_SPLIT_BEFORE_DICT_VALUE=_BoolConverter, BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=_BoolConverter, BLANK_LINE_BEFORE_CLASS_DOCSTRING=_BoolConverter, + BLANK_LINE_BEFORE_MODULE_DOCSTRING=_BoolConverter, BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=int, COALESCE_BRACKETS=_BoolConverter, COLUMN_LIMIT=int, diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index a1ca77946..01ed3d9b6 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2218,6 +2218,59 @@ def __init__(self): finally: style.SetGlobalStyle(style.CreateChromiumStyle()) + def testBlankLineBeforeModuleDocstring(self): + unformatted_code = textwrap.dedent('''\ + #!/usr/bin/env python + # -*- coding: utf-8 name> -*- + + """Some module docstring.""" + + + def foobar(): + pass + ''') + expected_code = textwrap.dedent('''\ + #!/usr/bin/env python + # -*- coding: utf-8 name> -*- + """Some module docstring.""" + + + def foobar(): + pass + ''') + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: pep8, ' + 'blank_line_before_module_docstring: True}')) + unformatted_code = textwrap.dedent('''\ + #!/usr/bin/env python + # -*- coding: utf-8 name> -*- + """Some module docstring.""" + + + def foobar(): + pass + ''') + expected_formatted_code = textwrap.dedent('''\ + #!/usr/bin/env python + # -*- coding: utf-8 name> -*- + + """Some module docstring.""" + + + def foobar(): + pass + ''') + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + def testTupleCohesion(self): unformatted_code = textwrap.dedent("""\ def f(): From 623721a564d8e31d9d8b748032ab23026731b18a Mon Sep 17 00:00:00 2001 From: Yinyin L Date: Mon, 5 Mar 2018 02:04:34 +0800 Subject: [PATCH 252/719] Added `CONTINUATION_ALIGN_STYLE` knob For choosing continuation alignment style when `USE_TABS` is enabled. --- CHANGELOG | 2 ++ README.rst | 14 +++++++++ yapf/yapflib/format_token.py | 29 +++++++++++++++++- yapf/yapflib/style.py | 29 ++++++++++++++++++ yapftests/format_token_test.py | 42 +++++++++++++++++++++++++ yapftests/style_test.py | 14 +++++++++ yapftests/yapf_test.py | 56 ++++++++++++++++++++++++++++++++++ 7 files changed, 185 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 67a7440f6..87bc3e7a3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,8 @@ - Introduce a new option of formatting multiline literals. Add `SPLIT_BEFORE_CLOSING_BRACKET` knob to control whether closing bracket should get their own line. +- Added `CONTINUATION_ALIGN_STYLE` knob to choose continuation alignment style + when `USE_TABS` is enabled. ## [0.20.2] 2018-02-12 ### Changed diff --git a/README.rst b/README.rst index 86ab6c68f..7e4bd3d84 100644 --- a/README.rst +++ b/README.rst @@ -351,6 +351,20 @@ Knobs ``COLUMN_LIMIT`` The column limit (or max line-length) +``CONTINUATION_ALIGN_STYLE`` + The style for continuation alignment. Possible values are: + + - SPACE: Use spaces for continuation alignment. This is default behavior. + - FIXED: Use fixed number (CONTINUATION_INDENT_WIDTH) of columns + (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs) for continuation + alignment. + - VALIGN-RIGHT: Vertically align continuation lines with indent characters. + Slightly right (one more indent character) if cannot vertically align + continuation lines with indent characters. + + For options ``FIXED``, and ``VALIGN-RIGHT`` are only available when + ``USE_TABS`` is enabled. + ``CONTINUATION_INDENT_WIDTH`` Indent width used for line continuations. diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index d86c16d5b..474e9b124 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -58,6 +58,28 @@ class Subtype(object): TYPED_NAME_ARG_LIST = 20 +def _TabbedContinuationAlignPadding(spaces, align_style, tab_width, + continuation_indent_width): + """Build padding string for continuation alignment in tabbed indentation. + + Arguments: + spaces: (int) The number of spaces to place before the token for alignment. + align_style: (str) The alignment style for continuation lines. + tab_width: (int) Number of columns of each tab character. + continuation_indent_width: (int) Indent columns for line continuations. + + Returns: + A padding string for alignment with style specified by align_style option. + """ + if align_style == 'FIXED': + if spaces > 0: + return '\t' * int(continuation_indent_width / tab_width) + return '' + elif align_style == 'VALIGN-RIGHT': + return '\t' * int((spaces + tab_width - 1) / tab_width) + return ' ' * spaces + + class FormatToken(object): """A wrapper around pytree Leaf nodes. @@ -123,7 +145,12 @@ def AddWhitespacePrefix(self, newlines_before, spaces=0, indent_level=0): indent_level: (int) The indentation level. """ if style.Get('USE_TABS'): - indent_before = '\t' * indent_level + ' ' * spaces + if newlines_before > 0: + indent_before = '\t' * indent_level + _TabbedContinuationAlignPadding( + spaces, style.Get('CONTINUATION_ALIGN_STYLE'), + style.Get('INDENT_WIDTH'), style.Get('CONTINUATION_INDENT_WIDTH')) + else: + indent_before = '\t' * indent_level + ' ' * spaces else: indent_before = ( ' ' * indent_level * style.Get('INDENT_WIDTH') + ' ' * spaces) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index f8865375c..9950f8110 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -90,6 +90,21 @@ def method(): })"""), COLUMN_LIMIT=textwrap.dedent("""\ The column limit."""), + CONTINUATION_ALIGN_STYLE=textwrap.dedent("""\ + The style for continuation alignment. Possible values are: + + - SPACE: Use spaces for continuation alignment. This is default behavior. + - FIXED: Use fixed number (CONTINUATION_INDENT_WIDTH) of columns + (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs) for continuation + alignment. + - LESS: Slightly left if cannot vertically align continuation lines with + indent characters. + - VALIGN-RIGHT: Vertically align continuation lines with indent + characters. Slightly right (one more indent character) if cannot + vertically align continuation lines with indent characters. + + For options FIXED, and VALIGN-RIGHT are only available when USE_TABS is + enabled."""), CONTINUATION_INDENT_WIDTH=textwrap.dedent("""\ Indent width used for line continuations."""), DEDENT_CLOSING_BRACKETS=textwrap.dedent("""\ @@ -245,6 +260,7 @@ def CreatePEP8Style(): BLANK_LINE_BEFORE_CLASS_DOCSTRING=False, COALESCE_BRACKETS=False, COLUMN_LIMIT=79, + CONTINUATION_ALIGN_STYLE='SPACE', CONTINUATION_INDENT_WIDTH=4, DEDENT_CLOSING_BRACKETS=False, EACH_DICT_ENTRY_ON_SEPARATE_LINE=True, @@ -345,6 +361,18 @@ def _GetStyleFactory(style): return None +def _ContinuationAlignStyleStringConverter(s): + """Option value converter for a continuation align style string.""" + accepted_styles = ('SPACE', 'FIXED', 'VALIGN-RIGHT') + if s: + r = s.upper() + if r not in accepted_styles: + raise ValueError("unknown continuation align style: %r" % (s,)) + else: + r = accepted_styles[0] + return r + + def _StringListConverter(s): """Option value converter for a comma-separated list of strings.""" return [part.strip() for part in s.split(',')] @@ -376,6 +404,7 @@ def _BoolConverter(s): BLANK_LINE_BEFORE_CLASS_DOCSTRING=_BoolConverter, COALESCE_BRACKETS=_BoolConverter, COLUMN_LIMIT=int, + CONTINUATION_ALIGN_STYLE=_ContinuationAlignStyleStringConverter, CONTINUATION_INDENT_WIDTH=int, DEDENT_CLOSING_BRACKETS=_BoolConverter, EACH_DICT_ENTRY_ON_SEPARATE_LINE=_BoolConverter, diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index f7b613bce..3adad4ebb 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -21,6 +21,48 @@ from yapf.yapflib import format_token +class TabbedContinuationAlignPaddingTest(unittest.TestCase): + + def testSpace(self): + align_style = 'SPACE' + + pad = format_token._TabbedContinuationAlignPadding(0, align_style, 2, 4) + self.assertEqual(pad, '') + + pad = format_token._TabbedContinuationAlignPadding(2, align_style, 2, 4) + self.assertEqual(pad, ' ' * 2) + + pad = format_token._TabbedContinuationAlignPadding(5, align_style, 2, 4) + self.assertEqual(pad, ' ' * 5) + + def testFixed(self): + align_style = 'FIXED' + + pad = format_token._TabbedContinuationAlignPadding(0, align_style, 4, 8) + self.assertEqual(pad, '') + + pad = format_token._TabbedContinuationAlignPadding(2, align_style, 4, 8) + self.assertEqual(pad, "\t" * 2) + + pad = format_token._TabbedContinuationAlignPadding(5, align_style, 4, 8) + self.assertEqual(pad, "\t" * 2) + + def testVAlignRight(self): + align_style = 'VALIGN-RIGHT' + + pad = format_token._TabbedContinuationAlignPadding(0, align_style, 4, 8) + self.assertEqual(pad, '') + + pad = format_token._TabbedContinuationAlignPadding(2, align_style, 4, 8) + self.assertEqual(pad, "\t") + + pad = format_token._TabbedContinuationAlignPadding(4, align_style, 4, 8) + self.assertEqual(pad, "\t") + + pad = format_token._TabbedContinuationAlignPadding(5, align_style, 4, 8) + self.assertEqual(pad, "\t" * 2) + + class FormatTokenTest(unittest.TestCase): def testSimple(self): diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 7f9a715e4..694cefaa1 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -26,6 +26,20 @@ class UtilsTest(unittest.TestCase): + def testContinuationAlignStyleStringConverter(self): + self.assertEqual(style._ContinuationAlignStyleStringConverter(''), 'SPACE') + self.assertEqual( + style._ContinuationAlignStyleStringConverter('space'), 'SPACE') + self.assertEqual( + style._ContinuationAlignStyleStringConverter('fixed'), 'FIXED') + self.assertEqual( + style._ContinuationAlignStyleStringConverter('valign-right'), + 'VALIGN-RIGHT') + with self.assertRaises(ValueError) as ctx: + style._ContinuationAlignStyleStringConverter('blahblah') + self.assertTrue( + "unknown continuation align style: 'blahblah'" in str(ctx.exception)) + def testStringListConverter(self): self.assertEqual(style._StringListConverter('foo, bar'), ['foo', 'bar']) self.assertEqual(style._StringListConverter('foo,bar'), ['foo', 'bar']) diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 5f3d3fc64..6df28b60d 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1196,6 +1196,62 @@ def f(): based_on_style = chromium USE_TABS = true INDENT_WIDTH=1 +""" + with utils.TempFileContents(self.test_tmpdir, style_contents) as stylepath: + self.assertYapfReformats( + unformatted_code, + expected_formatted_code, + extra_options=['--style={0}'.format(stylepath)]) + + def testUseTabsContinuationAlignStyleFixed(self): + unformatted_code = """\ +def foo_function(arg1, arg2, arg3): + return ['hello', 'world',] +""" + expected_formatted_code = """\ +def foo_function(arg1, arg2, + arg3): + return [ + 'hello', + 'world', + ] +""" + style_contents = u"""\ +[style] +based_on_style = chromium +USE_TABS = true +COLUMN_LIMIT=32 +INDENT_WIDTH=4 +CONTINUATION_INDENT_WIDTH=8 +CONTINUATION_ALIGN_STYLE = fixed +""" + with utils.TempFileContents(self.test_tmpdir, style_contents) as stylepath: + self.assertYapfReformats( + unformatted_code, + expected_formatted_code, + extra_options=['--style={0}'.format(stylepath)]) + + def testUseTabsContinuationAlignStyleVAlignRight(self): + unformatted_code = """\ +def foo_function(arg1, arg2, arg3): + return ['hello', 'world',] +""" + expected_formatted_code = """\ +def foo_function(arg1, arg2, + arg3): + return [ + 'hello', + 'world', + ] +""" + style_contents = u"""\ +[style] +based_on_style = chromium +USE_TABS = true +COLUMN_LIMIT=32 +INDENT_WIDTH=4 +CONTINUATION_INDENT_WIDTH=8 +CONTINUATION_ALIGN_STYLE = valign-right """ with utils.TempFileContents(self.test_tmpdir, style_contents) as stylepath: self.assertYapfReformats( From ac05feb03251568b081abcd699eecdf22a302bfa Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 14 Mar 2018 23:59:49 -0700 Subject: [PATCH 253/719] Don't split ellipses. Closes #533 --- CHANGELOG | 2 ++ yapf/yapflib/format_decision_state.py | 3 +++ yapf/yapflib/unwrapped_line.py | 3 ++- yapftests/reformatter_python3_test.py | 11 +++++++++++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 87bc3e7a3..486c64fd5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,8 @@ get their own line. - Added `CONTINUATION_ALIGN_STYLE` knob to choose continuation alignment style when `USE_TABS` is enabled. +### Fixed +- Don't split ellipses. ## [0.20.2] 2018-02-12 ### Changed diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index ce360df36..832d67a89 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -161,6 +161,9 @@ def CanSplit(self, must_split): if not style.Get('ALLOW_SPLIT_BEFORE_DICT_VALUE'): return False + if previous and previous.value == '.' and current.value == '.': + return False + return current.can_break_before def MustSplit(self): diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index e7e82c79d..92b986ebf 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -255,7 +255,8 @@ def _SpaceRequiredBetween(left, right): if lval == '.' and rval == 'import': # Space after the '.' in an import statement. return True - if lval == '=' and rval == '.': + if (lval == '=' and rval == '.' and + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN not in left.subtypes): # Space between equal and '.' as in "X = ...". return True if ((right.is_keyword or right.is_name) and diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index 7ff01ebaf..9be6528d5 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -367,6 +367,17 @@ def testMultilineFormatString(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testEllipses(self): + if sys.version_info[1] < 6: + return + code = """\ +def dirichlet(x12345678901234567890123456789012345678901234567890=...) -> None: + return +""" + # https://github.com/google/yapf/issues/533 + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From 3a787e6c7bfab046212345c5117ff4c743f4cc34 Mon Sep 17 00:00:00 2001 From: Markus Gerstel Date: Wed, 14 Feb 2018 17:07:35 +0000 Subject: [PATCH 254/719] Add knob BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION to modify the number of blank lines around top level function and class definitions. Closes #527 --- CHANGELOG | 2 ++ README.rst | 13 +++++++++++++ yapf/yapflib/blank_line_calculator.py | 3 ++- yapf/yapflib/reformatter.py | 9 +++++---- yapf/yapflib/style.py | 5 +++++ 5 files changed, 27 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 486c64fd5..d278a6dab 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,8 @@ get their own line. - Added `CONTINUATION_ALIGN_STYLE` knob to choose continuation alignment style when `USE_TABS` is enabled. +- Add 'BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION' knob to control the number + of blank lines between top-level function and class definitions. ### Fixed - Don't split ellipses. diff --git a/README.rst b/README.rst index 7e4bd3d84..3b43d2941 100644 --- a/README.rst +++ b/README.rst @@ -325,6 +325,19 @@ Knobs ``BLANK_LINE_BEFORE_CLASS_DOCSTRING`` Insert a blank line before a class-level docstring. +``BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION`` + Sets the number of desired blank lines surrounding top-level function and + class definitions. For example: + + .. code-block:: python + + class Foo: + pass + # <------ having two blank lines here + # <------ is the default setting + class Bar: + pass + ``COALESCE_BRACKETS`` Do not split consecutive brackets. Only relevant when ``DEDENT_CLOSING_BRACKETS`` is set. For example: diff --git a/yapf/yapflib/blank_line_calculator.py b/yapf/yapflib/blank_line_calculator.py index 4c62e8be6..0880a8039 100644 --- a/yapf/yapflib/blank_line_calculator.py +++ b/yapf/yapflib/blank_line_calculator.py @@ -27,6 +27,7 @@ from yapf.yapflib import py3compat from yapf.yapflib import pytree_utils from yapf.yapflib import pytree_visitor +from yapf.yapflib import style _NO_BLANK_LINES = 1 _ONE_BLANK_LINE = 2 @@ -155,7 +156,7 @@ def _GetNumNewlines(self, node): if self.last_was_decorator: return _NO_BLANK_LINES elif self._IsTopLevel(node): - return _TWO_BLANK_LINES + return 1 + style.Get('BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION') return _ONE_BLANK_LINE def _SetNumNewlines(self, node, num_newlines): diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 58a72591a..a4965ab33 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -479,9 +479,9 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, prev_last_token = prev_uwline.last if prev_last_token.is_docstring: if (not indent_depth and first_token.value in {'class', 'def', 'async'}): - # Separate a class or function from the module-level docstring with two - # blank lines. - return TWO_BLANK_LINES + # Separate a class or function from the module-level docstring with + # appropriate number of blank lines. + return 1 + style.Get('BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION') if _NoBlankLinesBeforeCurrentToken(prev_last_token.value, first_token, prev_last_token): return NO_BLANK_LINES @@ -509,7 +509,8 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, if final_lines[index - 1].first.value == '@': final_lines[index].first.AdjustNewlinesBefore(NO_BLANK_LINES) else: - prev_last_token.AdjustNewlinesBefore(TWO_BLANK_LINES) + prev_last_token.AdjustNewlinesBefore( + 1 + style.Get('BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION')) if first_token.newlines is not None: pytree_utils.SetNodeAnnotation( first_token.node, pytree_utils.Annotation.NEWLINES, None) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 9950f8110..02e0f9419 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -71,6 +71,9 @@ def method(): ..."""), BLANK_LINE_BEFORE_CLASS_DOCSTRING=textwrap.dedent("""\ Insert a blank line before a class-level docstring."""), + BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=textwrap.dedent("""\ + Number of blank lines surrounding top-level function and class + definitions."""), COALESCE_BRACKETS=textwrap.dedent("""\ Do not split consecutive brackets. Only relevant when dedent_closing_brackets is set. For example: @@ -258,6 +261,7 @@ def CreatePEP8Style(): ALLOW_SPLIT_BEFORE_DICT_VALUE=True, BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=False, BLANK_LINE_BEFORE_CLASS_DOCSTRING=False, + BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=2, COALESCE_BRACKETS=False, COLUMN_LIMIT=79, CONTINUATION_ALIGN_STYLE='SPACE', @@ -402,6 +406,7 @@ def _BoolConverter(s): ALLOW_SPLIT_BEFORE_DICT_VALUE=_BoolConverter, BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=_BoolConverter, BLANK_LINE_BEFORE_CLASS_DOCSTRING=_BoolConverter, + BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=int, COALESCE_BRACKETS=_BoolConverter, COLUMN_LIMIT=int, CONTINUATION_ALIGN_STYLE=_ContinuationAlignStyleStringConverter, From 222afe8f4cdd92a6e38fd1ad6957fbdb7f4f3a80 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 18 Mar 2018 20:42:05 -0700 Subject: [PATCH 255/719] Bump version to v0.21.0 --- CHANGELOG | 2 +- HACKING.rst | 2 +- yapf/__init__.py | 2 +- yapf/yapflib/format_token.py | 11 ++++++----- yapf/yapflib/style.py | 2 +- yapftests/format_token_test.py | 16 ++++++++-------- yapftests/style_test.py | 4 ++-- 7 files changed, 20 insertions(+), 19 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d278a6dab..92806ad8e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.20.3] UNRELEASED +## [0.21.0] 2018-03-18 ### Added - Introduce a new option of formatting multiline literals. Add `SPLIT_BEFORE_CLOSING_BRACKET` knob to control whether closing bracket should diff --git a/HACKING.rst b/HACKING.rst index eb1618032..cc27c5ac7 100644 --- a/HACKING.rst +++ b/HACKING.rst @@ -13,7 +13,7 @@ Releasing a new version ----------------------- * Run tests: python setup.py test - [don't forget to run with Python 2.7 and 3.4] + [don't forget to run with Python 2.7 and 3.6] * Bump version in yapf/__init__.py diff --git a/yapf/__init__.py b/yapf/__init__.py index d8fd680f6..0322b31ab 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.20.2' +__version__ = '0.21.0' def main(argv): diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 474e9b124..14899e90d 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -300,13 +300,14 @@ def is_string(self): @property @py3compat.lru_cache() def is_multiline_string(self): + """A multiline string.""" if py3compat.PY3: - prefix = "(" - prefix += "r|u|R|U|f|F|fr|Fr|fR|FR|rf|rF|Rf|RF" # strings - prefix += "|b|B|br|Br|bR|BR|rb|rB|Rb|RB" # bytes - prefix += ")?" + prefix = '(' + prefix += 'r|u|R|U|f|F|fr|Fr|fR|FR|rf|rF|Rf|RF' # strings + prefix += '|b|B|br|Br|bR|BR|rb|rB|Rb|RB' # bytes + prefix += ')?' else: - prefix = "[uUbB]?[rR]?" + prefix = '[uUbB]?[rR]?' regex = r'^{prefix}(?P"""|\'\'\').*(?P=delim)$'.format(prefix=prefix) return (self.is_string and diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 02e0f9419..5f2fdacd8 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -371,7 +371,7 @@ def _ContinuationAlignStyleStringConverter(s): if s: r = s.upper() if r not in accepted_styles: - raise ValueError("unknown continuation align style: %r" % (s,)) + raise ValueError('unknown continuation align style: %r' % (s,)) else: r = accepted_styles[0] return r diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index 3adad4ebb..7dfb82a56 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -42,10 +42,10 @@ def testFixed(self): self.assertEqual(pad, '') pad = format_token._TabbedContinuationAlignPadding(2, align_style, 4, 8) - self.assertEqual(pad, "\t" * 2) + self.assertEqual(pad, '\t' * 2) pad = format_token._TabbedContinuationAlignPadding(5, align_style, 4, 8) - self.assertEqual(pad, "\t" * 2) + self.assertEqual(pad, '\t' * 2) def testVAlignRight(self): align_style = 'VALIGN-RIGHT' @@ -54,13 +54,13 @@ def testVAlignRight(self): self.assertEqual(pad, '') pad = format_token._TabbedContinuationAlignPadding(2, align_style, 4, 8) - self.assertEqual(pad, "\t") + self.assertEqual(pad, '\t') pad = format_token._TabbedContinuationAlignPadding(4, align_style, 4, 8) - self.assertEqual(pad, "\t") + self.assertEqual(pad, '\t') pad = format_token._TabbedContinuationAlignPadding(5, align_style, 4, 8) - self.assertEqual(pad, "\t" * 2) + self.assertEqual(pad, '\t' * 2) class FormatTokenTest(unittest.TestCase): @@ -70,8 +70,8 @@ def testSimple(self): self.assertEqual("FormatToken(name=STRING, value='hello world')", str(tok)) self.assertTrue(tok.is_string) - tok = format_token.FormatToken(pytree.Leaf(token.COMMENT, "# A comment")) - self.assertEqual("FormatToken(name=COMMENT, value=# A comment)", str(tok)) + tok = format_token.FormatToken(pytree.Leaf(token.COMMENT, '# A comment')) + self.assertEqual('FormatToken(name=COMMENT, value=# A comment)', str(tok)) self.assertTrue(tok.is_comment) def testIsMultilineString(self): @@ -82,5 +82,5 @@ def testIsMultilineString(self): self.assertTrue(tok.is_multiline_string) -if __name__ == "__main__": +if __name__ == '__main__': unittest.main() diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 694cefaa1..7f4a4652a 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -37,8 +37,8 @@ def testContinuationAlignStyleStringConverter(self): 'VALIGN-RIGHT') with self.assertRaises(ValueError) as ctx: style._ContinuationAlignStyleStringConverter('blahblah') - self.assertTrue( - "unknown continuation align style: 'blahblah'" in str(ctx.exception)) + self.assertIn("unknown continuation align style: 'blahblah'", + str(ctx.exception)) def testStringListConverter(self): self.assertEqual(style._StringListConverter('foo, bar'), ['foo', 'bar']) From fa3c58fe95740eaf0d61c14c16f6cd3aa1404dfe Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 23 Mar 2018 01:21:44 -0700 Subject: [PATCH 256/719] Don't force a split in Google style. Google / Chromium allows you to put a set generator on a single line if it's trivial and fits. --- yapf/yapflib/style.py | 3 ++- yapftests/reformatter_buganizer_test.py | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 7fd2177fa..6f14fad82 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -312,8 +312,9 @@ def CreateGoogleStyle(): style['I18N_COMMENT'] = r'#\..*' style['I18N_FUNCTION_CALL'] = ['N_', '_'] style['SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET'] = False - style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False style['SPLIT_BEFORE_BITWISE_OPERATOR'] = False + style['SPLIT_BEFORE_DICT_SET_GENERATOR'] = False + style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False style['SPLIT_COMPLEX_COMPREHENSION'] = True style['SPLIT_PENALTY_COMPREHENSION'] = 2100 return style diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index e04c9621f..9d6a49d91 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,26 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB65246454(self): + unformatted_code = """\ +class _(): + + def _(self): + self.assertEqual({i.id + for i in successful_instances}, + {i.id + for i in self._statuses.successful_instances}) +""" + expected_formatted_code = """\ +class _(): + + def _(self): + self.assertEqual({i.id for i in successful_instances}, + {i.id for i in self._statuses.successful_instances}) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB67935450(self): unformatted_code = """\ def _(): From 03162be519957938635f62d790dea95cdcf82956 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 26 Mar 2018 22:26:06 -0700 Subject: [PATCH 257/719] Improve function call splitting heuristic. This looks to see if each argument in a function call can fit on a single line. If not, then we want to split. --- CHANGELOG | 4 ++ yapf/yapflib/format_decision_state.py | 11 +++++ yapf/yapflib/format_token.py | 6 +++ yapf/yapflib/identify_container.py | 59 +++++++++++++++++++++++++ yapf/yapflib/pytree_unwrapper.py | 5 +++ yapf/yapflib/pytree_utils.py | 22 +++++++++ yapf/yapflib/yapf_api.py | 2 + yapftests/reformatter_buganizer_test.py | 13 ++++++ yapftests/yapf_test_helper.py | 2 + 9 files changed, 124 insertions(+) create mode 100644 yapf/yapflib/identify_container.py diff --git a/CHANGELOG b/CHANGELOG index e3cc518f0..59674781e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,10 @@ ### Added - The `BLANK_LINE_BEFORE_MODULE_DOCSTRING` knob adds a blank line before a module's docstring. +### Changed +- Improve the heuristic we use to determine when to split at the start of a + function call. First check whether or not all elements can fit in the space + without wrapping. If not, then we split. ## [0.21.0] 2018-03-18 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 832d67a89..6df27a18b 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -439,6 +439,17 @@ def SurroundedByParens(token): if self._FitsOnLine(previous, previous.matching_bracket): return False elif not self._FitsOnLine(previous, previous.matching_bracket): + if len(previous.container_elements) == 1: + return False + + elements = previous.container_elements + [previous.matching_bracket] + i = 1 + while i < len(elements): + if (not elements[i - 1].OpensScope() and + not self._FitsOnLine(elements[i - 1], elements[i])): + return True + i += 1 + if (self.column_limit - self.column) / float(self.column_limit) < 0.3: # Try not to squish all of the arguments off to the right. return current.next_token != previous.matching_bracket diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 14899e90d..4530cb84e 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -93,6 +93,10 @@ class FormatToken(object): this is the first token in the unwrapped line. matching_bracket: If a bracket token ('[', '{', or '(') the matching bracket. + container_opening: If the object is in a container, this points to its + opening bracket. + container_elements: If this is the start of a container, a list of the + elements in the container. whitespace_prefix: The prefix for the whitespace. spaces_required_before: The number of spaces required before a token. This is a lower-bound for the formatter and not a hard requirement. For @@ -118,6 +122,8 @@ def __init__(self, node): self.next_token = None self.previous_token = None self.matching_bracket = None + self.container_opening = None + self.container_elements = [] self.whitespace_prefix = '' self.can_break_before = False self.must_break_before = False diff --git a/yapf/yapflib/identify_container.py b/yapf/yapflib/identify_container.py new file mode 100644 index 000000000..2d4176c32 --- /dev/null +++ b/yapf/yapflib/identify_container.py @@ -0,0 +1,59 @@ +# Copyright 2018 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Identify containers for lib2to3 trees. + +This module identifies containers and the elements in them. Each element points +to the opening bracket and vice-versa. + + IdentifyContainers(): the main function exported by this module. +""" + +from lib2to3 import pytree + +from yapf.yapflib import pytree_utils +from yapf.yapflib import pytree_visitor + + +def IdentifyContainers(tree): + """Run the identify containers visitor over the tree, modifying it in place. + + Arguments: + tree: the top-level pytree node to annotate with subtypes. + """ + identify_containers = _IdentifyContainers() + identify_containers.Visit(tree) + + +class _IdentifyContainers(pytree_visitor.PyTreeVisitor): + """_IdentifyContainers - see file-level docstring for detailed description.""" + + def Visit_trailer(self, node): # pylint: disable=invalid-name + if len(node.children) != 3: + return + if pytree_utils.NodeName(node.children[0]) != 'LPAR': + return + + if pytree_utils.NodeName(node.children[1]) == 'arglist': + for child in node.children[1].children: + pytree_utils.SetOpeningBracket( + _GetFirstLeafNode(child), node.children[0]) + else: + pytree_utils.SetOpeningBracket( + _GetFirstLeafNode(node.children[1]), node.children[0]) + + +def _GetFirstLeafNode(node): + if isinstance(node, pytree.Leaf): + return node + return _GetFirstLeafNode(node.children[0]) diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index a81ccd468..f72e0bf57 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -306,6 +306,11 @@ def _MatchBrackets(uwline): token.matching_bracket = bracket_stack[-1] bracket_stack.pop() + for bracket in bracket_stack: + if pytree_utils.GetOpeningBracket(token.node) == bracket.node: + bracket.container_elements.append(token) + token.container_opening = bracket + def _AdjustSplitPenalty(uwline): """Visit the node and adjust the split penalties if needed. diff --git a/yapf/yapflib/pytree_utils.py b/yapf/yapflib/pytree_utils.py index 08048d870..3444f44df 100644 --- a/yapf/yapflib/pytree_utils.py +++ b/yapf/yapflib/pytree_utils.py @@ -259,6 +259,28 @@ def RemoveSubtypeAnnotation(node, value): SetNodeAnnotation(node, Annotation.SUBTYPE, attr) +def GetOpeningBracket(node): + """Get opening bracket value from a node. + + Arguments: + node: the node. + + Returns: + The opening bracket node or None if it couldn't find one. + """ + return getattr(node, _NODE_ANNOTATION_PREFIX + "container_bracket", None) + + +def SetOpeningBracket(node, bracket): + """Set opening bracket value for a node. + + Arguments: + node: the node. + bracket: opening bracket to set. + """ + setattr(node, _NODE_ANNOTATION_PREFIX + "container_bracket", bracket) + + def DumpNodeToString(node): """Dump a string representation of the given node. For debugging. diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 271e3a591..b78128524 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -42,6 +42,7 @@ from yapf.yapflib import comment_splicer from yapf.yapflib import continuation_splicer from yapf.yapflib import file_resources +from yapf.yapflib import identify_container from yapf.yapflib import py3compat from yapf.yapflib import pytree_unwrapper from yapf.yapflib import pytree_utils @@ -133,6 +134,7 @@ def FormatCode(unformatted_source, comment_splicer.SpliceComments(tree) continuation_splicer.SpliceContinuations(tree) subtype_assigner.AssignSubtypes(tree) + identify_container.IdentifyContainers(tree) split_penalty.ComputeSplitPenalties(tree) blank_line_calculator.CalculateBlankLines(tree) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 9d6a49d91..8fb6d1f7b 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,19 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB30394228(self): + code = """\ +class _(): + + def _(self): + return some.randome.function.calling( + wf, None, alert.Format(alert.subject, alert=alert, threshold=threshold), + alert.Format(alert.body, alert=alert, threshold=threshold), + alert.html_formatting) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB65246454(self): unformatted_code = """\ class _(): diff --git a/yapftests/yapf_test_helper.py b/yapftests/yapf_test_helper.py index 53357a2b1..1f21b363a 100644 --- a/yapftests/yapf_test_helper.py +++ b/yapftests/yapf_test_helper.py @@ -20,6 +20,7 @@ from yapf.yapflib import blank_line_calculator from yapf.yapflib import comment_splicer from yapf.yapflib import continuation_splicer +from yapf.yapflib import identify_container from yapf.yapflib import pytree_unwrapper from yapf.yapflib import pytree_utils from yapf.yapflib import pytree_visitor @@ -74,6 +75,7 @@ def ParseAndUnwrap(code, dumptree=False): comment_splicer.SpliceComments(tree) continuation_splicer.SpliceContinuations(tree) subtype_assigner.AssignSubtypes(tree) + identify_container.IdentifyContainers(tree) split_penalty.ComputeSplitPenalties(tree) blank_line_calculator.CalculateBlankLines(tree) From 9ffeee8a35142177562b66189e2305bf6fdeb880 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 26 Mar 2018 22:56:55 -0700 Subject: [PATCH 258/719] Analyze elements of a tuple for splitting. We may want to split tuples up similarly to how function arguments are split. --- CHANGELOG | 2 ++ yapf/yapflib/format_decision_state.py | 2 +- yapf/yapflib/identify_container.py | 15 ++++++++++ yapf/yapflib/pytree_unwrapper.py | 2 +- yapftests/reformatter_buganizer_test.py | 38 +++++++++++++++++++++++++ 5 files changed, 57 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 59674781e..8e461a92b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,8 @@ - Improve the heuristic we use to determine when to split at the start of a function call. First check whether or not all elements can fit in the space without wrapping. If not, then we split. +- Check all of the elements of a tuple. Similarly to how arguments are + analyzed. This allows tuples to be split more rationally. ## [0.21.0] 2018-03-18 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 6df27a18b..4e62f80bf 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -452,7 +452,7 @@ def SurroundedByParens(token): if (self.column_limit - self.column) / float(self.column_limit) < 0.3: # Try not to squish all of the arguments off to the right. - return current.next_token != previous.matching_bracket + return True else: # Split after the opening of a container if it doesn't fit on the # current line. diff --git a/yapf/yapflib/identify_container.py b/yapf/yapflib/identify_container.py index 2d4176c32..9d382394c 100644 --- a/yapf/yapflib/identify_container.py +++ b/yapf/yapflib/identify_container.py @@ -39,6 +39,9 @@ class _IdentifyContainers(pytree_visitor.PyTreeVisitor): """_IdentifyContainers - see file-level docstring for detailed description.""" def Visit_trailer(self, node): # pylint: disable=invalid-name + for child in node.children: + self.Visit(child) + if len(node.children) != 3: return if pytree_utils.NodeName(node.children[0]) != 'LPAR': @@ -52,6 +55,18 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name pytree_utils.SetOpeningBracket( _GetFirstLeafNode(node.children[1]), node.children[0]) + def Visit_atom(self, node): # pylint: disable=invalid-name + for child in node.children: + self.Visit(child) + + if len(node.children) != 3: + return + if pytree_utils.NodeName(node.children[0]) != 'LPAR': + return + + for child in node.children[1].children: + pytree_utils.SetOpeningBracket(_GetFirstLeafNode(child), node.children[0]) + def _GetFirstLeafNode(node): if isinstance(node, pytree.Leaf): diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index f72e0bf57..f6be26021 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -307,7 +307,7 @@ def _MatchBrackets(uwline): bracket_stack.pop() for bracket in bracket_stack: - if pytree_utils.GetOpeningBracket(token.node) == bracket.node: + if id(pytree_utils.GetOpeningBracket(token.node)) == id(bracket.node): bracket.container_elements.append(token) token.container_opening = bracket diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 8fb6d1f7b..026179861 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,44 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB33228502(self): + unformatted_code = """\ +def _(): + success_rate_stream_table = module.Precompute( + query_function=module.DefineQueryFunction( + name='Response error ratio', + expression=((m.Fetch( + m.Raw('monarch.BorgTask', + '/corp/travel/trips2/dispatcher/email/response'), + {'borg_job': module_config.job, 'metric:response_type': 'SUCCESS'}), + m.Fetch(m.Raw('monarch.BorgTask', '/corp/travel/trips2/dispatcher/email/response'), {'borg_job': module_config.job})) + | m.Window(m.Delta('1h')) + | m.Join('successes', 'total') + | m.Point(m.VAL['successes'] / m.VAL['total'])))) +""" + expected_formatted_code = """\ +def _(): + success_rate_stream_table = module.Precompute( + query_function=module.DefineQueryFunction( + name='Response error ratio', + expression=( + (m.Fetch( + m.Raw('monarch.BorgTask', + '/corp/travel/trips2/dispatcher/email/response'), { + 'borg_job': module_config.job, + 'metric:response_type': 'SUCCESS' + }), + m.Fetch( + m.Raw('monarch.BorgTask', + '/corp/travel/trips2/dispatcher/email/response'), + {'borg_job': module_config.job})) + | m.Window(m.Delta('1h')) + | m.Join('successes', 'total') + | m.Point(m.VAL['successes'] / m.VAL['total'])))) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB30394228(self): code = """\ class _(): From 11b7c9f3b9ce4e210e228aa7daaec64f658dacb9 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 26 Mar 2018 23:25:45 -0700 Subject: [PATCH 259/719] Look for pylint comments disabling long lambda warnings This allows long lambdas on a case-by-case basis. --- CHANGELOG | 3 +++ yapf/yapflib/split_penalty.py | 12 +++++++++++- yapftests/reformatter_buganizer_test.py | 21 +++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 8e461a92b..0a00c8c17 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,9 @@ without wrapping. If not, then we split. - Check all of the elements of a tuple. Similarly to how arguments are analyzed. This allows tuples to be split more rationally. +### Fixed +- Attempt to determine if long lambdas are allowed. This can be done on a + case-by-case basis with a "pylint" disable comment. ## [0.21.0] 2018-03-18 ### Added diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 9fae32791..66f733f46 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -13,6 +13,8 @@ # limitations under the License. """Computation of split penalties before/between tokens.""" +import re + from lib2to3 import pytree from yapf.yapflib import format_token @@ -111,7 +113,15 @@ def Visit_funcdef(self, node): # pylint: disable=invalid-name def Visit_lambdef(self, node): # pylint: disable=invalid-name # lambdef ::= 'lambda' [varargslist] ':' test # Loop over the lambda up to and including the colon. - if style.Get('ALLOW_MULTILINE_LAMBDAS'): + allow_multiline_lambdas = style.Get('ALLOW_MULTILINE_LAMBDAS') + if not allow_multiline_lambdas: + for child in node.children: + if pytree_utils.NodeName(child) == 'COMMENT': + if re.search(r'pylint:.*disable=.*\bg-long-lambda', child.value): + allow_multiline_lambdas = True + break + + if allow_multiline_lambdas: _SetStronglyConnected(node) else: self._SetUnbreakableOnChildren(node) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 026179861..5b50c28f4 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,27 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB37099651(self): + unformatted_code = """\ +_MEMCACHE = lazy.MakeLazy( + # pylint: disable=g-long-lambda + lambda: function.call.mem.clients(FLAGS.some_flag_thingy, default_namespace=_LAZY_MEM_NAMESPACE, allow_pickle=True) + # pylint: enable=g-long-lambda +) +""" + expected_formatted_code = """\ +_MEMCACHE = lazy.MakeLazy( + # pylint: disable=g-long-lambda + lambda: function.call.mem.clients( + FLAGS.some_flag_thingy, + default_namespace=_LAZY_MEM_NAMESPACE, + allow_pickle=True) + # pylint: enable=g-long-lambda +) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB33228502(self): unformatted_code = """\ def _(): From df6ae576eb2425b97904d998ba4627734ba9ffdc Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 27 Mar 2018 00:15:30 -0700 Subject: [PATCH 260/719] A comment before a decorator isn't part of the decorator. --- CHANGELOG | 1 + yapf/yapflib/pytree_unwrapper.py | 6 ++++++ yapftests/reformatter_buganizer_test.py | 12 ++++++++++++ 3 files changed, 19 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 0a00c8c17..699428bd5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -15,6 +15,7 @@ ### Fixed - Attempt to determine if long lambdas are allowed. This can be done on a case-by-case basis with a "pylint" disable comment. +- A comment before a decorator isn't part of the decorator's line. ## [0.21.0] 2018-03-18 ### Added diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index f6be26021..bbb5cdb79 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -222,6 +222,12 @@ def Visit_async_stmt(self, node): # pylint: disable=invalid-name for child in node.children[index].children: self.Visit(child) + def Visit_decorator(self, node): # pylint: disable=invalid-name + for child in node.children: + self.Visit(child) + if pytree_utils.NodeName(child) == 'COMMENT': + self._StartNewLine() + def Visit_decorators(self, node): # pylint: disable=invalid-name for child in node.children: self._StartNewLine() diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 5b50c28f4..914befc76 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,18 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB38343525(self): + code = """\ +# This does foo. +@arg.String('some_path_to_a_file', required=True) +# This does bar. +@arg.String('some_path_to_a_file', required=True) +def f(): + print 1 +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB37099651(self): unformatted_code = """\ _MEMCACHE = lazy.MakeLazy( From 6fe40790ff2a209be33cc9d37d1ce3089cc6d7fa Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 27 Mar 2018 00:15:30 -0700 Subject: [PATCH 261/719] A comment before a decorator isn't part of the decorator. --- CHANGELOG | 1 + yapf/yapflib/pytree_unwrapper.py | 6 ++++++ yapf/yapflib/pytree_utils.py | 4 ++-- yapftests/reformatter_buganizer_test.py | 12 ++++++++++++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0a00c8c17..699428bd5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -15,6 +15,7 @@ ### Fixed - Attempt to determine if long lambdas are allowed. This can be done on a case-by-case basis with a "pylint" disable comment. +- A comment before a decorator isn't part of the decorator's line. ## [0.21.0] 2018-03-18 ### Added diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index f6be26021..bbb5cdb79 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -222,6 +222,12 @@ def Visit_async_stmt(self, node): # pylint: disable=invalid-name for child in node.children[index].children: self.Visit(child) + def Visit_decorator(self, node): # pylint: disable=invalid-name + for child in node.children: + self.Visit(child) + if pytree_utils.NodeName(child) == 'COMMENT': + self._StartNewLine() + def Visit_decorators(self, node): # pylint: disable=invalid-name for child in node.children: self._StartNewLine() diff --git a/yapf/yapflib/pytree_utils.py b/yapf/yapflib/pytree_utils.py index 3444f44df..d89588fc6 100644 --- a/yapf/yapflib/pytree_utils.py +++ b/yapf/yapflib/pytree_utils.py @@ -268,7 +268,7 @@ def GetOpeningBracket(node): Returns: The opening bracket node or None if it couldn't find one. """ - return getattr(node, _NODE_ANNOTATION_PREFIX + "container_bracket", None) + return getattr(node, _NODE_ANNOTATION_PREFIX + 'container_bracket', None) def SetOpeningBracket(node, bracket): @@ -278,7 +278,7 @@ def SetOpeningBracket(node, bracket): node: the node. bracket: opening bracket to set. """ - setattr(node, _NODE_ANNOTATION_PREFIX + "container_bracket", bracket) + setattr(node, _NODE_ANNOTATION_PREFIX + 'container_bracket', bracket) def DumpNodeToString(node): diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 5b50c28f4..914befc76 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,18 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB38343525(self): + code = """\ +# This does foo. +@arg.String('some_path_to_a_file', required=True) +# This does bar. +@arg.String('some_path_to_a_file', required=True) +def f(): + print 1 +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB37099651(self): unformatted_code = """\ _MEMCACHE = lazy.MakeLazy( From d7d6e9b6a817e5f8d7417fb23d74139c77642ead Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 27 Mar 2018 13:43:11 -0700 Subject: [PATCH 262/719] Adjust split penalties around arithmetic ops. We want to break around the operator before the operands. --- CHANGELOG | 2 ++ yapf/yapflib/comment_splicer.py | 4 ++-- yapf/yapflib/split_penalty.py | 22 +++++++++++++++------- yapftests/reformatter_buganizer_test.py | 21 +++++++++++++++++++-- 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 699428bd5..904d01a83 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,8 @@ without wrapping. If not, then we split. - Check all of the elements of a tuple. Similarly to how arguments are analyzed. This allows tuples to be split more rationally. +- Adjust splitting penalties around arithmetic operators so that the code can + flow more freely. The code must flow! ### Fixed - Attempt to determine if long lambdas are allowed. This can be done on a case-by-case basis with a "pylint" disable comment. diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index 8717394f0..af999d260 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -177,8 +177,8 @@ def _VisitNodeRec(node): rindex = (0 if '\n' not in comment_prefix.rstrip() else comment_prefix.rstrip().rindex('\n') + 1) comment_column = ( - len(comment_prefix[rindex:]) - - len(comment_prefix[rindex:].lstrip())) + len(comment_prefix[rindex:]) - len( + comment_prefix[rindex:].lstrip())) comments = _CreateCommentsFromPrefix( comment_prefix, comment_lineno, diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 66f733f46..f81580498 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -396,6 +396,8 @@ def Visit_shift_expr(self, node): # pylint: disable=invalid-name self.DefaultNodeVisit(node) _IncreasePenalty(node, SHIFT_EXPR) + _ARITH_OPS = frozenset({'PLUS', 'MINUS'}) + def Visit_arith_expr(self, node): # pylint: disable=invalid-name # arith_expr ::= term (('+'|'-') term)* self.DefaultNodeVisit(node) @@ -404,19 +406,25 @@ def Visit_arith_expr(self, node): # pylint: disable=invalid-name index = 1 while index < len(node.children) - 1: child = node.children[index] - if isinstance(child, pytree.Leaf) and child.value in '+-': + if pytree_utils.NodeName(child) in self._ARITH_OPS: next_node = _FirstChildNode(node.children[index + 1]) - _SetSplitPenalty( - next_node, - pytree_utils.GetNodeAnnotation( - next_node, pytree_utils.Annotation.SPLIT_PENALTY, default=0) - - 100) + _SetSplitPenalty(next_node, ARITH_EXPR) index += 1 + _TERM_OPS = frozenset({'STAR', 'AT', 'SLASH', 'PERCENT', 'DOUBLESLASH'}) + def Visit_term(self, node): # pylint: disable=invalid-name # term ::= factor (('*'|'@'|'/'|'%'|'//') factor)* - _IncreasePenalty(node, TERM) self.DefaultNodeVisit(node) + _IncreasePenalty(node, TERM) + + index = 1 + while index < len(node.children) - 1: + child = node.children[index] + if pytree_utils.NodeName(child) in self._TERM_OPS: + next_node = _FirstChildNode(node.children[index + 1]) + _SetSplitPenalty(next_node, TERM) + index += 1 def Visit_factor(self, node): # pyline: disable=invalid-name # factor ::= ('+'|'-'|'~') factor | power diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 914befc76..8f6ebacd6 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,23 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB30500455(self): + unformatted_code = """\ +INITIAL_SYMTAB = dict([(name, 'exception#' + name) for name in INITIAL_EXCEPTIONS +] * [(name, 'type#' + name) for name in INITIAL_TYPES] + [ + (name, 'function#' + name) for name in INITIAL_FUNCTIONS +] + [(name, 'const#' + name) for name in INITIAL_CONSTS]) +""" + expected_formatted_code = """\ +INITIAL_SYMTAB = dict( + [(name, 'exception#' + name) for name in INITIAL_EXCEPTIONS] * + [(name, 'type#' + name) for name in INITIAL_TYPES] + + [(name, 'function#' + name) for name in INITIAL_FUNCTIONS] + + [(name, 'const#' + name) for name in INITIAL_CONSTS]) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB38343525(self): code = """\ # This does foo. @@ -503,8 +520,8 @@ def _(): expected_formatted_code = textwrap.dedent("""\ class _(): def _(): - hints.append(('hg tag -f -l -r %s %s # %s' % - (short(ctx.node()), candidatetag, firstline))[:78]) + hints.append(('hg tag -f -l -r %s %s # %s' % (short( + ctx.node()), candidatetag, firstline))[:78]) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) From c58891d8e11df0f7d1a5e5715a430b9cc2c34edf Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 27 Mar 2018 15:31:54 -0700 Subject: [PATCH 263/719] Increase the affinity of the closing paren to arg list --- CHANGELOG | 1 + yapf/yapflib/split_penalty.py | 4 +++ yapftests/reformatter_buganizer_test.py | 46 +++++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 904d01a83..7dc793cb2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,7 @@ analyzed. This allows tuples to be split more rationally. - Adjust splitting penalties around arithmetic operators so that the code can flow more freely. The code must flow! +- Try to meld an argument list's closing parenthesis to the last argument. ### Fixed - Attempt to determine if long lambdas are allowed. This can be done on a case-by-case basis with a "pylint" disable comment. diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index f81580498..fe32e4996 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -231,6 +231,10 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name }: # Don't split an argument list with one element if at all possible. _SetStronglyConnected(node.children[1], node.children[2]) + + if name == 'arglist': + _SetStronglyConnected(node.children[-1]) + self.DefaultNodeVisit(node) def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 8f6ebacd6..ffb6ded5e 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,52 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB65546221(self): + unformatted_code = """\ +class _(): + + def _(): + return timedelta(seconds=max(float(time_scale), small_interval) * + 1.41 ** min(num_attempts, 9)) +""" + expected_formatted_code = """\ +class _(): + + def _(): + return timedelta( + seconds=max(float(time_scale), small_interval) * + 1.41**min(num_attempts, 9)) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB65546221(self): + unformatted_code = """\ +SUPPORTED_PLATFORMS = ( + "centos-6", + "centos-7", + "ubuntu-1204-precise", + "ubuntu-1404-trusty", + "ubuntu-1604-xenial", + "debian-7-wheezy", + "debian-8-jessie", + "debian-9-stretch",) +""" + expected_formatted_code = """\ +SUPPORTED_PLATFORMS = ( + "centos-6", + "centos-7", + "ubuntu-1204-precise", + "ubuntu-1404-trusty", + "ubuntu-1604-xenial", + "debian-7-wheezy", + "debian-8-jessie", + "debian-9-stretch", +) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB30500455(self): unformatted_code = """\ INITIAL_SYMTAB = dict([(name, 'exception#' + name) for name in INITIAL_EXCEPTIONS From aca0c3c965f12b55e774ddd4786a3541b15bb68b Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 27 Mar 2018 17:10:36 -0700 Subject: [PATCH 264/719] Refactor common function. --- yapf/yapflib/blank_line_calculator.py | 10 +--- yapf/yapflib/identify_container.py | 13 ++--- yapf/yapflib/pytree_unwrapper.py | 9 +-- yapf/yapflib/pytree_utils.py | 12 ++++ yapf/yapflib/split_penalty.py | 80 +++++++++++++-------------- yapf/yapflib/subtype_assigner.py | 22 ++------ 6 files changed, 65 insertions(+), 81 deletions(-) diff --git a/yapf/yapflib/blank_line_calculator.py b/yapf/yapflib/blank_line_calculator.py index 0880a8039..0a4fcc2a9 100644 --- a/yapf/yapflib/blank_line_calculator.py +++ b/yapf/yapflib/blank_line_calculator.py @@ -116,7 +116,7 @@ def DefaultNodeVisit(self, node): """ if self.last_was_class_or_function: if pytree_utils.NodeName(node) in _PYTHON_STATEMENTS: - leaf = _GetFirstChildLeaf(node) + leaf = pytree_utils.FirstLeafNode(node) self._SetNumNewlines(leaf, self._GetNumNewlines(leaf)) self.last_was_class_or_function = False super(_BlankLineCalculator, self).DefaultNodeVisit(node) @@ -169,16 +169,10 @@ def _IsTopLevel(self, node): def _StartsInZerothColumn(node): - return (_GetFirstChildLeaf(node).column == 0 or + return (pytree_utils.FirstLeafNode(node).column == 0 or (_AsyncFunction(node) and node.prev_sibling.column == 0)) def _AsyncFunction(node): return (py3compat.PY3 and node.prev_sibling and pytree_utils.NodeName(node.prev_sibling) == 'ASYNC') - - -def _GetFirstChildLeaf(node): - if isinstance(node, pytree.Leaf): - return node - return _GetFirstChildLeaf(node.children[0]) diff --git a/yapf/yapflib/identify_container.py b/yapf/yapflib/identify_container.py index 9d382394c..23630c505 100644 --- a/yapf/yapflib/identify_container.py +++ b/yapf/yapflib/identify_container.py @@ -50,10 +50,10 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name if pytree_utils.NodeName(node.children[1]) == 'arglist': for child in node.children[1].children: pytree_utils.SetOpeningBracket( - _GetFirstLeafNode(child), node.children[0]) + pytree_utils.FirstLeafNode(child), node.children[0]) else: pytree_utils.SetOpeningBracket( - _GetFirstLeafNode(node.children[1]), node.children[0]) + pytree_utils.FirstLeafNode(node.children[1]), node.children[0]) def Visit_atom(self, node): # pylint: disable=invalid-name for child in node.children: @@ -65,10 +65,5 @@ def Visit_atom(self, node): # pylint: disable=invalid-name return for child in node.children[1].children: - pytree_utils.SetOpeningBracket(_GetFirstLeafNode(child), node.children[0]) - - -def _GetFirstLeafNode(node): - if isinstance(node, pytree.Leaf): - return node - return _GetFirstLeafNode(node.children[0]) + pytree_utils.SetOpeningBracket( + pytree_utils.FirstLeafNode(child), node.children[0]) diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index bbb5cdb79..049dbbb5d 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -377,11 +377,6 @@ def _ContainsComments(node): def _SetMustSplitOnFirstLeaf(node): """Set the "must split" annotation on the first leaf node.""" - - def FindFirstLeaf(node): - if isinstance(node, pytree.Leaf): - return node - return FindFirstLeaf(node.children[0]) - pytree_utils.SetNodeAnnotation( - FindFirstLeaf(node), pytree_utils.Annotation.MUST_SPLIT, True) + pytree_utils.FirstLeafNode(node), pytree_utils.Annotation.MUST_SPLIT, + True) diff --git a/yapf/yapflib/pytree_utils.py b/yapf/yapflib/pytree_utils.py index d89588fc6..999ba88bb 100644 --- a/yapf/yapflib/pytree_utils.py +++ b/yapf/yapflib/pytree_utils.py @@ -69,6 +69,18 @@ def NodeName(node): return pygram.python_grammar.number2symbol[node.type] +def FirstLeafNode(node): + if isinstance(node, pytree.Leaf): + return node + return FirstLeafNode(node.children[0]) + + +def LastLeafNode(node): + if isinstance(node, pytree.Leaf): + return node + return LastLeafNode(node.children[-1]) + + # lib2to3 thoughtfully provides pygram.python_grammar_no_print_statement for # parsing Python 3 code that wouldn't parse otherwise (when 'print' is used in a # context where a keyword is disallowed). diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index fe32e4996..416eda3bc 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -106,7 +106,8 @@ def Visit_funcdef(self, node): # pylint: disable=invalid-name _SetUnbreakable(node.children[colon_idx]) self.DefaultNodeVisit(node) if arrow_idx > 0: - _SetSplitPenalty(_LastChildNode(node.children[arrow_idx - 1]), 0) + _SetSplitPenalty( + pytree_utils.LastLeafNode(node.children[arrow_idx - 1]), 0) _SetUnbreakable(node.children[arrow_idx]) _SetStronglyConnected(node.children[arrow_idx + 1]) @@ -155,9 +156,10 @@ def Visit_argument(self, node): # pylint: disable=invalid-name while index < len(node.children) - 1: child = node.children[index] if isinstance(child, pytree.Leaf) and child.value == '=': - _SetSplitPenalty(_FirstChildNode(node.children[index]), NAMED_ASSIGN) _SetSplitPenalty( - _FirstChildNode(node.children[index + 1]), NAMED_ASSIGN) + pytree_utils.FirstLeafNode(node.children[index]), NAMED_ASSIGN) + _SetSplitPenalty( + pytree_utils.FirstLeafNode(node.children[index + 1]), NAMED_ASSIGN) index += 1 def Visit_tname(self, node): # pylint: disable=invalid-name @@ -167,9 +169,10 @@ def Visit_tname(self, node): # pylint: disable=invalid-name while index < len(node.children) - 1: child = node.children[index] if isinstance(child, pytree.Leaf) and child.value == ':': - _SetSplitPenalty(_FirstChildNode(node.children[index]), NAMED_ASSIGN) _SetSplitPenalty( - _FirstChildNode(node.children[index + 1]), NAMED_ASSIGN) + pytree_utils.FirstLeafNode(node.children[index]), NAMED_ASSIGN) + _SetSplitPenalty( + pytree_utils.FirstLeafNode(node.children[index + 1]), NAMED_ASSIGN) index += 1 def Visit_dotted_name(self, node): # pylint: disable=invalid-name @@ -203,10 +206,11 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name if (len(node.children[1].children) > 1 and pytree_utils.NodeName(node.children[1].children[1]) == 'comp_for'): # Don't penalize splitting before a comp_for expression. - _SetSplitPenalty(_FirstChildNode(node.children[1]), 0) + _SetSplitPenalty(pytree_utils.FirstLeafNode(node.children[1]), 0) else: _SetSplitPenalty( - _FirstChildNode(node.children[1]), ONE_ELEMENT_ARGUMENT) + pytree_utils.FirstLeafNode(node.children[1]), + ONE_ELEMENT_ARGUMENT) elif (pytree_utils.NodeName(node.children[0]) == 'LSQB' and len(node.children[1].children) > 2 and (name.endswith('_test') or name.endswith('_expr'))): @@ -219,9 +223,11 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name (name.endswith('_expr') and style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'))) if split_before: - _SetSplitPenalty(_LastChildNode(node.children[1].children[1]), 0) + _SetSplitPenalty( + pytree_utils.LastLeafNode(node.children[1].children[1]), 0) else: - _SetSplitPenalty(_FirstChildNode(node.children[1].children[2]), 0) + _SetSplitPenalty( + pytree_utils.FirstLeafNode(node.children[1].children[2]), 0) # Don't split the ending bracket of a subscript list. _SetVeryStronglyConnected(node.children[-1]) @@ -285,13 +291,15 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring subtypes = pytree_utils.GetNodeAnnotation( trailer.children[0], pytree_utils.Annotation.SUBTYPE) if subtypes and format_token.Subtype.SUBSCRIPT_BRACKET in subtypes: - _SetStronglyConnected(_FirstChildNode(trailer.children[1])) + _SetStronglyConnected( + pytree_utils.FirstLeafNode(trailer.children[1])) - last_child_node = _LastChildNode(trailer) + last_child_node = pytree_utils.LastLeafNode(trailer) if last_child_node.value.strip().startswith('#'): last_child_node = last_child_node.prev_sibling if not style.Get('DEDENT_CLOSING_BRACKETS'): - if _LastChildNode(last_child_node.prev_sibling).value != ',': + last = pytree_utils.LastLeafNode(last_child_node.prev_sibling) + if last.value != ',': if last_child_node.value == ']': _SetUnbreakable(last_child_node) else: @@ -313,7 +321,7 @@ def Visit_subscript(self, node): # pylint: disable=invalid-name def Visit_comp_for(self, node): # pylint: disable=invalid-name # comp_for ::= 'for' exprlist 'in' testlist_safe [comp_iter] - _SetSplitPenalty(_FirstChildNode(node), 0) + _SetSplitPenalty(pytree_utils.FirstLeafNode(node), 0) _SetStronglyConnected(*node.children[1:]) self.DefaultNodeVisit(node) @@ -331,10 +339,11 @@ def Visit_or_test(self, node): # pylint: disable=invalid-name index = 1 while index + 1 < len(node.children): if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'): - _DecrementSplitPenalty(_FirstChildNode(node.children[index]), OR_TEST) + _DecrementSplitPenalty( + pytree_utils.FirstLeafNode(node.children[index]), OR_TEST) else: _DecrementSplitPenalty( - _FirstChildNode(node.children[index + 1]), OR_TEST) + pytree_utils.FirstLeafNode(node.children[index + 1]), OR_TEST) index += 2 def Visit_and_test(self, node): # pylint: disable=invalid-name @@ -344,10 +353,11 @@ def Visit_and_test(self, node): # pylint: disable=invalid-name index = 1 while index + 1 < len(node.children): if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'): - _DecrementSplitPenalty(_FirstChildNode(node.children[index]), AND_TEST) + _DecrementSplitPenalty( + pytree_utils.FirstLeafNode(node.children[index]), AND_TEST) else: _DecrementSplitPenalty( - _FirstChildNode(node.children[index + 1]), AND_TEST) + pytree_utils.FirstLeafNode(node.children[index + 1]), AND_TEST) index += 2 def Visit_not_test(self, node): # pylint: disable=invalid-name @@ -359,8 +369,10 @@ def Visit_comparison(self, node): # pylint: disable=invalid-name # comparison ::= expr (comp_op expr)* self.DefaultNodeVisit(node) if len(node.children) == 3 and _StronglyConnectedCompOp(node): - _SetSplitPenalty(_FirstChildNode(node.children[1]), STRONGLY_CONNECTED) - _SetSplitPenalty(_FirstChildNode(node.children[2]), STRONGLY_CONNECTED) + _SetSplitPenalty( + pytree_utils.FirstLeafNode(node.children[1]), STRONGLY_CONNECTED) + _SetSplitPenalty( + pytree_utils.FirstLeafNode(node.children[2]), STRONGLY_CONNECTED) else: _IncreasePenalty(node, COMPARISON) @@ -381,7 +393,7 @@ def Visit_expr(self, node): # pylint: disable=invalid-name _SetSplitPenalty(child, style.Get('SPLIT_PENALTY_BITWISE_OPERATOR')) else: _SetSplitPenalty( - _FirstChildNode(node.children[index + 1]), + pytree_utils.FirstLeafNode(node.children[index + 1]), style.Get('SPLIT_PENALTY_BITWISE_OPERATOR')) index += 1 @@ -411,7 +423,7 @@ def Visit_arith_expr(self, node): # pylint: disable=invalid-name while index < len(node.children) - 1: child = node.children[index] if pytree_utils.NodeName(child) in self._ARITH_OPS: - next_node = _FirstChildNode(node.children[index + 1]) + next_node = pytree_utils.FirstLeafNode(node.children[index + 1]) _SetSplitPenalty(next_node, ARITH_EXPR) index += 1 @@ -426,7 +438,7 @@ def Visit_term(self, node): # pylint: disable=invalid-name while index < len(node.children) - 1: child = node.children[index] if pytree_utils.NodeName(child) in self._TERM_OPS: - next_node = _FirstChildNode(node.children[index + 1]) + next_node = pytree_utils.FirstLeafNode(node.children[index + 1]) _SetSplitPenalty(next_node, TERM) index += 1 @@ -446,7 +458,7 @@ def Visit_atom(self, node): # pylint: disable=invalid-name _SetSplitPenalty(node.children[-1], STRONGLY_CONNECTED) else: if len(node.children) > 2: - _SetSplitPenalty(_FirstChildNode(node.children[1]), EXPR) + _SetSplitPenalty(pytree_utils.FirstLeafNode(node.children[1]), EXPR) _SetSplitPenalty(node.children[-1], ATOM) elif node.children[0].value in '[{' and len(node.children) == 2: # Keep empty containers together if we can. @@ -461,7 +473,7 @@ def Visit_testlist_gexp(self, node): # pylint: disable=invalid-name prev_was_comma = True else: if prev_was_comma: - _SetSplitPenalty(_FirstChildNode(child), 0) + _SetSplitPenalty(pytree_utils.FirstLeafNode(child), 0) prev_was_comma = False ############################################################################ @@ -513,7 +525,7 @@ def RecExpression(node, first_child_leaf): for child in node.children: RecExpression(child, first_child_leaf) - RecExpression(node, _FirstChildNode(node)) + RecExpression(node, pytree_utils.FirstLeafNode(node)) def _IncreasePenalty(node, amt): @@ -533,7 +545,7 @@ def RecExpression(node, first_child_leaf): for child in node.children: RecExpression(child, first_child_leaf) - RecExpression(node, _FirstChildNode(node)) + RecExpression(node, pytree_utils.FirstLeafNode(node)) def _RecAnnotate(tree, annotate_name, annotate_value): @@ -559,8 +571,8 @@ def _RecAnnotate(tree, annotate_name, annotate_value): def _StronglyConnectedCompOp(op): if (len(op.children[1].children) == 2 and pytree_utils.NodeName(op.children[1]) == 'comp_op' and - _FirstChildNode(op.children[1]).value == 'not' and - _LastChildNode(op.children[1]).value == 'in'): + pytree_utils.FirstLeafNode(op.children[1]).value == 'not' and + pytree_utils.LastLeafNode(op.children[1]).value == 'in'): return True if (isinstance(op.children[1], pytree.Leaf) and op.children[1].value in {'==', 'in'}): @@ -598,15 +610,3 @@ def RecGetLeaves(node): if prev_child.lineno != child.lineno: _SetSplitPenalty(child, 0) prev_child = child - - -def _FirstChildNode(node): - if isinstance(node, pytree.Leaf): - return node - return _FirstChildNode(node.children[0]) - - -def _LastChildNode(node): - if isinstance(node, pytree.Leaf): - return node - return _LastChildNode(node.children[-1]) diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 8d3b7f44e..8bf3d8d97 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -96,7 +96,7 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name # Mark the first leaf of a key entry as a DICTIONARY_KEY. We # normally want to split before them if the dictionary cannot exist # on a single line. - if not unpacking or _GetFirstLeafNode(child).value == '**': + if not unpacking or pytree_utils.FirstLeafNode(child).value == '**': _AppendFirstLeafTokenSubtype(child, format_token.Subtype.DICTIONARY_KEY) _AppendSubtypeRec(child, format_token.Subtype.DICTIONARY_KEY_PART) @@ -384,8 +384,8 @@ def _InsertPseudoParentheses(node): comment_node = node.children[-1].clone() node.children[-1].remove() - first = _GetFirstLeafNode(node) - last = _GetLastLeafNode(node) + first = pytree_utils.FirstLeafNode(node) + last = pytree_utils.LastLeafNode(node) if first == last and first.type == token.COMMENT: # A comment was inserted before the value, which is a pytree.Leaf. @@ -396,8 +396,8 @@ def _InsertPseudoParentheses(node): node = new_node last.remove() - first = _GetFirstLeafNode(node) - last = _GetLastLeafNode(node) + first = pytree_utils.FirstLeafNode(node) + last = pytree_utils.LastLeafNode(node) lparen = pytree.Leaf( token.LPAR, u'(', context=('', (first.get_lineno(), first.column - 1))) @@ -426,15 +426,3 @@ def _InsertPseudoParentheses(node): new_node = pytree.Node(syms.atom, [lparen, clone, rparen]) node.replace(new_node) _AppendFirstLeafTokenSubtype(clone, format_token.Subtype.DICTIONARY_VALUE) - - -def _GetFirstLeafNode(node): - if isinstance(node, pytree.Leaf): - return node - return _GetFirstLeafNode(node.children[0]) - - -def _GetLastLeafNode(node): - if isinstance(node, pytree.Leaf): - return node - return _GetLastLeafNode(node.children[-1]) From aa21f7accd6d9adc2574c60292cff7f3406e197d Mon Sep 17 00:00:00 2001 From: Darien Hager Date: Fri, 30 Mar 2018 19:10:01 -0700 Subject: [PATCH 265/719] Add failing unit-test demonstrating that exclusion patterns can fail when using a relative target directory and trying to exclude a child hidden folder. --- yapftests/file_resources_test.py | 72 ++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 4440e074b..72ff5a653 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -14,6 +14,7 @@ # limitations under the License. """Tests for yapf.file_resources.""" +import contextlib import os import shutil import tempfile @@ -26,6 +27,14 @@ from yapftests import utils +@contextlib.contextmanager +def _restore_working_dir(): + curdir = os.getcwd() + try: + yield + finally: + os.chdir(curdir) + class GetDefaultStyleForDirTest(unittest.TestCase): def setUp(self): @@ -138,6 +147,69 @@ def test_recursive_find_in_dir_with_exclude(self): os.path.join(tdir2, 'testfile2.py'), ])) + def test_find_with_excluded_hidden_dirs(self): + tdir1 = self._make_test_dir('.test1') + tdir2 = self._make_test_dir('test_2') + tdir3 = self._make_test_dir('test.3') + files = [ + os.path.join(tdir1, 'testfile1.py'), + os.path.join(tdir2, 'testfile2.py'), + os.path.join(tdir3, 'testfile3.py'), + ] + _touch_files(files) + + actual = file_resources.GetCommandLineFiles( + [self.test_tmpdir], recursive=True, exclude=['*.test1*']) + + self.assertEqual( + sorted( + actual + ), + sorted([ + os.path.join(tdir2, 'testfile2.py'), + os.path.join(tdir3, 'testfile3.py'), + ])) + + def test_find_with_excluded_hidden_dirs_relative(self): + """ + A regression test against a specific case where a hidden directory (one + beginning with a period) is being excluded, but it is also an immediate + child of the current directory which has been specified in a relative + manner. + + At its core, the bug has to do with overzelous stripping of "./foo" so that + it removes too much from "./.foo" . + """ + tdir1 = self._make_test_dir('.test1') + tdir2 = self._make_test_dir('test_2') + tdir3 = self._make_test_dir('test.3') + files = [ + os.path.join(tdir1, 'testfile1.py'), + os.path.join(tdir2, 'testfile2.py'), + os.path.join(tdir3, 'testfile3.py'), + ] + _touch_files(files) + + # We must temporarily change the current directory, so that we test against + # patterns like ./.test1/file instead of /tmp/foo/.test1/file + with _restore_working_dir(): + + os.chdir(self.test_tmpdir) + actual = file_resources.GetCommandLineFiles( + [os.path.relpath(self.test_tmpdir)], + recursive=True, exclude=['*.test1*']) + + self.assertEqual( + sorted( + actual + ), + sorted([ + os.path.join(os.path.relpath(self.test_tmpdir), + os.path.basename(tdir2), 'testfile2.py'), + os.path.join(os.path.relpath(self.test_tmpdir), + os.path.basename(tdir3), 'testfile3.py'), + ])) + def test_find_with_excluded_dirs(self): tdir1 = self._make_test_dir('test1') tdir2 = self._make_test_dir('test2/testinner/') From 194ab7d42e28455c675966116ca05702c431859d Mon Sep 17 00:00:00 2001 From: Darien Hager Date: Fri, 30 Mar 2018 19:10:55 -0700 Subject: [PATCH 266/719] Fix issue with matching against hidden child folders in relative-directory context. --- yapf/yapflib/file_resources.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 5468ced43..67eea61bb 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -148,7 +148,10 @@ def _FindPythonFiles(filenames, recursive, exclude): def IsIgnored(path, exclude): """Return True if filename matches any patterns in exclude.""" - return any(fnmatch.fnmatch(path.lstrip('./'), e.rstrip('/')) for e in exclude) + path = path.lstrip("/") + while path.startswith("./"): + path = path[2:] + return any(fnmatch.fnmatch(path, e.rstrip('/')) for e in exclude) def IsPythonFile(filename): From a5a084f095ecc8416c4eb87b2dd6d8921889af0d Mon Sep 17 00:00:00 2001 From: Darien Hager Date: Fri, 30 Mar 2018 19:29:26 -0700 Subject: [PATCH 267/719] Apply formatting patch that Travis CI is suggesting for the PR --- yapftests/file_resources_test.py | 36 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 72ff5a653..5f06e3e6b 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -35,6 +35,7 @@ def _restore_working_dir(): finally: os.chdir(curdir) + class GetDefaultStyleForDirTest(unittest.TestCase): def setUp(self): @@ -159,12 +160,10 @@ def test_find_with_excluded_hidden_dirs(self): _touch_files(files) actual = file_resources.GetCommandLineFiles( - [self.test_tmpdir], recursive=True, exclude=['*.test1*']) + [self.test_tmpdir], recursive=True, exclude=['*.test1*']) self.assertEqual( - sorted( - actual - ), + sorted(actual), sorted([ os.path.join(tdir2, 'testfile2.py'), os.path.join(tdir3, 'testfile3.py'), @@ -184,9 +183,9 @@ def test_find_with_excluded_hidden_dirs_relative(self): tdir2 = self._make_test_dir('test_2') tdir3 = self._make_test_dir('test.3') files = [ - os.path.join(tdir1, 'testfile1.py'), - os.path.join(tdir2, 'testfile2.py'), - os.path.join(tdir3, 'testfile3.py'), + os.path.join(tdir1, 'testfile1.py'), + os.path.join(tdir2, 'testfile2.py'), + os.path.join(tdir3, 'testfile3.py'), ] _touch_files(files) @@ -196,19 +195,20 @@ def test_find_with_excluded_hidden_dirs_relative(self): os.chdir(self.test_tmpdir) actual = file_resources.GetCommandLineFiles( - [os.path.relpath(self.test_tmpdir)], - recursive=True, exclude=['*.test1*']) + [os.path.relpath(self.test_tmpdir)], + recursive=True, + exclude=['*.test1*']) self.assertEqual( - sorted( - actual - ), - sorted([ - os.path.join(os.path.relpath(self.test_tmpdir), - os.path.basename(tdir2), 'testfile2.py'), - os.path.join(os.path.relpath(self.test_tmpdir), - os.path.basename(tdir3), 'testfile3.py'), - ])) + sorted(actual), + sorted([ + os.path.join( + os.path.relpath(self.test_tmpdir), os.path.basename(tdir2), + 'testfile2.py'), + os.path.join( + os.path.relpath(self.test_tmpdir), os.path.basename(tdir3), + 'testfile3.py'), + ])) def test_find_with_excluded_dirs(self): tdir1 = self._make_test_dir('test1') From ca30e7627023281a94b4e66575c7c67522f933c7 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 30 Mar 2018 20:45:14 -0700 Subject: [PATCH 268/719] Start new wrapped line only if comment is first item in decorator node --- CHANGELOG | 2 ++ yapf/yapflib/blank_line_calculator.py | 2 -- yapf/yapflib/identify_container.py | 2 -- yapf/yapflib/pytree_unwrapper.py | 3 ++- yapftests/reformatter_buganizer_test.py | 20 +++++++++++++++++++- 5 files changed, 23 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 7dc793cb2..6970b8d05 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,6 +19,8 @@ - Attempt to determine if long lambdas are allowed. This can be done on a case-by-case basis with a "pylint" disable comment. - A comment before a decorator isn't part of the decorator's line. +- Only force a new wrapped line after a comment in a decorator when it's the + first token in the decorator. ## [0.21.0] 2018-03-18 ### Added diff --git a/yapf/yapflib/blank_line_calculator.py b/yapf/yapflib/blank_line_calculator.py index 0a4fcc2a9..c239ee7eb 100644 --- a/yapf/yapflib/blank_line_calculator.py +++ b/yapf/yapflib/blank_line_calculator.py @@ -22,8 +22,6 @@ newlines: The number of newlines required before the node. """ -from lib2to3 import pytree - from yapf.yapflib import py3compat from yapf.yapflib import pytree_utils from yapf.yapflib import pytree_visitor diff --git a/yapf/yapflib/identify_container.py b/yapf/yapflib/identify_container.py index 23630c505..5c5fc5bf0 100644 --- a/yapf/yapflib/identify_container.py +++ b/yapf/yapflib/identify_container.py @@ -19,8 +19,6 @@ IdentifyContainers(): the main function exported by this module. """ -from lib2to3 import pytree - from yapf.yapflib import pytree_utils from yapf.yapflib import pytree_visitor diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index 049dbbb5d..550bc89d1 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -225,7 +225,8 @@ def Visit_async_stmt(self, node): # pylint: disable=invalid-name def Visit_decorator(self, node): # pylint: disable=invalid-name for child in node.children: self.Visit(child) - if pytree_utils.NodeName(child) == 'COMMENT': + if (pytree_utils.NodeName(child) == 'COMMENT' and + child == node.children[0]): self._StartNewLine() def Visit_decorators(self, node): # pylint: disable=invalid-name diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index ffb6ded5e..519b0f16b 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,7 +28,25 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) - def testB65546221(self): + def testB77329955(self): + code = """\ +class _(): + + @parameterized.named_parameters( + ('ReadyExpiredSuccess', True, True, True, None, None), + ('SpannerUpdateFails', True, False, True, None, None), + ('ReadyNotExpired', False, True, True, True, None), + # ('ReadyNotExpiredNotHealthy', False, True, True, False, True), + # ('ReadyNotExpiredNotHealthyErrorFails', False, True, True, False, False + # ('ReadyNotExpiredNotHealthyUpdateFails', False, False, True, False, True + ) + def _(): + pass +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB65197969(self): unformatted_code = """\ class _(): From c4e24c3a5b13bc78d428738423dee3083ff838fd Mon Sep 17 00:00:00 2001 From: cardenb Date: Wed, 4 Apr 2018 16:31:44 -0700 Subject: [PATCH 269/719] Added an option to split on all args even if not comma terminated. --- yapf/yapflib/format_decision_state.py | 7 +++++++ yapf/yapflib/style.py | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 4e62f80bf..c0a3346ba 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -375,6 +375,13 @@ def SurroundedByParens(token): if previous.value in '(,': if opening.matching_bracket.previous_token.value == ',': return True + if style.Get('SPLIT_ARGUMENTS'): + # Split before arguments in a function call or definition if the + # arguments are terminated by a comma. + opening = _GetOpeningBracket(current) + if opening and opening.previous_token and opening.previous_token.is_name: + if previous.value in '(,' and opening.matching_bracket: + return True if ((current.is_name or current.value in {'*', '**'}) and previous.value == ','): diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 6f14fad82..511513e0c 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -175,6 +175,8 @@ def method(): SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=textwrap.dedent("""\ Split before arguments if the argument list is terminated by a comma."""), + SPLIT_ARGUMENTS=textwrap.dedent("""\ + Split before arguments"""), SPLIT_BEFORE_BITWISE_OPERATOR=textwrap.dedent("""\ Set to True to prefer splitting before '&', '|' or '^' rather than after."""), @@ -282,6 +284,7 @@ def CreatePEP8Style(): SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=False, SPACES_BEFORE_COMMENT=2, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False, + SPLIT_ARGUMENTS=False, SPLIT_BEFORE_BITWISE_OPERATOR=True, SPLIT_BEFORE_CLOSING_BRACKET=True, SPLIT_BEFORE_DICT_SET_GENERATOR=True, @@ -429,6 +432,7 @@ def _BoolConverter(s): SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=_BoolConverter, SPACES_BEFORE_COMMENT=int, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter, + SPLIT_ARGUMENTS=_BoolConverter, SPLIT_BEFORE_BITWISE_OPERATOR=_BoolConverter, SPLIT_BEFORE_CLOSING_BRACKET=_BoolConverter, SPLIT_BEFORE_DICT_SET_GENERATOR=_BoolConverter, From 22322d6fb531362806929e7c3aabf58bfa921f8a Mon Sep 17 00:00:00 2001 From: Mike Stipicevic Date: Mon, 16 Apr 2018 17:09:38 +0200 Subject: [PATCH 270/719] Add and update documentation about return codes --- README.rst | 11 +++++++++++ yapf/__init__.py | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index ccc74d97f..f67f72eed 100644 --- a/README.rst +++ b/README.rst @@ -126,6 +126,17 @@ Options:: -vv, --verbose Print out file names while processing +------------ +Return Codes +------------ + +Normally YAPF returns zero on successful program termination and non-zero otherwise. + +If ``--diff`` is supplied, YAPF returns zero when no changes were necessary, non-zero +otherwise (including program error). You can use this in a CI workflow to test that code +has been YAPF-formatted. + + Formatting style ================ diff --git a/yapf/__init__.py b/yapf/__init__.py index 0322b31ab..6281f0784 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -49,7 +49,8 @@ def main(argv): in argv[0]). Returns: - 0 if there were no changes, non-zero otherwise. + Zero on successful program termination, non-zero otherwise. + With --diff: zero if there were no changes, non-zero otherwise. Raises: YapfError: if none of the supplied files were Python files. From 20b03d5166221fac8741b17d86681c7e2af0c275 Mon Sep 17 00:00:00 2001 From: cardenb Date: Sun, 13 May 2018 18:56:21 -0700 Subject: [PATCH 271/719] Changed logic for splitting comma separated values and added unittests for it. --- yapf/yapflib/format_decision_state.py | 10 ++-- yapf/yapflib/style.py | 6 +-- yapftests/reformatter_basic_test.py | 74 ++++++++++++++++----------- 3 files changed, 51 insertions(+), 39 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index c0a3346ba..a5d03de31 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -180,6 +180,9 @@ def MustSplit(self): if not previous: return False + if style.Get('SPLIT_ALL_COMMA_SEPARATED_VALUES') and previous.value == ',': + return True + if (self.stack[-1].split_before_closing_bracket and current.value in '}]' and style.Get('SPLIT_BEFORE_CLOSING_BRACKET')): # Split before the closing bracket if we can. @@ -375,13 +378,6 @@ def SurroundedByParens(token): if previous.value in '(,': if opening.matching_bracket.previous_token.value == ',': return True - if style.Get('SPLIT_ARGUMENTS'): - # Split before arguments in a function call or definition if the - # arguments are terminated by a comma. - opening = _GetOpeningBracket(current) - if opening and opening.previous_token and opening.previous_token.is_name: - if previous.value in '(,' and opening.matching_bracket: - return True if ((current.is_name or current.value in {'*', '**'}) and previous.value == ','): diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 511513e0c..e4d21f319 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -175,7 +175,7 @@ def method(): SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=textwrap.dedent("""\ Split before arguments if the argument list is terminated by a comma."""), - SPLIT_ARGUMENTS=textwrap.dedent("""\ + SPLIT_ALL_COMMA_SEPARATED_VALUES=textwrap.dedent("""\ Split before arguments"""), SPLIT_BEFORE_BITWISE_OPERATOR=textwrap.dedent("""\ Set to True to prefer splitting before '&', '|' or '^' rather than @@ -284,7 +284,7 @@ def CreatePEP8Style(): SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=False, SPACES_BEFORE_COMMENT=2, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False, - SPLIT_ARGUMENTS=False, + SPLIT_ALL_COMMA_SEPARATED_VALUES=False, SPLIT_BEFORE_BITWISE_OPERATOR=True, SPLIT_BEFORE_CLOSING_BRACKET=True, SPLIT_BEFORE_DICT_SET_GENERATOR=True, @@ -432,7 +432,7 @@ def _BoolConverter(s): SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=_BoolConverter, SPACES_BEFORE_COMMENT=int, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter, - SPLIT_ARGUMENTS=_BoolConverter, + SPLIT_ALL_COMMA_SEPARATED_VALUES=_BoolConverter, SPLIT_BEFORE_BITWISE_OPERATOR=_BoolConverter, SPLIT_BEFORE_CLOSING_BRACKET=_BoolConverter, SPLIT_BEFORE_DICT_SET_GENERATOR=_BoolConverter, diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 01ed3d9b6..406449a35 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -28,36 +28,52 @@ class BasicReformatterTest(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) - def testSimple(self): - unformatted_code = textwrap.dedent("""\ - if a+b: + def testSplittingAllArgs(self): + style.SetGlobalStyle(style.CreateStyleFromConfig('{split_all_comma_separated_values: true, column_limit: 40}')) + unformatted_code = textwrap.dedent("""\ + responseDict = {"timestamp": timestamp, "someValue": value, "whatever": 120} + """) + expected_formatted_code = textwrap.dedent("""\ + responseDict = { + "timestamp": timestamp, + "someValue": value, + "whatever": 120 + } + """) + unformatted_code = textwrap.dedent("""\ + def foo(long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def foo(long_arg, + really_long_arg, + really_really_long_arg, + cant_keep_all_these_args): pass - """) - expected_formatted_code = textwrap.dedent("""\ - if a + b: - pass - """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - - def testSimpleFunctions(self): - unformatted_code = textwrap.dedent("""\ - def g(): - pass - - def f(): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - def g(): - pass - - - def f(): - pass - """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + unformatted_code = textwrap.dedent("""\ + foo_tuple = [long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args] + """) + expected_formatted_code = textwrap.dedent("""\ + foo_tuple = [ + long_arg, + really_long_arg, + really_really_long_arg, + cant_keep_all_these_args + ] + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + unformatted_code = textwrap.dedent("""\ + foo_tuple = [short, arg] + """) + expected_formatted_code = textwrap.dedent("""\ + foo_tuple = [short, arg] + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSimpleFunctionsWithTrailingComments(self): unformatted_code = textwrap.dedent("""\ From e1daa6323f4ea348d64706545befc5a580e5328f Mon Sep 17 00:00:00 2001 From: cardenb Date: Mon, 14 May 2018 22:41:56 -0700 Subject: [PATCH 272/719] Changed some code formatting errors (irony is apparent to me here). --- yapftests/reformatter_basic_test.py | 32 +++++++++++++++-------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 406449a35..360aae41e 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -29,34 +29,36 @@ def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) def testSplittingAllArgs(self): - style.SetGlobalStyle(style.CreateStyleFromConfig('{split_all_comma_separated_values: true, column_limit: 40}')) - unformatted_code = textwrap.dedent("""\ + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{split_all_comma_separated_values: true, column_limit: 40}')) + unformatted_code = textwrap.dedent("""\ responseDict = {"timestamp": timestamp, "someValue": value, "whatever": 120} """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent("""\ responseDict = { "timestamp": timestamp, "someValue": value, "whatever": 120 } """) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ def foo(long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent("""\ def foo(long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - unformatted_code = textwrap.dedent("""\ + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + unformatted_code = textwrap.dedent("""\ foo_tuple = [long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args] """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent("""\ foo_tuple = [ long_arg, really_long_arg, @@ -64,16 +66,16 @@ def foo(long_arg, cant_keep_all_these_args ] """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - unformatted_code = textwrap.dedent("""\ + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + unformatted_code = textwrap.dedent("""\ foo_tuple = [short, arg] """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent("""\ foo_tuple = [short, arg] """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSimpleFunctionsWithTrailingComments(self): unformatted_code = textwrap.dedent("""\ From 77bf2f9fe3b5115d2602b6c4e802c50de29ca7de Mon Sep 17 00:00:00 2001 From: cardenb Date: Mon, 14 May 2018 22:54:12 -0700 Subject: [PATCH 273/719] Added to the changelong. --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 6970b8d05..2533c5f4d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,9 @@ ### Added - The `BLANK_LINE_BEFORE_MODULE_DOCSTRING` knob adds a blank line before a module's docstring. +- The `SPLIT_ALL_COMMA_SEPARATED_VALUES` knob causes all lists, tuples, dicts + function defs, etc... to split on all values, instead of maximizing the + number of elements on each line, when not able to fit on a single line. ### Changed - Improve the heuristic we use to determine when to split at the start of a function call. First check whether or not all elements can fit in the space From 009b780c658a817ccc08e53ffadc39b15a7c8e11 Mon Sep 17 00:00:00 2001 From: cardenb Date: Tue, 15 May 2018 11:40:28 -0700 Subject: [PATCH 274/719] Documented the SPLIT_ALL_COMMA_SEPARATED_VALUES knob in the README. --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index ccc74d97f..2e4ed1e02 100644 --- a/README.rst +++ b/README.rst @@ -465,6 +465,10 @@ Knobs ``SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED`` Split before arguments if the argument list is terminated by a comma. +``SPLIT_ALL_COMMA_SEPARATED_VALUES`` + If a comma separated list (dict, list, tuple, or function def) is on a + line that is too long, split such that all elements are on a single line. + ``SPLIT_BEFORE_BITWISE_OPERATOR`` Set to ``True`` to prefer splitting before ``&``, ``|`` or ``^`` rather than after. From 93aca751a946f196bc64ddfdc3621a764e243cc4 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 15 May 2018 22:24:24 -0700 Subject: [PATCH 275/719] Bump version to v0.22.0 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 2533c5f4d..b6782a3de 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## Unreleased +## [0.22.0] 2018-05-15 ### Added - The `BLANK_LINE_BEFORE_MODULE_DOCSTRING` knob adds a blank line before a module's docstring. diff --git a/yapf/__init__.py b/yapf/__init__.py index 6281f0784..10061acb8 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.21.0' +__version__ = '0.22.0' def main(argv): From dd1644653cf9ce588cc756b64e7b6f2323899529 Mon Sep 17 00:00:00 2001 From: Dick Marinus Date: Sun, 20 May 2018 21:27:52 +0200 Subject: [PATCH 276/719] initial version, include missing files in MANIFEST.in --- MANIFEST.in | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 MANIFEST.in diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 000000000..5c70a558a --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,4 @@ +include HACKING.rst LICENSE AUTHORS CHANGELOG CONTRIBUTING.rst CONTRIBUTORS +include .coveragerc .editorconfig .flake8 plugins/README.rst +include plugins/vim/autoload/yapf.vim plugins/vim/plugin/yapf.vim pylintrc +include .style.yapf tox.ini .travis.yml .vimrc From ded5d1bf64a70f643f1c7ecd2caf6f6bd3d19b4e Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 21 May 2018 14:29:10 -0700 Subject: [PATCH 277/719] Don't increase N_TOKENS. Closes #571 --- CHANGELOG | 5 +++++ yapf/yapflib/format_token.py | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index b6782a3de..e845388e7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,11 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.22.1] UNRELEASED +### Fixed +- There's no need to increase N_TOKENS. In fact, it causes other things which + use lib2to3 to fail if called from YAPF. + ## [0.22.0] 2018-05-15 ### Added - The `BLANK_LINE_BEFORE_MODULE_DOCSTRING` knob adds a blank line before a diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 4530cb84e..ef04e4eb2 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -26,7 +26,6 @@ from yapf.yapflib import style CONTINUATION = token.N_TOKENS -token.N_TOKENS += 1 class Subtype(object): From 7e23cd8b8a07c6118a5a8fe86641b21546b560d4 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 21 May 2018 14:56:15 -0700 Subject: [PATCH 278/719] Fix lint warnings. --- yapf/yapflib/file_resources.py | 4 ++-- yapftests/file_resources_test.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 67eea61bb..764e2d656 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -148,8 +148,8 @@ def _FindPythonFiles(filenames, recursive, exclude): def IsIgnored(path, exclude): """Return True if filename matches any patterns in exclude.""" - path = path.lstrip("/") - while path.startswith("./"): + path = path.lstrip('/') + while path.startswith('./'): path = path[2:] return any(fnmatch.fnmatch(path, e.rstrip('/')) for e in exclude) diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 5f06e3e6b..70cea46e6 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -170,7 +170,8 @@ def test_find_with_excluded_hidden_dirs(self): ])) def test_find_with_excluded_hidden_dirs_relative(self): - """ + """Test find with excluded hidden dirs. + A regression test against a specific case where a hidden directory (one beginning with a period) is being excluded, but it is also an immediate child of the current directory which has been specified in a relative From 29955ca8e0f19844858167384d97dace1942c09f Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 21 May 2018 23:50:24 -0700 Subject: [PATCH 279/719] Fix ReST formatting. Closes #572 --- README.rst | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 99412e57c..4b2e1d0fb 100644 --- a/README.rst +++ b/README.rst @@ -51,13 +51,13 @@ Installation To install YAPF from PyPI: -.. code-block:: +.. code-block:: shell $ pip install yapf (optional) If you are using Python 2.7 and want to enable multiprocessing: -.. code-block:: +.. code-block:: shell $ pip install futures @@ -70,7 +70,7 @@ library, installation is not necessary. YAPF supports being run as a directory by the Python interpreter. If you cloned/unzipped YAPF into ``DIR``, it's possible to run: -.. code-block:: +.. code-block:: shell $ PYTHONPATH=DIR python DIR/yapf [options] ... @@ -151,7 +151,7 @@ file that specifies the desired style, or a dictionary of key/value pairs. The config file is a simple listing of (case-insensitive) ``key = value`` pairs with a ``[style]`` heading. For example: -.. code-block:: +.. code-block:: ini [style] based_on_style = pep8 @@ -164,7 +164,7 @@ custom style is based on (think of it like subclassing). It's also possible to do the same on the command line with a dictionary. For example: -.. code-block:: +.. code-block:: shell --style='{based_on_style: chromium, indent_width: 4}' @@ -583,6 +583,7 @@ Knobs (Potentially) Frequently Asked Questions ======================================== +-------------------------------------------- Why does YAPF destroy my awesome formatting? -------------------------------------------- @@ -624,6 +625,7 @@ To preserve the nice dedented closing brackets, use the brackets, including function definitions and calls, are going to use that style. This provides consistency across the formatted codebase. +------------------------------- Why Not Improve Existing Tools? ------------------------------- @@ -632,6 +634,7 @@ designed to come up with the best formatting possible. Existing tools were created with different goals in mind, and would require extensive modifications to convert to using clang-format's algorithm. +----------------------------- Can I Use YAPF In My Program? ----------------------------- @@ -642,6 +645,7 @@ tool. This means that a tool or IDE plugin is free to use YAPF. Gory Details ============ +---------------- Algorithm Design ---------------- From 81a9de33ae33a1cd14fef955701b9d8c98f38947 Mon Sep 17 00:00:00 2001 From: Cyril Jouve Date: Mon, 4 Jun 2018 23:44:44 +0200 Subject: [PATCH 280/719] avoid reading whole file in IsPythonFile --- yapf/yapflib/file_resources.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 764e2d656..6e7202d10 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -178,8 +178,8 @@ def IsPythonFile(filename): try: with py3compat.open_with_encoding( filename, mode='r', encoding=encoding) as fd: - first_line = fd.readlines()[0] - except (IOError, IndexError): + first_line = fd.readline(256) + except IOError: return False return re.match(r'^#!.*\bpython[23]?\b', first_line) From 0cf19571fc4cfdd98fbd4c3ef351caf045f91005 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 11 Jun 2018 21:51:41 -0700 Subject: [PATCH 281/719] Don't count "pytype" comments as column violations --- yapf/yapflib/format_decision_state.py | 3 ++- yapf/yapflib/format_token.py | 5 +++++ yapf/yapflib/reformatter.py | 2 +- yapftests/reformatter_buganizer_test.py | 10 ++++++++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index a5d03de31..bff8ea3e2 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -652,7 +652,8 @@ def MoveStateToNextToken(self): # Calculate the penalty for overflowing the column limit. penalty = 0 - if not current.is_pylint_comment and self.column > self.column_limit: + if (not current.is_pylint_comment and not current.is_pytype_comment and + self.column > self.column_limit): excess_characters = self.column - self.column_limit penalty += style.Get('SPLIT_PENALTY_EXCESS_CHARACTER') * excess_characters diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index ef04e4eb2..79dced4af 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -332,3 +332,8 @@ def is_pseudo_paren(self): def is_pylint_comment(self): return self.is_comment and re.match(r'#.*\bpylint:\s*(disable|enable)=', self.value) + + @property + def is_pytype_comment(self): + return self.is_comment and re.match(r'#.*\bpytype:\s*(disable|enable)=', + self.value) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 0485d7e79..6539e68e9 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -238,7 +238,7 @@ def _CanPlaceOnSingleLine(uwline): indent_amt = style.Get('INDENT_WIDTH') * uwline.depth last = uwline.last last_index = -1 - if last.is_pylint_comment: + if last.is_pylint_comment or last.is_pytype_comment: last = last.previous_token last_index = -2 if last is None: diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 519b0f16b..6a1c78153 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,16 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB77923341(self): + code = """\ +def f(): + if (aaaaaaaaaaaaaa.bbbbbbbbbbbb.ccccc <= 0 and # pytype: disable=attribute-error + ddddddddddd.eeeeeeeee == constants.FFFFFFFFFFFFFF): + raise "yo" +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB77329955(self): code = """\ class _(): From 21cf67d6e71d90de206ab9b34a6a37c640d6b034 Mon Sep 17 00:00:00 2001 From: Lawrence Coleman Date: Tue, 19 Jun 2018 16:42:30 -0500 Subject: [PATCH 282/719] Add comments for pipenv support pipenv no longer installs to the running virtual environment, and instead must be separately activated. The added commented lines run yapf inside of the pre-generated virtual environment generated by pipenv. --- plugins/pre-commit.sh | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/plugins/pre-commit.sh b/plugins/pre-commit.sh index acd46c68f..896f0ffba 100644 --- a/plugins/pre-commit.sh +++ b/plugins/pre-commit.sh @@ -27,12 +27,23 @@ if [ ! "$PYTHON_FILES" ]; then exit 0 fi +########## PIP VERSION ############# # Verify that yapf is installed; if not, warn and exit. if [ -z $(which yapf) ]; then echo 'yapf not on path; can not format. Please install yapf:' echo ' pip install yapf' exit 2 fi +######### END PIP VERSION ########## + +########## PIPENV VERSION ########## +# if [ -z $(pipenv run which yapf) ]; then +# echo 'yapf not on path; can not format. Please install yapf:' +# echo ' pipenv install yapf' +# exit 2 +# fi +###### END PIPENV VERSION ########## + # Check for unstaged changes to files in the index. CHANGED_FILES=(`git diff --name-only ${PYTHON_FILES[@]}`) @@ -47,10 +58,20 @@ if [ "$CHANGED_FILES" ]; then done exit 1 fi + # Format all staged files, then exit with an error code if any have uncommitted # changes. echo 'Formatting staged Python files . . .' + +########## PIP VERSION ############# yapf -i -r ${PYTHON_FILES[@]} +######### END PIP VERSION ########## + +########## PIPENV VERSION ########## +# pipenv run yapf -i -r ${PYTHON_FILES[@]} +###### END PIPENV VERSION ########## + + CHANGED_FILES=(`git diff --name-only ${PYTHON_FILES[@]}`) if [ "$CHANGED_FILES" ]; then echo 'Reformatted staged files. Please review and stage the changes.' From 3fd96db62ad68b1bd0bb39511c83db2db4c2e2ec Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 1 Jul 2018 22:17:25 -0700 Subject: [PATCH 283/719] Improve documentation so quotes aren't included Closes #583 --- README.rst | 2 +- yapf/yapflib/style.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 4b2e1d0fb..120acac64 100644 --- a/README.rst +++ b/README.rst @@ -457,7 +457,7 @@ Knobs 1 + 2 * 3 - 4 / 5 - will be formatted as follows when configured with a value ``"*,/"``: + will be formatted as follows when configured with ``*,/``: .. code-block:: python diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index e4d21f319..c0920c512 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -158,7 +158,7 @@ def method(): 1 + 2 * 3 - 4 / 5 - will be formatted as follows when configured with a value "*,/": + will be formatted as follows when configured with *,/: 1 + 2*3 - 4/5 From 5a3bd52e3933ef3385f2738cd332b7b52a2c45d5 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 1 Jul 2018 22:25:30 -0700 Subject: [PATCH 284/719] Change error message instead of cloning exception Closes #582 --- CHANGELOG | 2 ++ yapf/yapflib/yapf_api.py | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index e845388e7..767043a11 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,8 @@ ### Fixed - There's no need to increase N_TOKENS. In fact, it causes other things which use lib2to3 to fail if called from YAPF. +- Change the exception message instead of creating a new one that's just a + clone. ## [0.22.0] 2018-05-15 ### Added diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index b78128524..d22beed7f 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -128,7 +128,8 @@ def FormatCode(unformatted_source, try: tree = pytree_utils.ParseCodeToTree(unformatted_source) except parse.ParseError as e: - raise parse.ParseError(filename + ': ' + e.message) + e.message = filename + ': ' + e.message + raise # Run passes on the tree, modifying it in place. comment_splicer.SpliceComments(tree) From 93f91a47fd9f75d359e4eb78dee1614d42f4730b Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 1 Jul 2018 22:29:36 -0700 Subject: [PATCH 285/719] Specify that we read from stdin by default Closes #555 --- yapf/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 10061acb8..22ab014c0 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -127,7 +127,8 @@ def main(argv): action='store_true', help='Print out file names while processing') - parser.add_argument('files', nargs='*') + parser.add_argument( + 'files', nargs='*', help='Reads from stdin when no files are specified.') args = parser.parse_args(argv[1:]) if args.version: From 39acc823d76a2c2f58a27af91ee594ef96c0a237 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 1 Jul 2018 23:02:35 -0700 Subject: [PATCH 286/719] Add knob disabling comma ending heuristic --- CHANGELOG | 5 ++++- README.rst | 4 ++++ yapf/yapflib/pytree_unwrapper.py | 3 +++ yapf/yapflib/style.py | 5 +++++ yapftests/reformatter_basic_test.py | 15 +++++++++++++++ 5 files changed, 31 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 767043a11..4693f039e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.22.1] UNRELEASED +## [0.23.0] UNRELEASED +### Added +- `DISABLE_ENDING_COMMA_HEURISTIC` is a new knob to disable the heuristic which + splits a list onto separate lines if the list is comma-terminated. ### Fixed - There's no need to increase N_TOKENS. In fact, it causes other things which use lib2to3 to fail if called from YAPF. diff --git a/README.rst b/README.rst index 120acac64..19ef0c21a 100644 --- a/README.rst +++ b/README.rst @@ -415,6 +415,10 @@ Knobs end_ts=now(), ) # <--- this bracket is dedented and on a separate line +``DISABLE_ENDING_COMMA_HEURISTIC`` + Disable the heuristic which places each list element on a separate line if + the list is comma-terminated. + ``EACH_DICT_ENTRY_ON_SEPARATE_LINE`` Place each dictionary entry onto its own line. diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index 550bc89d1..0d371ae19 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -34,6 +34,7 @@ from yapf.yapflib import pytree_utils from yapf.yapflib import pytree_visitor from yapf.yapflib import split_penalty +from yapf.yapflib import style from yapf.yapflib import unwrapped_line @@ -342,6 +343,8 @@ def _AdjustSplitPenalty(uwline): def _DetermineMustSplitAnnotation(node): """Enforce a split in the list if the list ends with a comma.""" + if style.Get('DISABLE_ENDING_COMMA_HEURISTIC'): + return if not _ContainsComments(node): token = next(node.parent.leaves()) if token.value == '(': diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index c0920c512..61442468b 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -129,6 +129,9 @@ def method(): start_ts=now()-timedelta(days=3), end_ts=now(), ) # <--- this bracket is dedented and on a separate line"""), + DISABLE_ENDING_COMMA_HEURISTIC=textwrap.dedent("""\ + Disable the heuristic which places each list element on a separate line + if the list is comma-terminated."""), EACH_DICT_ENTRY_ON_SEPARATE_LINE=textwrap.dedent("""\ Place each dictionary entry onto its own line."""), I18N_COMMENT=textwrap.dedent("""\ @@ -272,6 +275,7 @@ def CreatePEP8Style(): CONTINUATION_ALIGN_STYLE='SPACE', CONTINUATION_INDENT_WIDTH=4, DEDENT_CLOSING_BRACKETS=False, + DISABLE_ENDING_COMMA_HEURISTIC=False, EACH_DICT_ENTRY_ON_SEPARATE_LINE=True, I18N_COMMENT='', I18N_FUNCTION_CALL='', @@ -420,6 +424,7 @@ def _BoolConverter(s): CONTINUATION_ALIGN_STYLE=_ContinuationAlignStyleStringConverter, CONTINUATION_INDENT_WIDTH=int, DEDENT_CLOSING_BRACKETS=_BoolConverter, + DISABLE_ENDING_COMMA_HEURISTIC=_BoolConverter, EACH_DICT_ENTRY_ON_SEPARATE_LINE=_BoolConverter, I18N_COMMENT=str, I18N_FUNCTION_CALL=_StringListConverter, diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 360aae41e..2078b094c 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2490,6 +2490,21 @@ def bar(self): finally: style.SetGlobalStyle(style.CreateChromiumStyle()) + def testDisableEndingCommaHeuristic(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: chromium,' + ' disable_ending_comma_heuristic: True}')) + + code = """\ +x = [1, 2, 3, 4, 5, 6, 7,] +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + if __name__ == '__main__': unittest.main() From 058c58b3df440941296e997cd7b8b083ca7d921c Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 1 Jul 2018 23:07:43 -0700 Subject: [PATCH 287/719] Use 'msg' instead of 'message' which is deprecated Closes #564 --- yapf/yapflib/yapf_api.py | 2 +- yapftests/reformatter_basic_test.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index d22beed7f..282dea3eb 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -128,7 +128,7 @@ def FormatCode(unformatted_source, try: tree = pytree_utils.ParseCodeToTree(unformatted_source) except parse.ParseError as e: - e.message = filename + ': ' + e.message + e.msg = filename + ': ' + e.msg raise # Run passes on the tree, modifying it in place. diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 2078b094c..a3de63dad 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2493,9 +2493,8 @@ def bar(self): def testDisableEndingCommaHeuristic(self): try: style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: chromium,' - ' disable_ending_comma_heuristic: True}')) + style.CreateStyleFromConfig('{based_on_style: chromium,' + ' disable_ending_comma_heuristic: True}')) code = """\ x = [1, 2, 3, 4, 5, 6, 7,] From 50f28f9559da3fbfd3fc7a115033c2a357d17485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Sun, 8 Jul 2018 19:18:49 +0100 Subject: [PATCH 288/719] Add python 3.7 to Travis CI, but allow failures --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 1d905185d..6e20c9946 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,11 +5,13 @@ python: - 3.4 - 3.5 - 3.6 + - 3.7-dev - nightly matrix: allow_failures: - python: nightly + - python: 3.7-dev include: - python: 2.7 env: SCA=true From c706b4810f730dc1ba47cdd7cfc9272781f36d82 Mon Sep 17 00:00:00 2001 From: Hugo Ricateau Date: Wed, 1 Aug 2018 19:11:58 +0200 Subject: [PATCH 289/719] Adds a INDENT_BLANK_LINES option. --- README.rst | 3 +++ yapf/yapflib/format_token.py | 15 +++++++++++++++ yapf/yapflib/reformatter.py | 2 +- yapf/yapflib/style.py | 4 ++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 19ef0c21a..caa865679 100644 --- a/README.rst +++ b/README.rst @@ -448,6 +448,9 @@ Knobs ``INDENT_WIDTH`` The number of columns to use for indentation. +``INDENT_BLANK_LINES`` + Set to ``True`` to prefer indented blank lines rather than empty + ``JOIN_MULTIPLE_LINES`` Join short lines into one line. E.g., single line ``if`` statements. diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 79dced4af..baafdf638 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -139,6 +139,21 @@ def __init__(self, node): else: self.value = self.node.value + @property + def formatted_whitespace_prefix(self): + if style.Get('INDENT_BLANK_LINES'): + without_newline = self.whitespace_prefix.lstrip('\n') + without_spaces = without_newline.lstrip(' ') + height = len(self.whitespace_prefix) - len(without_newline) + depth = len(without_newline) - len(without_spaces) + formatted_whitespace_prefix = ('\n' + ' '*depth)*height + if not formatted_whitespace_prefix: + formatted_whitespace_prefix += ' '*depth + formatted_whitespace_prefix += without_spaces + return formatted_whitespace_prefix + else: + return self.whitespace_prefix + def AddWhitespacePrefix(self, newlines_before, spaces=0, indent_level=0): """Register a token's whitespace prefix. diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 6539e68e9..1b24f1813 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -254,7 +254,7 @@ def _FormatFinalLines(final_lines, verify): formatted_line = [] for tok in line.tokens: if not tok.is_pseudo_paren: - formatted_line.append(tok.whitespace_prefix) + formatted_line.append(tok.formatted_whitespace_prefix) formatted_line.append(tok.value) else: if (not tok.next_token.whitespace_prefix.startswith('\n') and diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 61442468b..a550a8911 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -154,6 +154,8 @@ def method(): }"""), INDENT_WIDTH=textwrap.dedent("""\ The number of columns to use for indentation."""), + INDENT_BLANK_LINES=textwrap.dedent("""\ + Indent blank lines."""), JOIN_MULTIPLE_LINES=textwrap.dedent("""\ Join short lines into one line. E.g., single line 'if' statements."""), NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=textwrap.dedent("""\ @@ -281,6 +283,7 @@ def CreatePEP8Style(): I18N_FUNCTION_CALL='', INDENT_DICTIONARY_VALUE=False, INDENT_WIDTH=4, + INDENT_BLANK_LINES=False, JOIN_MULTIPLE_LINES=True, SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=True, SPACES_AROUND_POWER_OPERATOR=False, @@ -430,6 +433,7 @@ def _BoolConverter(s): I18N_FUNCTION_CALL=_StringListConverter, INDENT_DICTIONARY_VALUE=_BoolConverter, INDENT_WIDTH=int, + INDENT_BLANK_LINES=_BoolConverter, JOIN_MULTIPLE_LINES=_BoolConverter, NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=_StringSetConverter, SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=_BoolConverter, From cbe2cf122a72509bd9d7c5eb02759aecdf819177 Mon Sep 17 00:00:00 2001 From: Hugo Ricateau Date: Wed, 1 Aug 2018 19:34:22 +0200 Subject: [PATCH 290/719] Fixes formatting. --- yapf/yapflib/format_token.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index baafdf638..2122a2b82 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -146,9 +146,9 @@ def formatted_whitespace_prefix(self): without_spaces = without_newline.lstrip(' ') height = len(self.whitespace_prefix) - len(without_newline) depth = len(without_newline) - len(without_spaces) - formatted_whitespace_prefix = ('\n' + ' '*depth)*height + formatted_whitespace_prefix = ('\n' + ' ' * depth) * height if not formatted_whitespace_prefix: - formatted_whitespace_prefix += ' '*depth + formatted_whitespace_prefix += ' ' * depth formatted_whitespace_prefix += without_spaces return formatted_whitespace_prefix else: From a78ee0353d10af968b22b6dd813fd93b9b3e9d4b Mon Sep 17 00:00:00 2001 From: Hugo Ricateau Date: Thu, 2 Aug 2018 12:18:54 +0200 Subject: [PATCH 291/719] Adds a test for the INDENT_BLANK_LINES option. --- yapftests/reformatter_basic_test.py | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index a3de63dad..86fff309c 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -133,6 +133,40 @@ def foobar(): # foo uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testIndentBlankLines(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: chromium, indent_blank_lines: true}')) + unformatted_code = textwrap.dedent("""\ + class foo(object): + + def foobar(self): + + pass + + def barfoo(self, x, y): # bar + + if x: + + return y + + + def bar(): + + return 0 + """) + expected_formatted_code = """class foo(object):\n \n def foobar(self):\n \n pass\n \n def barfoo(self, x, y): # bar\n \n if x:\n \n return y\n\n\ndef bar():\n \n return 0\n""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + + unformatted_code, expected_formatted_code = expected_formatted_code, unformatted_code + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testMultipleUgliness(self): unformatted_code = textwrap.dedent("""\ x = { 'a':37,'b':42, From 7b574a1c86ae24fa1b42d317ee6cb00d64ecae17 Mon Sep 17 00:00:00 2001 From: Hugo Ricateau Date: Mon, 6 Aug 2018 15:24:02 +0200 Subject: [PATCH 292/719] Fixes incompatibility with the USE_TABS option. --- yapf/yapflib/format_token.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 2122a2b82..d1e6797aa 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -142,17 +142,11 @@ def __init__(self, node): @property def formatted_whitespace_prefix(self): if style.Get('INDENT_BLANK_LINES'): - without_newline = self.whitespace_prefix.lstrip('\n') - without_spaces = without_newline.lstrip(' ') - height = len(self.whitespace_prefix) - len(without_newline) - depth = len(without_newline) - len(without_spaces) - formatted_whitespace_prefix = ('\n' + ' ' * depth) * height - if not formatted_whitespace_prefix: - formatted_whitespace_prefix += ' ' * depth - formatted_whitespace_prefix += without_spaces - return formatted_whitespace_prefix - else: - return self.whitespace_prefix + without_newlines = self.whitespace_prefix.lstrip('\n') + height = len(self.whitespace_prefix) - len(without_newlines) + if height: + return ('\n' + without_newlines) * height + return self.whitespace_prefix def AddWhitespacePrefix(self, newlines_before, spaces=0, indent_level=0): """Register a token's whitespace prefix. From ac4de8c54154d5f15e875616ad985bd8a5984656 Mon Sep 17 00:00:00 2001 From: James Kuszmaul Date: Fri, 17 Aug 2018 14:04:36 -0700 Subject: [PATCH 293/719] Don't add space between '.' and print To be honest, not sure we should ever be adding a space here, as we can end up with class members that are keywords. Also, I suspect that the existing logic is wrong, and should also be checking rval, even if we don't want to add print to the checks. --- yapf/yapflib/unwrapped_line.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 92b986ebf..d4c7429ce 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -317,9 +317,12 @@ def _SpaceRequiredBetween(left, right): if lval == '@' and format_token.Subtype.DECORATOR in left.subtypes: # Decorators shouldn't be separated from the 'at' sign. return False - if left.is_keyword and rval == '.' or lval == '.' and right.is_keyword: + if left.is_keyword and rval == '.': # Add space between keywords and dots. - return lval != 'None' + return lval != 'None' and lval != 'print' + if lval == '.' and right.is_keyword: + # Add space between keywords and dots. + return rval != 'None' and rval != 'print' if lval == '.' or rval == '.': # Don't place spaces between dots. return False From ace63955274751b6970ce0ba5280218d2f602e77 Mon Sep 17 00:00:00 2001 From: James Kuszmaul Date: Fri, 17 Aug 2018 14:24:35 -0700 Subject: [PATCH 294/719] Add small test for a.print --- yapftests/yapf_test.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 6df28b60d..0d307357c 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -59,6 +59,11 @@ def testNoEndingNewline(self): """) self._Check(unformatted_code, expected_formatted_code) + def testPrintAfterPeriod(self): + unformatted_code = textwrap.dedent("""a.print\n""") + expected_formatted_code = textwrap.dedent("""a.print\n""") + self._Check(unformatted_code, expected_formatted_code) + class FormatFileTest(unittest.TestCase): From 7d0cad836749fcefdc11c96534cfab701987406b Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 26 Aug 2018 20:05:26 -0700 Subject: [PATCH 295/719] Retain vertical spacing when --lines used If formatting is disabled for a line in the range specified on the command line, it could be reformatted accidentally. Closes #565 --- CHANGELOG | 2 ++ yapf/yapflib/comment_splicer.py | 4 ++-- yapf/yapflib/format_token.py | 3 ++- yapf/yapflib/reformatter.py | 7 +++---- yapftests/format_token_test.py | 6 ++++-- yapftests/yapf_test.py | 24 ++++++++++++++++++++++++ 6 files changed, 37 insertions(+), 9 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4693f039e..2618b9105 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,8 @@ use lib2to3 to fail if called from YAPF. - Change the exception message instead of creating a new one that's just a clone. +- Make sure not to reformat when a line is disabled even if the --lines option + is specified. ## [0.22.0] 2018-05-15 ### Added diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index af999d260..8717394f0 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -177,8 +177,8 @@ def _VisitNodeRec(node): rindex = (0 if '\n' not in comment_prefix.rstrip() else comment_prefix.rstrip().rindex('\n') + 1) comment_column = ( - len(comment_prefix[rindex:]) - len( - comment_prefix[rindex:].lstrip())) + len(comment_prefix[rindex:]) - + len(comment_prefix[rindex:].lstrip())) comments = _CreateCommentsFromPrefix( comment_prefix, comment_lineno, diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 79dced4af..f1ca49916 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -223,7 +223,8 @@ def ClosesScope(self): return self.value in pytree_utils.CLOSING_BRACKETS def __repr__(self): - msg = 'FormatToken(name={0}, value={1}'.format(self.name, self.value) + msg = 'FormatToken(name={0}, value={1}, lineno={2}'.format( + self.name, self.value, self.lineno) msg += ', pseudo)' if self.is_pseudo_paren else ')' return msg diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 6539e68e9..ebbff56f8 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -142,6 +142,8 @@ def _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines): pass elif lines and (cur_lineno in lines or prev_lineno in lines): desired_newlines = cur_tok.whitespace_prefix.count('\n') + if desired_newlines < required_newlines: + desired_newlines = required_newlines whitespace_lines = range(prev_lineno + 1, cur_lineno) deletable_lines = len(lines.intersection(whitespace_lines)) required_newlines = max(required_newlines - deletable_lines, @@ -173,7 +175,6 @@ def _EmitLineUnformatted(state): state: (format_decision_state.FormatDecisionState) The format decision state. """ - prev_lineno = None while state.next_token: previous_token = state.next_token.previous_token previous_lineno = previous_token.lineno @@ -184,10 +185,8 @@ def _EmitLineUnformatted(state): if previous_token.is_continuation: newline = False else: - newline = ( - prev_lineno is not None and state.next_token.lineno > previous_lineno) + newline = state.next_token.lineno > previous_lineno - prev_lineno = state.next_token.lineno state.AddTokenToState(newline=newline, dry_run=False) diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index 7dfb82a56..2f6f973ba 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -67,11 +67,13 @@ class FormatTokenTest(unittest.TestCase): def testSimple(self): tok = format_token.FormatToken(pytree.Leaf(token.STRING, "'hello world'")) - self.assertEqual("FormatToken(name=STRING, value='hello world')", str(tok)) + self.assertEqual("FormatToken(name=STRING, value='hello world', lineno=0)", + str(tok)) self.assertTrue(tok.is_string) tok = format_token.FormatToken(pytree.Leaf(token.COMMENT, '# A comment')) - self.assertEqual('FormatToken(name=COMMENT, value=# A comment)', str(tok)) + self.assertEqual('FormatToken(name=COMMENT, value=# A comment, lineno=0)', + str(tok)) self.assertTrue(tok.is_comment) def testIsMultilineString(self): diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 6df28b60d..186ebadc4 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1354,6 +1354,30 @@ def testCP936Encoding(self): expected_formatted_code, env={'PYTHONIOENCODING': 'cp936'}) + def testDisableWithLineRanges(self): + unformatted_code = """\ +# yapf: disable +a = [ + 1, + 2, + + 3 +] +""" + expected_formatted_code = """\ +# yapf: disable +a = [ + 1, + 2, + + 3 +] +""" + self.assertYapfReformats( + unformatted_code, + expected_formatted_code, + extra_options=['--style', 'chromium', '--lines', '1-100']) + class BadInputTest(unittest.TestCase): """Test yapf's behaviour when passed bad input.""" From d0e014ce968f3e8343efeb867847e72503fa2da1 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 26 Aug 2018 21:34:09 -0700 Subject: [PATCH 296/719] Fix regexp for no spaces around bin op knob Closes #559 --- CHANGELOG | 2 ++ README.rst | 8 ++++---- yapf/yapflib/comment_splicer.py | 4 ++-- yapf/yapflib/style.py | 19 +++++++++++++++---- yapf/yapflib/subtype_assigner.py | 2 +- yapf/yapflib/unwrapped_line.py | 2 +- yapftests/yapf_test.py | 17 +++++++++++++++++ 7 files changed, 42 insertions(+), 12 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 2618b9105..283a8e3c5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,8 @@ clone. - Make sure not to reformat when a line is disabled even if the --lines option is specified. +- The "no spaces around operators" flag wasn't correctly converting strings to + sets. Changed the regexp to handle it better. ## [0.22.0] 2018-05-15 ### Added diff --git a/README.rst b/README.rst index 19ef0c21a..ddd3ffe5c 100644 --- a/README.rst +++ b/README.rst @@ -451,9 +451,6 @@ Knobs ``JOIN_MULTIPLE_LINES`` Join short lines into one line. E.g., single line ``if`` statements. -``SPACES_AROUND_POWER_OPERATOR`` - Set to ``True`` to prefer using spaces around ``**``. - ``NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS`` Do not include spaces around selected binary operators. For example: @@ -461,12 +458,15 @@ Knobs 1 + 2 * 3 - 4 / 5 - will be formatted as follows when configured with ``*,/``: + will be formatted as follows when configured with ``"*/"``: .. code-block:: python 1 + 2*3 - 4/5 +``SPACES_AROUND_POWER_OPERATOR`` + Set to ``True`` to prefer using spaces around ``**``. + ``SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN`` Set to ``True`` to prefer spaces around the assignment operator for default or keyword arguments. diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index 8717394f0..af999d260 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -177,8 +177,8 @@ def _VisitNodeRec(node): rindex = (0 if '\n' not in comment_prefix.rstrip() else comment_prefix.rstrip().rindex('\n') + 1) comment_column = ( - len(comment_prefix[rindex:]) - - len(comment_prefix[rindex:].lstrip())) + len(comment_prefix[rindex:]) - len( + comment_prefix[rindex:].lstrip())) comments = _CreateCommentsFromPrefix( comment_prefix, comment_lineno, diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 61442468b..b9e8b6962 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -282,9 +282,9 @@ def CreatePEP8Style(): INDENT_DICTIONARY_VALUE=False, INDENT_WIDTH=4, JOIN_MULTIPLE_LINES=True, + NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=set(), SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=True, SPACES_AROUND_POWER_OPERATOR=False, - NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=set(), SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=False, SPACES_BEFORE_COMMENT=2, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False, @@ -390,12 +390,18 @@ def _ContinuationAlignStyleStringConverter(s): def _StringListConverter(s): """Option value converter for a comma-separated list of strings.""" + if len(s) > 2 and s[0] in '"\'': + s = s[1:-1] return [part.strip() for part in s.split(',')] def _StringSetConverter(s): """Option value converter for a comma-separated set of strings.""" - return set(part.strip() for part in s.split(',')) + if len(s) > 2 and s[0] in '"\'': + s = s[1:-1] + if ',' in s: + return set(part.strip() for part in s.split(',')) + return set(s.strip()) def _BoolConverter(s): @@ -489,6 +495,7 @@ def GlobalStyles(): if not def_style: return _style return _GLOBAL_STYLE_FACTORY() + if isinstance(style_config, dict): config = _CreateConfigParserFromConfigDict(style_config) elif isinstance(style_config, py3compat.basestring): @@ -519,8 +526,12 @@ def _CreateConfigParserFromConfigString(config_string): "Invalid style dict syntax: '{}'.".format(config_string)) config = py3compat.ConfigParser() config.add_section('style') - for key, value in re.findall(r'([a-zA-Z0-9_]+)\s*[:=]\s*([a-zA-Z0-9_]+)', - config_string): + for key, value, _ in re.findall( + r'([a-zA-Z0-9_]+)\s*[:=]\s*' + + r'(?:' + + r'((?P[\'"]).*?(?P=quote)|' + + r'[a-zA-Z0-9_]+)' + + r')', config_string): # yapf: disable config.set('style', key, value) return config diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 8bf3d8d97..8009ddcd1 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -195,7 +195,7 @@ def Visit_term(self, node): # pylint: disable=invalid-name for child in node.children: self.Visit(child) if (isinstance(child, pytree.Leaf) and - child.value in {'*', '/', '%', '//'}): + child.value in {'*', '/', '%', '//', '@'}): _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) def Visit_factor(self, node): # pylint: disable=invalid-name diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 92b986ebf..b063100c2 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -460,7 +460,7 @@ def IsSurroundedByBrackets(tok): _LOGICAL_OPERATORS = frozenset({'and', 'or'}) _BITWISE_OPERATORS = frozenset({'&', '|', '^'}) -_TERM_OPERATORS = frozenset({'*', '/', '%', '//'}) +_TERM_OPERATORS = frozenset({'*', '/', '%', '//', '@'}) def _SplitPenalty(prev_token, cur_token): diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 186ebadc4..34004dc96 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1345,6 +1345,23 @@ def testSpacingBeforeCommentsInDicts(self): expected_formatted_code, extra_options=['--style', 'chromium', '--lines', '1-1']) + @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') + def testNoSpacesAroundBinaryOperators(self): + unformatted_code = """\ +a = 4-b/c@d**37 +""" + expected_formatted_code = """\ +a = 4-b / c@d**37 +""" + self.assertYapfReformats( + unformatted_code, + expected_formatted_code, + extra_options=[ + '--style', + '{based_on_style: pep8, ' + + 'no_spaces_around_selected_binary_operators: "@,**,-"}', + ]) + @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testCP936Encoding(self): unformatted_code = 'print("äž­æ–‡")\n' From 9e8318a240d420a14cfdc6b370e7a8783050d3f0 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 27 Aug 2018 05:09:42 -0700 Subject: [PATCH 297/719] Bump version to v0.23.0 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 283a8e3c5..40afca9f4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.23.0] UNRELEASED +## [0.23.0] 2018-08-27 ### Added - `DISABLE_ENDING_COMMA_HEURISTIC` is a new knob to disable the heuristic which splits a list onto separate lines if the list is comma-terminated. diff --git a/yapf/__init__.py b/yapf/__init__.py index 22ab014c0..5d8a27c5d 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.22.0' +__version__ = '0.23.0' def main(argv): From 787672c5c1e698350490599bd0a80557c0a87aeb Mon Sep 17 00:00:00 2001 From: Yoan Blanc Date: Mon, 23 Jul 2018 11:08:10 +0200 Subject: [PATCH 298/719] py3compat: remove any BOM Signed-off-by: Yoan Blanc --- yapf/__init__.py | 1 + yapf/yapflib/py3compat.py | 11 +++++++++++ yapftests/yapf_test.py | 3 ++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 5d8a27c5d..6a3f3edca 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -176,6 +176,7 @@ def main(argv): style_config = file_resources.GetDefaultStyleForDir(os.getcwd()) source = [line.rstrip() for line in original_source] + source[0] = py3compat.removeBOM(source[0]) reformatted_source, _ = yapf_api.FormatCode( py3compat.unicode('\n'.join(source) + '\n'), filename='', diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py index c66d6c681..5373b013a 100644 --- a/yapf/yapflib/py3compat.py +++ b/yapf/yapflib/py3compat.py @@ -13,6 +13,7 @@ # limitations under the License. """Utilities for Python2 / Python3 compatibility.""" +import codecs import io import os import sys @@ -116,3 +117,13 @@ class ConfigParser(configparser.ConfigParser): def read_file(self, fp, source=None): self.readfp(fp, filename=source) + + +def removeBOM(source): + """Remove any Byte-order-Mark bytes from the beginning of a file.""" + bom = codecs.BOM_UTF8 + if PY3: + bom = bom.decode('utf-8') + if source.startswith(bom): + return source[len(bom):] + return source diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index aaae288de..6e6408362 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -411,7 +411,8 @@ def assertYapfReformats(self, stdin=subprocess.PIPE, stderr=subprocess.PIPE, env=env) - reformatted_code, stderrdata = p.communicate(unformatted.encode('utf-8')) + reformatted_code, stderrdata = p.communicate( + unformatted.encode('utf-8-sig')) self.assertEqual(stderrdata, b'') self.assertMultiLineEqual(reformatted_code.decode('utf-8'), expected) From cd0d6695db621fa18cca1f30bdb89dda4cfbfc4e Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 27 Aug 2018 18:30:38 -0700 Subject: [PATCH 299/719] Add SPLIT_BEFORE_DOT option This option allows the user to specify if they want to split before or after the dot if it's required. --- CHANGELOG | 6 +++++ README.rst | 14 ++++++++++ yapf/yapflib/format_decision_state.py | 4 +-- yapf/yapflib/split_penalty.py | 35 ++++++------------------- yapf/yapflib/style.py | 13 +++++++++ yapf/yapflib/unwrapped_line.py | 3 --- yapftests/reformatter_buganizer_test.py | 28 +++++++++++++++----- yapftests/split_penalty_test.py | 12 ++++----- 8 files changed, 71 insertions(+), 44 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 40afca9f4..c41315c20 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,12 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.24.0] UNRELEASED +### Added +- Added 'SPLIT_BEFORE_DOT' knob to support "builder style" calls. The "builder + style" option didn't work as advertised. Lines would split after the dots, + not before them regardless of the penalties. + ## [0.23.0] 2018-08-27 ### Added - `DISABLE_ENDING_COMMA_HEURISTIC` is a new knob to disable the heuristic which diff --git a/README.rst b/README.rst index ddd3ffe5c..b5d22d91f 100644 --- a/README.rst +++ b/README.rst @@ -503,6 +503,20 @@ Knobs for variable in bar if variable != 42 } +``SPLIT_BEFORE_DOT`` + Split before the '.' if we need to split a longer expression: + + .. code-block:: python + + foo = ('This is a really long string: {}, {}, {}, {}'.format(a, b, c, d)) + + would reformat to something like: + + .. code-block:: python + + foo = ('This is a really long string: {}, {}, {}, {}' + .format(a, b, c, d)) + ``SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN`` Split after the opening paren which surrounds an expression if it doesn't fit on a single line. diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index bff8ea3e2..d61ea8215 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -336,8 +336,8 @@ def SurroundedByParens(token): ########################################################################### # Argument List Splitting if (style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and not current.is_comment and - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in - current.subtypes): + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in current + .subtypes): if (previous.value not in {'=', ':', '*', '**'} and current.value not in ':=,)' and not _IsFunctionDefinition(previous)): # If we're going to split the lines because of named arguments, then we diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 416eda3bc..c6ebb0b85 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -193,8 +193,11 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name def Visit_trailer(self, node): # pylint: disable=invalid-name # trailer ::= '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME if node.children[0].value == '.': - self._SetUnbreakableOnChildren(node) - _SetSplitPenalty(node.children[1], DOTTED_NAME) + before = style.Get('SPLIT_BEFORE_DOT') + _SetSplitPenalty(node.children[0], STRONGLY_CONNECTED + if before else DOTTED_NAME) + _SetSplitPenalty(node.children[1], DOTTED_NAME + if before else STRONGLY_CONNECTED) elif len(node.children) == 2: # Don't split an empty argument list if at all possible. _SetSplitPenalty(node.children[1], VERY_STRONGLY_CONNECTED) @@ -253,7 +256,9 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring pytree_utils.NodeName(node.children[1]) == 'trailer'): # children[1] itself is a whole trailer: we don't want to # mark all of it as unbreakable, only its first token: (, [ or . - _SetUnbreakable(node.children[1].children[0]) + first = pytree_utils.FirstLeafNode(node.children[1]) + if first.value != '.': + _SetUnbreakable(node.children[1].children[0]) # A special case when there are more trailers in the sequence. Given: # atom tr1 tr2 @@ -310,10 +315,6 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring # split the two. _SetStronglyConnected(trailer.children[-1]) - # If the original source has a "builder" style calls, then we should allow - # the reformatter to retain that. - _AllowBuilderStyleCalls(node) - def Visit_subscript(self, node): # pylint: disable=invalid-name # subscript ::= test | [test] ':' [test] [sliceop] _SetStronglyConnected(*node.children) @@ -590,23 +591,3 @@ def _DecrementSplitPenalty(node, amt): def _SetSplitPenalty(node, penalty): pytree_utils.SetNodeAnnotation(node, pytree_utils.Annotation.SPLIT_PENALTY, penalty) - - -def _AllowBuilderStyleCalls(node): - """Allow splitting before '.' if it's a builder style function call.""" - - def RecGetLeaves(node): - if isinstance(node, pytree.Leaf): - return [node] - children = [] - for child in node.children: - children += RecGetLeaves(child) - return children - - list_of_children = RecGetLeaves(node) - prev_child = None - for child in list_of_children: - if child.value == '.': - if prev_child.lineno != child.lineno: - _SetSplitPenalty(child, 0) - prev_child = child diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index b9e8b6962..0486ef402 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -194,6 +194,16 @@ def method(): variable: 'Hello world, have a nice day!' for variable in bar if variable != 42 }"""), + SPLIT_BEFORE_DOT=textwrap.dedent("""\ + Split before the '.' if we need to split a longer expression: + + foo = ('This is a really long string: {}, {}, {}, {}'.format(a, b, c, d)) + + would reformat to something like: + + foo = ('This is a really long string: {}, {}, {}, {}' + .format(a, b, c, d)) + """), SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=textwrap.dedent("""\ Split after the opening paren which surrounds an expression if it doesn't fit on a single line. @@ -292,6 +302,7 @@ def CreatePEP8Style(): SPLIT_BEFORE_BITWISE_OPERATOR=True, SPLIT_BEFORE_CLOSING_BRACKET=True, SPLIT_BEFORE_DICT_SET_GENERATOR=True, + SPLIT_BEFORE_DOT=False, SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=False, SPLIT_BEFORE_FIRST_ARGUMENT=False, SPLIT_BEFORE_LOGICAL_OPERATOR=True, @@ -334,6 +345,7 @@ def CreateChromiumStyle(): style['INDENT_WIDTH'] = 2 style['JOIN_MULTIPLE_LINES'] = False style['SPLIT_BEFORE_BITWISE_OPERATOR'] = True + style['SPLIT_BEFORE_DOT'] = True style['SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN'] = True return style @@ -447,6 +459,7 @@ def _BoolConverter(s): SPLIT_BEFORE_BITWISE_OPERATOR=_BoolConverter, SPLIT_BEFORE_CLOSING_BRACKET=_BoolConverter, SPLIT_BEFORE_DICT_SET_GENERATOR=_BoolConverter, + SPLIT_BEFORE_DOT=_BoolConverter, SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=_BoolConverter, SPLIT_BEFORE_FIRST_ARGUMENT=_BoolConverter, SPLIT_BEFORE_LOGICAL_OPERATOR=_BoolConverter, diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 01b662057..0bf4fba44 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -418,9 +418,6 @@ def _CanBreakBefore(prev_token, cur_token): if prev_token.is_name and cval == '[': # Don't break in the middle of an array dereference. return False - if prev_token.is_name and cval == '.': - # Don't break before the '.' in a dotted name. - return False if cur_token.is_comment and prev_token.lineno == cur_token.lineno: # Don't break a comment at the end of the line. return False diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 6a1c78153..7712351b9 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,22 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def test113210278(self): + unformatted_code = """\ +def _(): + aaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccc(\ +eeeeeeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffffffffffffffffffffff.\ +ggggggggggggggggggggggggggggggggg.hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh()) +""" + expected_formatted_code = """\ +def _(): + aaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccc( + eeeeeeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffffffffffffffffffffff + .ggggggggggggggggggggggggggggggggg.hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh()) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB77923341(self): code = """\ def f(): @@ -845,8 +861,8 @@ def lulz(): """) expected_formatted_code = textwrap.dedent("""\ def lulz(): - return (some_long_module_name.SomeLongClassName.some_long_attribute_name. - some_long_method_name()) + return (some_long_module_name.SomeLongClassName.some_long_attribute_name + .some_long_method_name()) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -944,8 +960,8 @@ def _(): def _(): _xxxxxxxxxxxxxxx( aaaaaaaa, - bbbbbbbbbbbbbb.cccccccccc[dddddddddddddddddddddddddddd. - eeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffff]) + bbbbbbbbbbbbbb.cccccccccc[dddddddddddddddddddddddddddd + .eeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffff]) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1017,8 +1033,8 @@ def _(): expected_formatted_code = textwrap.dedent("""\ def _(): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = ( - self.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb. - cccccccccccccccccccccccccccccccccccc) + self.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + .cccccccccccccccccccccccccccccccccccc) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index 7d500daa0..0d300d85a 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -198,8 +198,8 @@ def testStronglyConnected(self): ('foo', STRONGLY_CONNECTED), ('if', 0), ('a', STRONGLY_CONNECTED), - ('.', UNBREAKABLE), - ('x', DOTTED_NAME), + ('.', DOTTED_NAME), + ('x', STRONGLY_CONNECTED), ('==', STRONGLY_CONNECTED), ('37', STRONGLY_CONNECTED), (']', None), @@ -224,10 +224,10 @@ def testFuncCalls(self): tree = self._ParseAndComputePenalties(code) self._CheckPenalties(tree, [ ('foo', None), - ('.', UNBREAKABLE), - ('bar', DOTTED_NAME), - ('.', STRONGLY_CONNECTED), - ('baz', DOTTED_NAME), + ('.', DOTTED_NAME), + ('bar', STRONGLY_CONNECTED), + ('.', DOTTED_NAME), + ('baz', STRONGLY_CONNECTED), ('(', STRONGLY_CONNECTED), ('1', None), (',', UNBREAKABLE), From 25a014d4f9f7684704853a47179a7f4c7e0d515a Mon Sep 17 00:00:00 2001 From: cclauss Date: Tue, 28 Aug 2018 14:07:22 +0200 Subject: [PATCH 300/719] Travis CI: Upgrade from Python 3.7.0a4+ to production release Upgrade from Python 3.7.0a4+ to Python 3.7.0 production release in alignment with travis-ci/travis-ci#9069 --- .travis.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6e20c9946..4f9a91d87 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,18 +5,24 @@ python: - 3.4 - 3.5 - 3.6 - - 3.7-dev - nightly matrix: allow_failures: - python: nightly - - python: 3.7-dev + - python: 3.7 include: - python: 2.7 env: SCA=true - python: 3.5 env: SCA=true + - python: 3.7 + dist: xenial # required for Python 3.7 (travis-ci/travis-ci#9069) + sudo: required # required for Python 3.7 (travis-ci/travis-ci#9069) + - python: 3.7 + dist: xenial # required for Python 3.7 (travis-ci/travis-ci#9069) + sudo: required # required for Python 3.7 (travis-ci/travis-ci#9069) + env: SCA=true install: - if [ -z "$SCA" ]; then pip install --quiet coveralls; else echo skip; fi From b87757955eb770c38282f6b1c140cc391d48a3d2 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 27 Aug 2018 18:30:38 -0700 Subject: [PATCH 301/719] Add SPLIT_BEFORE_DOT option This option allows the user to specify if they want to split before or after the dot if it's required. --- CHANGELOG | 6 +++++ README.rst | 14 ++++++++++ yapf/yapflib/format_decision_state.py | 4 +-- yapf/yapflib/split_penalty.py | 35 ++++++------------------- yapf/yapflib/style.py | 21 ++++++++++++--- yapf/yapflib/unwrapped_line.py | 3 --- yapftests/reformatter_buganizer_test.py | 28 +++++++++++++++----- yapftests/split_penalty_test.py | 12 ++++----- yapftests/yapf_test.py | 2 +- 9 files changed, 76 insertions(+), 49 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 40afca9f4..c41315c20 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,12 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.24.0] UNRELEASED +### Added +- Added 'SPLIT_BEFORE_DOT' knob to support "builder style" calls. The "builder + style" option didn't work as advertised. Lines would split after the dots, + not before them regardless of the penalties. + ## [0.23.0] 2018-08-27 ### Added - `DISABLE_ENDING_COMMA_HEURISTIC` is a new knob to disable the heuristic which diff --git a/README.rst b/README.rst index ddd3ffe5c..b5d22d91f 100644 --- a/README.rst +++ b/README.rst @@ -503,6 +503,20 @@ Knobs for variable in bar if variable != 42 } +``SPLIT_BEFORE_DOT`` + Split before the '.' if we need to split a longer expression: + + .. code-block:: python + + foo = ('This is a really long string: {}, {}, {}, {}'.format(a, b, c, d)) + + would reformat to something like: + + .. code-block:: python + + foo = ('This is a really long string: {}, {}, {}, {}' + .format(a, b, c, d)) + ``SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN`` Split after the opening paren which surrounds an expression if it doesn't fit on a single line. diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index bff8ea3e2..d61ea8215 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -336,8 +336,8 @@ def SurroundedByParens(token): ########################################################################### # Argument List Splitting if (style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and not current.is_comment and - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in - current.subtypes): + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in current + .subtypes): if (previous.value not in {'=', ':', '*', '**'} and current.value not in ':=,)' and not _IsFunctionDefinition(previous)): # If we're going to split the lines because of named arguments, then we diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 416eda3bc..c6ebb0b85 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -193,8 +193,11 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name def Visit_trailer(self, node): # pylint: disable=invalid-name # trailer ::= '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME if node.children[0].value == '.': - self._SetUnbreakableOnChildren(node) - _SetSplitPenalty(node.children[1], DOTTED_NAME) + before = style.Get('SPLIT_BEFORE_DOT') + _SetSplitPenalty(node.children[0], STRONGLY_CONNECTED + if before else DOTTED_NAME) + _SetSplitPenalty(node.children[1], DOTTED_NAME + if before else STRONGLY_CONNECTED) elif len(node.children) == 2: # Don't split an empty argument list if at all possible. _SetSplitPenalty(node.children[1], VERY_STRONGLY_CONNECTED) @@ -253,7 +256,9 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring pytree_utils.NodeName(node.children[1]) == 'trailer'): # children[1] itself is a whole trailer: we don't want to # mark all of it as unbreakable, only its first token: (, [ or . - _SetUnbreakable(node.children[1].children[0]) + first = pytree_utils.FirstLeafNode(node.children[1]) + if first.value != '.': + _SetUnbreakable(node.children[1].children[0]) # A special case when there are more trailers in the sequence. Given: # atom tr1 tr2 @@ -310,10 +315,6 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring # split the two. _SetStronglyConnected(trailer.children[-1]) - # If the original source has a "builder" style calls, then we should allow - # the reformatter to retain that. - _AllowBuilderStyleCalls(node) - def Visit_subscript(self, node): # pylint: disable=invalid-name # subscript ::= test | [test] ':' [test] [sliceop] _SetStronglyConnected(*node.children) @@ -590,23 +591,3 @@ def _DecrementSplitPenalty(node, amt): def _SetSplitPenalty(node, penalty): pytree_utils.SetNodeAnnotation(node, pytree_utils.Annotation.SPLIT_PENALTY, penalty) - - -def _AllowBuilderStyleCalls(node): - """Allow splitting before '.' if it's a builder style function call.""" - - def RecGetLeaves(node): - if isinstance(node, pytree.Leaf): - return [node] - children = [] - for child in node.children: - children += RecGetLeaves(child) - return children - - list_of_children = RecGetLeaves(node) - prev_child = None - for child in list_of_children: - if child.value == '.': - if prev_child.lineno != child.lineno: - _SetSplitPenalty(child, 0) - prev_child = child diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index b9e8b6962..e4725dfd3 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -194,6 +194,16 @@ def method(): variable: 'Hello world, have a nice day!' for variable in bar if variable != 42 }"""), + SPLIT_BEFORE_DOT=textwrap.dedent("""\ + Split before the '.' if we need to split a longer expression: + + foo = ('This is a really long string: {}, {}, {}, {}'.format(a, b, c, d)) + + would reformat to something like: + + foo = ('This is a really long string: {}, {}, {}, {}' + .format(a, b, c, d)) + """), SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=textwrap.dedent("""\ Split after the opening paren which surrounds an expression if it doesn't fit on a single line. @@ -292,6 +302,7 @@ def CreatePEP8Style(): SPLIT_BEFORE_BITWISE_OPERATOR=True, SPLIT_BEFORE_CLOSING_BRACKET=True, SPLIT_BEFORE_DICT_SET_GENERATOR=True, + SPLIT_BEFORE_DOT=False, SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=False, SPLIT_BEFORE_FIRST_ARGUMENT=False, SPLIT_BEFORE_LOGICAL_OPERATOR=True, @@ -334,6 +345,7 @@ def CreateChromiumStyle(): style['INDENT_WIDTH'] = 2 style['JOIN_MULTIPLE_LINES'] = False style['SPLIT_BEFORE_BITWISE_OPERATOR'] = True + style['SPLIT_BEFORE_DOT'] = True style['SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN'] = True return style @@ -447,6 +459,7 @@ def _BoolConverter(s): SPLIT_BEFORE_BITWISE_OPERATOR=_BoolConverter, SPLIT_BEFORE_CLOSING_BRACKET=_BoolConverter, SPLIT_BEFORE_DICT_SET_GENERATOR=_BoolConverter, + SPLIT_BEFORE_DOT=_BoolConverter, SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=_BoolConverter, SPLIT_BEFORE_FIRST_ARGUMENT=_BoolConverter, SPLIT_BEFORE_LOGICAL_OPERATOR=_BoolConverter, @@ -527,10 +540,10 @@ def _CreateConfigParserFromConfigString(config_string): config = py3compat.ConfigParser() config.add_section('style') for key, value, _ in re.findall( - r'([a-zA-Z0-9_]+)\s*[:=]\s*' + - r'(?:' + - r'((?P[\'"]).*?(?P=quote)|' + - r'[a-zA-Z0-9_]+)' + + r'([a-zA-Z0-9_]+)\s*[:=]\s*' + r'(?:' + r'((?P[\'"]).*?(?P=quote)|' + r'[a-zA-Z0-9_]+)' r')', config_string): # yapf: disable config.set('style', key, value) return config diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 01b662057..0bf4fba44 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -418,9 +418,6 @@ def _CanBreakBefore(prev_token, cur_token): if prev_token.is_name and cval == '[': # Don't break in the middle of an array dereference. return False - if prev_token.is_name and cval == '.': - # Don't break before the '.' in a dotted name. - return False if cur_token.is_comment and prev_token.lineno == cur_token.lineno: # Don't break a comment at the end of the line. return False diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 6a1c78153..7712351b9 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,22 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def test113210278(self): + unformatted_code = """\ +def _(): + aaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccc(\ +eeeeeeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffffffffffffffffffffff.\ +ggggggggggggggggggggggggggggggggg.hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh()) +""" + expected_formatted_code = """\ +def _(): + aaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccc( + eeeeeeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffffffffffffffffffffff + .ggggggggggggggggggggggggggggggggg.hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh()) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB77923341(self): code = """\ def f(): @@ -845,8 +861,8 @@ def lulz(): """) expected_formatted_code = textwrap.dedent("""\ def lulz(): - return (some_long_module_name.SomeLongClassName.some_long_attribute_name. - some_long_method_name()) + return (some_long_module_name.SomeLongClassName.some_long_attribute_name + .some_long_method_name()) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -944,8 +960,8 @@ def _(): def _(): _xxxxxxxxxxxxxxx( aaaaaaaa, - bbbbbbbbbbbbbb.cccccccccc[dddddddddddddddddddddddddddd. - eeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffff]) + bbbbbbbbbbbbbb.cccccccccc[dddddddddddddddddddddddddddd + .eeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffff]) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1017,8 +1033,8 @@ def _(): expected_formatted_code = textwrap.dedent("""\ def _(): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = ( - self.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb. - cccccccccccccccccccccccccccccccccccc) + self.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + .cccccccccccccccccccccccccccccccccccc) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index 7d500daa0..0d300d85a 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -198,8 +198,8 @@ def testStronglyConnected(self): ('foo', STRONGLY_CONNECTED), ('if', 0), ('a', STRONGLY_CONNECTED), - ('.', UNBREAKABLE), - ('x', DOTTED_NAME), + ('.', DOTTED_NAME), + ('x', STRONGLY_CONNECTED), ('==', STRONGLY_CONNECTED), ('37', STRONGLY_CONNECTED), (']', None), @@ -224,10 +224,10 @@ def testFuncCalls(self): tree = self._ParseAndComputePenalties(code) self._CheckPenalties(tree, [ ('foo', None), - ('.', UNBREAKABLE), - ('bar', DOTTED_NAME), - ('.', STRONGLY_CONNECTED), - ('baz', DOTTED_NAME), + ('.', DOTTED_NAME), + ('bar', STRONGLY_CONNECTED), + ('.', DOTTED_NAME), + ('baz', STRONGLY_CONNECTED), ('(', STRONGLY_CONNECTED), ('1', None), (',', UNBREAKABLE), diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index aaae288de..68bc77a18 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1363,7 +1363,7 @@ def testNoSpacesAroundBinaryOperators(self): expected_formatted_code, extra_options=[ '--style', - '{based_on_style: pep8, ' + + '{based_on_style: pep8, ' 'no_spaces_around_selected_binary_operators: "@,**,-"}', ]) From a120a21d8a7a21ec57433b49ef6ca677dd54a68a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 28 Aug 2018 17:46:41 -0700 Subject: [PATCH 302/719] Func calls in arg lists don't cause named assigns Don't mark all args in a function arg list as being part of a named assign if only a function call in the arg list has one. --- CHANGELOG | 2 + yapf/yapflib/subtype_assigner.py | 28 ++++++++------ yapftests/file_resources_test.py | 50 +++++++++++++------------ yapftests/reformatter_buganizer_test.py | 24 +++++++++++- 4 files changed, 68 insertions(+), 36 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c41315c20..0d78cc139 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,8 @@ - Added 'SPLIT_BEFORE_DOT' knob to support "builder style" calls. The "builder style" option didn't work as advertised. Lines would split after the dots, not before them regardless of the penalties. +### Fixed +- Don't count inner function calls when marking arguments as named assignments. ## [0.23.0] 2018-08-27 ### Added diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 8009ddcd1..ad6206677 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -337,20 +337,24 @@ def _SetArgListSubtype(node, node_subtype, list_subtype): def HasSubtype(node): """Return True if the arg list has a named assign subtype.""" if isinstance(node, pytree.Leaf): - if node_subtype in pytree_utils.GetNodeAnnotation( - node, pytree_utils.Annotation.SUBTYPE, set()): - return True - return False - has_subtype = False - for child in node.children: - if pytree_utils.NodeName(child) != 'arglist': - has_subtype |= HasSubtype(child) - return has_subtype + return node_subtype in pytree_utils.GetNodeAnnotation( + node, pytree_utils.Annotation.SUBTYPE, set()) - if HasSubtype(node): for child in node.children: - if pytree_utils.NodeName(child) != 'COMMA': - _AppendFirstLeafTokenSubtype(child, list_subtype) + node_name = pytree_utils.NodeName(child) + if node_name not in {'atom', 'arglist', 'power'}: + if HasSubtype(child): + return True + + return False + + if not HasSubtype(node): + return + + for child in node.children: + node_name = pytree_utils.NodeName(child) + if node_name not in {'atom', 'COMMA'}: + _AppendFirstLeafTokenSubtype(child, list_subtype) def _AppendTokenSubtype(node, subtype): diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 70cea46e6..8391e5f42 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -91,11 +91,13 @@ def test_find_files_not_dirs(self): _touch_files([file1, file2]) self.assertEqual( - file_resources.GetCommandLineFiles( - [file1, file2], recursive=False, exclude=None), [file1, file2]) + file_resources.GetCommandLineFiles([file1, file2], + recursive=False, + exclude=None), [file1, file2]) self.assertEqual( - file_resources.GetCommandLineFiles( - [file1, file2], recursive=True, exclude=None), [file1, file2]) + file_resources.GetCommandLineFiles([file1, file2], + recursive=True, + exclude=None), [file1, file2]) def test_nonrecursive_find_in_dir(self): tdir1 = self._make_test_dir('test1') @@ -124,9 +126,9 @@ def test_recursive_find_in_dir(self): self.assertEqual( sorted( - file_resources.GetCommandLineFiles( - [self.test_tmpdir], recursive=True, exclude=None)), - sorted(files)) + file_resources.GetCommandLineFiles([self.test_tmpdir], + recursive=True, + exclude=None)), sorted(files)) def test_recursive_find_in_dir_with_exclude(self): tdir1 = self._make_test_dir('test1') @@ -141,8 +143,9 @@ def test_recursive_find_in_dir_with_exclude(self): self.assertEqual( sorted( - file_resources.GetCommandLineFiles( - [self.test_tmpdir], recursive=True, exclude=['*test*3.py'])), + file_resources.GetCommandLineFiles([self.test_tmpdir], + recursive=True, + exclude=['*test*3.py'])), sorted([ os.path.join(tdir1, 'testfile1.py'), os.path.join(tdir2, 'testfile2.py'), @@ -159,8 +162,9 @@ def test_find_with_excluded_hidden_dirs(self): ] _touch_files(files) - actual = file_resources.GetCommandLineFiles( - [self.test_tmpdir], recursive=True, exclude=['*.test1*']) + actual = file_resources.GetCommandLineFiles([self.test_tmpdir], + recursive=True, + exclude=['*.test1*']) self.assertEqual( sorted(actual), @@ -225,22 +229,22 @@ def test_find_with_excluded_dirs(self): os.chdir(self.test_tmpdir) found = sorted( - file_resources.GetCommandLineFiles( - ['test1', 'test2', 'test3'], - recursive=True, - exclude=[ - 'test1', - 'test2/testinner/', - ])) + file_resources.GetCommandLineFiles(['test1', 'test2', 'test3'], + recursive=True, + exclude=[ + 'test1', + 'test2/testinner/', + ])) self.assertEqual(found, ['test3/foo/bar/bas/xxx/testfile3.py']) found = sorted( - file_resources.GetCommandLineFiles( - ['.'], recursive=True, exclude=[ - 'test1', - 'test3', - ])) + file_resources.GetCommandLineFiles(['.'], + recursive=True, + exclude=[ + 'test1', + 'test3', + ])) self.assertEqual(found, ['./test2/testinner/testfile2.py']) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 7712351b9..87b304688 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,7 +28,29 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) - def test113210278(self): + def testB79462249(self): + code = """\ +foo.bar(baz, [ + quux(thud=42), + norf, +]) +foo.bar(baz, [ + quux(), + norf, +]) +foo.bar(baz, quux(thud=42), aaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbb, + ccccccccccccccccccc) +foo.bar( + baz, + quux(thud=42), + aaaaaaaaaaaaaaaaaaaaaa=1, + bbbbbbbbbbbbbbbbbbbbb=2, + ccccccccccccccccccc=3) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testB113210278(self): unformatted_code = """\ def _(): aaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccc(\ From f894d2e5ba8e60d8c0906e5e4511bf7578b4774e Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 28 Aug 2018 18:08:23 -0700 Subject: [PATCH 303/719] Split list elems if they can't fit If list elements can't all fit on the same line, then make sure we split or it might make things ugly (similar to how function calls in lists can look bad). --- CHANGELOG | 3 ++ yapf/yapflib/format_decision_state.py | 9 ++++++ yapftests/reformatter_buganizer_test.py | 43 +++++++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 0d78cc139..a334d682c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,9 @@ not before them regardless of the penalties. ### Fixed - Don't count inner function calls when marking arguments as named assignments. +- Make sure that tuples and the like are formatted nicely if they all can't fit + on a single line. This is similar to how we format function calls within an + argument list. ## [0.23.0] 2018-08-27 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index d61ea8215..318726fe2 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -287,6 +287,15 @@ def SurroundedByParens(token): if not self._FitsOnLine(current, tok.matching_bracket): return True + if current.OpensScope() and previous.value == ',': + # If we have a list of tuples, then we can get a similar look as above. If + # the full list cannot fit on the line, then we want a split. + open_bracket = unwrapped_line.IsSurroundedByBrackets(current) + if (open_bracket and open_bracket.value in '[{' and + format_token.Subtype.SUBSCRIPT_BRACKET not in open_bracket.subtypes): + if not self._FitsOnLine(current, current.matching_bracket): + return True + ########################################################################### # Dict/Set Splitting if (style.Get('EACH_DICT_ENTRY_ON_SEPARATE_LINE') and diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 87b304688..3cbc1042f 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,49 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB80484938(self): + code = """\ +for sssssss, aaaaaaaaaa in [ + ('ssssssssssssssssssss', 'sssssssssssssssssssssssss'), + ('nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn', + 'nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn'), + ('pppppppppppppppppppppppppppp', 'pppppppppppppppppppppppppppppppp'), + ('wwwwwwwwwwwwwwwwwwww', 'wwwwwwwwwwwwwwwwwwwwwwwww'), + ('sssssssssssssssss', 'sssssssssssssssssssssss'), + ('ggggggggggggggggggggggg', 'gggggggggggggggggggggggggggg'), + ('ggggggggggggggggg', 'gggggggggggggggggggggg'), + ('eeeeeeeeeeeeeeeeeeeeee', 'eeeeeeeeeeeeeeeeeeeeeeeeeee') +]: + pass + +for sssssss, aaaaaaaaaa in [ + ('ssssssssssssssssssss', 'sssssssssssssssssssssssss'), + ('nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn', 'nnnnnnnnnnnnnnnnnnnnnnnnn'), + ('pppppppppppppppppppppppppppp', 'pppppppppppppppppppppppppppppppp'), + ('wwwwwwwwwwwwwwwwwwww', 'wwwwwwwwwwwwwwwwwwwwwwwww'), + ('sssssssssssssssss', 'sssssssssssssssssssssss'), + ('ggggggggggggggggggggggg', 'gggggggggggggggggggggggggggg'), + ('ggggggggggggggggg', 'gggggggggggggggggggggg'), + ('eeeeeeeeeeeeeeeeeeeeee', 'eeeeeeeeeeeeeeeeeeeeeeeeeee') +]: + pass + +for sssssss, aaaaaaaaaa in [ + ('ssssssssssssssssssss', 'sssssssssssssssssssssssss'), + ('nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn', + 'nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn'), + ('pppppppppppppppppppppppppppp', 'pppppppppppppppppppppppppppppppp'), + ('wwwwwwwwwwwwwwwwwwww', 'wwwwwwwwwwwwwwwwwwwwwwwww'), + ('sssssssssssssssss', 'sssssssssssssssssssssss'), + ('ggggggggggggggggggggggg', 'gggggggggggggggggggggggggggg'), + ('ggggggggggggggggg', 'gggggggggggggggggggggg'), + ('eeeeeeeeeeeeeeeeeeeeee', 'eeeeeeeeeeeeeeeeeeeeeeeeeee'), +]: + pass +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB79462249(self): code = """\ foo.bar(baz, [ From 15fabad3513c85e1ec01dbdf273977e80d66ce08 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 3 Sep 2018 03:03:31 -0700 Subject: [PATCH 304/719] Specify style in split penalty tests --- yapftests/split_penalty_test.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index 0d300d85a..027b7ebfc 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -22,6 +22,9 @@ from yapf.yapflib import pytree_utils from yapf.yapflib import pytree_visitor from yapf.yapflib import split_penalty +from yapf.yapflib import style + +from yapftests import yapf_test_helper UNBREAKABLE = split_penalty.UNBREAKABLE VERY_STRONGLY_CONNECTED = split_penalty.VERY_STRONGLY_CONNECTED @@ -29,7 +32,11 @@ STRONGLY_CONNECTED = split_penalty.STRONGLY_CONNECTED -class SplitPenaltyTest(unittest.TestCase): +class SplitPenaltyTest(yapf_test_helper.YAPFTest): + + @classmethod + def setUpClass(cls): + style.SetGlobalStyle(style.CreateChromiumStyle()) def _ParseAndComputePenalties(self, code, dumptree=False): """Parses the code and computes split penalties. @@ -198,8 +205,8 @@ def testStronglyConnected(self): ('foo', STRONGLY_CONNECTED), ('if', 0), ('a', STRONGLY_CONNECTED), - ('.', DOTTED_NAME), - ('x', STRONGLY_CONNECTED), + ('.', STRONGLY_CONNECTED), + ('x', DOTTED_NAME), ('==', STRONGLY_CONNECTED), ('37', STRONGLY_CONNECTED), (']', None), @@ -224,10 +231,10 @@ def testFuncCalls(self): tree = self._ParseAndComputePenalties(code) self._CheckPenalties(tree, [ ('foo', None), - ('.', DOTTED_NAME), - ('bar', STRONGLY_CONNECTED), - ('.', DOTTED_NAME), - ('baz', STRONGLY_CONNECTED), + ('.', STRONGLY_CONNECTED), + ('bar', DOTTED_NAME), + ('.', STRONGLY_CONNECTED), + ('baz', DOTTED_NAME), ('(', STRONGLY_CONNECTED), ('1', None), (',', UNBREAKABLE), From e8b87e87d817bf103d3d7efa4edabe13fb6b16a7 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 3 Sep 2018 18:12:13 -0700 Subject: [PATCH 305/719] Allow splitting a subscript if line goes over col limit --- CHANGELOG | 1 + yapf/yapflib/format_decision_state.py | 10 ++-------- yapftests/reformatter_buganizer_test.py | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a334d682c..6e6621d88 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,7 @@ - Make sure that tuples and the like are formatted nicely if they all can't fit on a single line. This is similar to how we format function calls within an argument list. +- Allow splitting in a subscript if it goes over the line limit. ## [0.23.0] 2018-08-27 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 318726fe2..cd6a7291c 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -44,9 +44,6 @@ class FormatDecisionState(object): next_token: The next token to be formatted. paren_level: The level of nesting inside (), [], and {}. lowest_level_on_line: The lowest paren_level on the current line. - newline: Indicates if a newline is added along the edge to this format - decision state node. - previous: The previous format decision state in the decision tree. stack: A stack (of _ParenState) keeping track of properties applying to parenthesis levels. comp_stack: A stack (of ComprehensionState) keeping track of properties @@ -74,8 +71,6 @@ def __init__(self, line, first_indent): self.stack = [_ParenState(first_indent, first_indent)] self.comp_stack = [] self.first_indent = first_indent - self.newline = False - self.previous = None self.column_limit = style.Get('COLUMN_LIMIT') def Clone(self): @@ -89,8 +84,6 @@ def Clone(self): new.lowest_level_on_line = self.lowest_level_on_line new.ignore_stack_for_comparison = self.ignore_stack_for_comparison new.first_indent = self.first_indent - new.newline = self.newline - new.previous = self.previous new.stack = [state.Clone() for state in self.stack] new.comp_stack = [state.Clone() for state in self.comp_stack] return new @@ -186,7 +179,8 @@ def MustSplit(self): if (self.stack[-1].split_before_closing_bracket and current.value in '}]' and style.Get('SPLIT_BEFORE_CLOSING_BRACKET')): # Split before the closing bracket if we can. - return current.node_split_penalty != split_penalty.UNBREAKABLE + if format_token.Subtype.SUBSCRIPT_BRACKET not in current.subtypes: + return current.node_split_penalty != split_penalty.UNBREAKABLE if (current.value == ')' and previous.value == ',' and not _IsSingleElementTuple(current.matching_bracket)): diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 3cbc1042f..2d20ceec0 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,25 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB112651423(self): + unformatted_code = """\ +def potato(feeditems, browse_use_case=None): + for item in turnip: + if kumquat: + if not feeds_variants.variants['FEEDS_LOAD_PLAYLIST_VIDEOS_FOR_ALL_ITEMS'] and item.video: + continue +""" + expected_formatted_code = """\ +def potato(feeditems, browse_use_case=None): + for item in turnip: + if kumquat: + if not feeds_variants.variants[ + 'FEEDS_LOAD_PLAYLIST_VIDEOS_FOR_ALL_ITEMS'] and item.video: + continue +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB80484938(self): code = """\ for sssssss, aaaaaaaaaa in [ From a1f6ae9f2cafd8cf98a2c7bff2c6142b5b1afd2d Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 3 Sep 2018 18:54:38 -0700 Subject: [PATCH 306/719] Increase the split penalty for an if-expression --- CHANGELOG | 1 + yapf/yapflib/split_penalty.py | 15 ++++-- yapftests/reformatter_buganizer_test.py | 68 ++++++++++++++++++++----- 3 files changed, 66 insertions(+), 18 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6e6621d88..ae7a2b033 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,7 @@ on a single line. This is similar to how we format function calls within an argument list. - Allow splitting in a subscript if it goes over the line limit. +- Increase the split penalty for an if-expression. ## [0.23.0] 2018-08-27 ### Added diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index c6ebb0b85..ecfcb418d 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -194,10 +194,10 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name # trailer ::= '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME if node.children[0].value == '.': before = style.Get('SPLIT_BEFORE_DOT') - _SetSplitPenalty(node.children[0], STRONGLY_CONNECTED - if before else DOTTED_NAME) - _SetSplitPenalty(node.children[1], DOTTED_NAME - if before else STRONGLY_CONNECTED) + _SetSplitPenalty(node.children[0], + STRONGLY_CONNECTED if before else DOTTED_NAME) + _SetSplitPenalty(node.children[1], + DOTTED_NAME if before else STRONGLY_CONNECTED) elif len(node.children) == 2: # Don't split an empty argument list if at all possible. _SetSplitPenalty(node.children[1], VERY_STRONGLY_CONNECTED) @@ -333,6 +333,11 @@ def Visit_comp_if(self, node): # pylint: disable=invalid-name _SetStronglyConnected(*node.children[1:]) self.DefaultNodeVisit(node) + def Visit_test(self, node): # pylint: disable=invalid-name + # test ::= or_test ['if' or_test 'else' test] | lambdef + _IncreasePenalty(node, OR_TEST) + self.DefaultNodeVisit(node) + def Visit_or_test(self, node): # pylint: disable=invalid-name # or_test ::= and_test ('or' and_test)* self.DefaultNodeVisit(node) @@ -537,7 +542,7 @@ def RecExpression(node, first_child_leaf): return if isinstance(node, pytree.Leaf): - if node.value in {'(', 'for', 'if'}: + if node.value in {'(', 'for'}: return penalty = pytree_utils.GetNodeAnnotation( node, pytree_utils.Annotation.SPLIT_PENALTY, default=0) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 2d20ceec0..2a5a139f6 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,47 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB112867548(self): + unformatted_code = """\ +def _(): + return flask.make_response( + 'Records: {}, Problems: {}, More: {}'.format( + process_result.result_ct, process_result.problem_ct, + process_result.has_more), + httplib.ACCEPTED if process_result.has_more else httplib.OK, + {'content-type': _TEXT_CONTEXT_TYPE}) +""" + expected_formatted_code = """\ +def _(): + return flask.make_response( + 'Records: {}, Problems: {}, More: {}'.format(process_result.result_ct, + process_result.problem_ct, + process_result.has_more), + httplib.ACCEPTED if process_result.has_more else httplib.OK, + {'content-type': _TEXT_CONTEXT_TYPE}) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testB112651423(self): + unformatted_code = """\ +def potato(feeditems, browse_use_case=None): + for item in turnip: + if kumquat: + if not feeds_variants.variants['FEEDS_LOAD_PLAYLIST_VIDEOS_FOR_ALL_ITEMS'] and item.video: + continue +""" + expected_formatted_code = """\ +def potato(feeditems, browse_use_case=None): + for item in turnip: + if kumquat: + if not feeds_variants.variants[ + 'FEEDS_LOAD_PLAYLIST_VIDEOS_FOR_ALL_ITEMS'] and item.video: + continue +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB112651423(self): unformatted_code = """\ def potato(feeditems, browse_use_case=None): @@ -1879,19 +1920,20 @@ def main(unused_argv): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB15597568(self): - unformatted_code = textwrap.dedent("""\ - if True: - if True: - if True: - print(("Return code was %d" + (", and the process timed out." if did_time_out else ".")) % errorcode) - """) - expected_formatted_code = textwrap.dedent("""\ - if True: - if True: - if True: - print(("Return code was %d" + (", and the process timed out." - if did_time_out else ".")) % errorcode) - """) + unformatted_code = """\ +if True: + if True: + if True: + print(("Return code was %d" + (", and the process timed out." if did_time_out else ".")) % errorcode) +""" + expected_formatted_code = """\ +if True: + if True: + if True: + print(("Return code was %d" + + (", and the process timed out." if did_time_out else ".")) % + errorcode) +""" uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) From 89da752ab8b2402006d152525e360f80ed1e30f8 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 3 Sep 2018 19:34:51 -0700 Subject: [PATCH 307/719] Increase penalty for splitting in subscripts --- CHANGELOG | 2 ++ yapf/yapflib/split_penalty.py | 12 +++++++++--- yapf/yapflib/style.py | 2 +- yapftests/reformatter_basic_test.py | 22 +++++++++++----------- yapftests/reformatter_buganizer_test.py | 9 +++++++++ 5 files changed, 32 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ae7a2b033..60d586998 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,8 @@ argument list. - Allow splitting in a subscript if it goes over the line limit. - Increase the split penalty for an if-expression. +- Increase penalty for splitting in a subscript so that it's more likely to + split in a function call or other data literal. ## [0.23.0] 2018-08-27 ### Added diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index ecfcb418d..5c3927f38 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -26,7 +26,7 @@ # TODO(morbo): Document the annotations in a centralized place. E.g., the # README file. UNBREAKABLE = 1000 * 1000 -NAMED_ASSIGN = 11000 +NAMED_ASSIGN = 15000 DOTTED_NAME = 4000 VERY_STRONGLY_CONNECTED = 3500 STRONGLY_CONNECTED = 3000 @@ -46,7 +46,8 @@ FACTOR = 2100 POWER = 2200 ATOM = 2300 -ONE_ELEMENT_ARGUMENT = 2500 +ONE_ELEMENT_ARGUMENT = 500 +SUBSCRIPT = 6000 def ComputeSplitPenalties(tree): @@ -239,7 +240,12 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name 'atom', 'power' }: # Don't split an argument list with one element if at all possible. - _SetStronglyConnected(node.children[1], node.children[2]) + subtypes = pytree_utils.GetNodeAnnotation( + pytree_utils.FirstLeafNode(node), pytree_utils.Annotation.SUBTYPE) + if subtypes and format_token.Subtype.SUBSCRIPT_BRACKET in subtypes: + _IncreasePenalty(node, SUBSCRIPT) + else: + _SetStronglyConnected(node.children[1], node.children[2]) if name == 'arglist': _SetStronglyConnected(node.children[-1]) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index e4725dfd3..6ee828fba 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -313,7 +313,7 @@ def CreatePEP8Style(): SPLIT_PENALTY_BEFORE_IF_EXPR=0, SPLIT_PENALTY_BITWISE_OPERATOR=300, SPLIT_PENALTY_COMPREHENSION=80, - SPLIT_PENALTY_EXCESS_CHARACTER=4500, + SPLIT_PENALTY_EXCESS_CHARACTER=7000, SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=30, SPLIT_PENALTY_IMPORT_NAMES=0, SPLIT_PENALTY_LOGICAL_OPERATOR=300, diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index a3de63dad..fa9173c32 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1339,18 +1339,18 @@ def testUnaryNotOperator(self): self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testRelaxArraySubscriptAffinity(self): - code = textwrap.dedent("""\ - class A(object): + code = """\ +class A(object): - def f(self, aaaaaaaaa, bbbbbbbbbbbbb, row): - if True: - if True: - if True: - if True: - if row[4] is None or row[5] is None: - bbbbbbbbbbbbb['..............'] = row[ - 5] if row[5] is not None else 5 - """) + def f(self, aaaaaaaaa, bbbbbbbbbbbbb, row): + if True: + if True: + if True: + if True: + if row[4] is None or row[5] is None: + bbbbbbbbbbbbb[ + '..............'] = row[5] if row[5] is not None else 5 +""" uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 2a5a139f6..f62181dcc 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,15 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB112711217(self): + code = """\ +def _(): + stats['moderated'] = ~stats.moderation_reason.isin( + approved_moderation_reasons) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB112867548(self): unformatted_code = """\ def _(): From 0f63b0d3f42a719a7b9577c5b2167bbf9f779570 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 6 Sep 2018 11:32:43 -0600 Subject: [PATCH 308/719] Fixed heading name Adding this to a setup.cfg file does not work: ``` [style] based_on_style = pep8 ``` But this does ``` [yapf] based_on_style = pep8 ``` --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index b5d22d91f..8359ab4ee 100644 --- a/README.rst +++ b/README.rst @@ -149,11 +149,11 @@ the predefined styles (e.g., ``pep8`` or ``google``), a path to a configuration file that specifies the desired style, or a dictionary of key/value pairs. The config file is a simple listing of (case-insensitive) ``key = value`` pairs -with a ``[style]`` heading. For example: +with a ``[yapf]`` heading. For example: .. code-block:: ini - [style] + [yapf] based_on_style = pep8 spaces_before_comment = 4 split_before_logical_operator = true From 9773e5628e89bcf665748eb09528008bd7de9920 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 7 Sep 2018 02:55:56 -0700 Subject: [PATCH 309/719] Copy node annotations after it's cloned. Closes #581 --- CHANGELOG | 2 ++ yapf/yapflib/pytree_utils.py | 12 ++++++++++++ yapf/yapflib/subtype_assigner.py | 10 +++++++++- yapftests/reformatter_basic_test.py | 18 ++++++++++++++++++ 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 60d586998..d03ca3254 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,8 @@ - Increase the split penalty for an if-expression. - Increase penalty for splitting in a subscript so that it's more likely to split in a function call or other data literal. +- Cloning a pytree node doesn't transfer its a annotations. Make sure we do + that so that we don't lose information. ## [0.23.0] 2018-08-27 ### Added diff --git a/yapf/yapflib/pytree_utils.py b/yapf/yapflib/pytree_utils.py index 999ba88bb..23f4a5b6f 100644 --- a/yapf/yapflib/pytree_utils.py +++ b/yapf/yapflib/pytree_utils.py @@ -219,6 +219,18 @@ def _InsertNodeAt(new_node, target, after=False): _NODE_ANNOTATION_PREFIX = '_yapf_annotation_' +def CopyYapfAnnotations(src, dst): + """Copy all YAPF annotations from the source node to the destination node. + + Argumsnts: + src: the source node. + dst: the destination node. + """ + for annotation in dir(src): + if annotation.startswith(_NODE_ANNOTATION_PREFIX): + setattr(dst, annotation, getattr(src, annotation, None)) + + def GetNodeAnnotation(node, annotation, default=None): """Get annotation value from a node. diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index ad6206677..bde7da57f 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -395,7 +395,13 @@ def _InsertPseudoParentheses(node): # A comment was inserted before the value, which is a pytree.Leaf. # Encompass the dictionary's value into an ATOM node. last = first.next_sibling - new_node = pytree.Node(syms.atom, [first.clone(), last.clone()]) + last_clone = last.clone() + new_node = pytree.Node(syms.atom, [first.clone(), last_clone]) + for orig_leaf, clone_leaf in zip(last.leaves(), last_clone.leaves()): + pytree_utils.CopyYapfAnnotations(orig_leaf, clone_leaf) + if hasattr(orig_leaf, 'is_pseudo'): + clone_leaf.is_pseudo = orig_leaf.is_pseudo + node.replace(new_node) node = new_node last.remove() @@ -427,6 +433,8 @@ def _InsertPseudoParentheses(node): _AppendFirstLeafTokenSubtype(node, format_token.Subtype.DICTIONARY_VALUE) else: clone = node.clone() + for orig_leaf, clone_leaf in zip(node.leaves(), clone.leaves()): + pytree_utils.CopyYapfAnnotations(orig_leaf, clone_leaf) new_node = pytree.Node(syms.atom, [lparen, clone, rparen]) node.replace(new_node) _AppendFirstLeafTokenSubtype(clone, format_token.Subtype.DICTIONARY_VALUE) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index fa9173c32..1dc461961 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2350,6 +2350,24 @@ def testEllipses(self): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + def testPseudoParens(self): + unformatted_code = """\ +my_dict = { + 'key': # Some comment about the key + {'nested_key': 1, }, +} +""" + expected_code = """\ +my_dict = { + 'key': # Some comment about the key + { + 'nested_key': 1, + }, +} +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + def testSplittingBeforeFirstArgumentOnFunctionCall(self): """Tests split_before_first_argument on a function call.""" try: From 2635b9a65861f396ee8b9347f51175c8c7fb171f Mon Sep 17 00:00:00 2001 From: Hugo Ricateau Date: Fri, 7 Sep 2018 12:02:30 +0200 Subject: [PATCH 310/719] Fixes bug. --- yapf/yapflib/format_decision_state.py | 1 + 1 file changed, 1 insertion(+) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index cd6a7291c..40b457174 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -930,6 +930,7 @@ def _IsFunctionDefinition(current): def _IsLastScopeInLine(current): + current = current.matching_bracket while current: current = current.next_token if current and current.OpensScope(): From d1dc9a4117ef7dccf2600c46b1aff6af00af1c5f Mon Sep 17 00:00:00 2001 From: Hugo Ricateau Date: Fri, 7 Sep 2018 12:02:49 +0200 Subject: [PATCH 311/719] Adds test. --- yapftests/reformatter_basic_test.py | 31 +++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index fa9173c32..3fd65f89e 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2504,6 +2504,37 @@ def testDisableEndingCommaHeuristic(self): finally: style.SetGlobalStyle(style.CreateChromiumStyle()) + def testDedentClosingBracketsWithTypeAnnotationExceedingLineLength(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{based_on_style: chromium,' + ' dedent_closing_brackets: True}')) + unformatted_code = textwrap.dedent("""\ + def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: + pass + + + def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def function( + first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None + ) -> None: + pass + + + def function( + first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None + ) -> None: + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + if __name__ == '__main__': unittest.main() From ed795f019a175ca75adc211c1850c45705ccca44 Mon Sep 17 00:00:00 2001 From: Hugo Ricateau Date: Fri, 7 Sep 2018 12:03:04 +0200 Subject: [PATCH 312/719] Updates CHANGELOG file. --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 60d586998..78c995e56 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,9 @@ - Increase the split penalty for an if-expression. - Increase penalty for splitting in a subscript so that it's more likely to split in a function call or other data literal. +- Correctly determine if a scope is the last in line. It avoids a wrong + computation of the line end when determining if it must split after the + opening bracket with `DEDENT_CLOSING_BRACKETS` enabled. ## [0.23.0] 2018-08-27 ### Added From 954df0c436554b8c1187381251dce563261f8910 Mon Sep 17 00:00:00 2001 From: Hugo Ricateau Date: Fri, 7 Sep 2018 12:05:59 +0200 Subject: [PATCH 313/719] Updates CHANGELOG file. --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index d03ca3254..b8ed804d9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,8 @@ - Added 'SPLIT_BEFORE_DOT' knob to support "builder style" calls. The "builder style" option didn't work as advertised. Lines would split after the dots, not before them regardless of the penalties. +- Added `INDENT_BLANK_LINES` knob to select whether the blank lines are empty + or indented consistently with the current block. ### Fixed - Don't count inner function calls when marking arguments as named assignments. - Make sure that tuples and the like are formatted nicely if they all can't fit From b17f6ca459ac4f258f7b9ae6995147dc0e8e52a0 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 7 Sep 2018 03:20:30 -0700 Subject: [PATCH 314/719] Support 3.7 in the tests and in the visitor methods Closes #586 --- CHANGELOG | 3 +++ yapf/yapflib/split_penalty.py | 8 ++++++++ yapf/yapflib/subtype_assigner.py | 8 ++++++++ yapftests/reformatter_basic_test.py | 2 ++ 4 files changed, 21 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index d03ca3254..78b601707 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,9 @@ - Added 'SPLIT_BEFORE_DOT' knob to support "builder style" calls. The "builder style" option didn't work as advertised. Lines would split after the dots, not before them regardless of the penalties. +### Changed +- Support Python 3.7 in the tests. The old "comp_for" and "comp_if" nodes are + now "old_comp_for" and "old_comp_if" in lib2to3. ### Fixed - Don't count inner function calls when marking arguments as named assignments. - Make sure that tuples and the like are formatted nicely if they all can't fit diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 5c3927f38..81e4d92a8 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -332,6 +332,10 @@ def Visit_comp_for(self, node): # pylint: disable=invalid-name _SetStronglyConnected(*node.children[1:]) self.DefaultNodeVisit(node) + def Visit_old_comp_for(self, node): # pylint: disable=invalid-name + # Python 3.7 + self.Visit_comp_for(node) + def Visit_comp_if(self, node): # pylint: disable=invalid-name # comp_if ::= 'if' old_test [comp_iter] _SetSplitPenalty(node.children[0], @@ -339,6 +343,10 @@ def Visit_comp_if(self, node): # pylint: disable=invalid-name _SetStronglyConnected(*node.children[1:]) self.DefaultNodeVisit(node) + def Visit_old_comp_if(self, node): # pylint: disable=invalid-name + # Python 3.7 + self.Visit_comp_if(node) + def Visit_test(self, node): # pylint: disable=invalid-name # test ::= or_test ['if' or_test 'else' test] | lambdef _IncreasePenalty(node, OR_TEST) diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index bde7da57f..beb805243 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -315,11 +315,19 @@ def Visit_comp_for(self, node): # pylint: disable=invalid-name _AppendSubtypeRec(node.parent.children[0], format_token.Subtype.COMP_EXPR) self.DefaultNodeVisit(node) + def Visit_old_comp_for(self, node): # pylint: disable=invalid-name + # Python 3.7 + self.Visit_comp_for(node) + def Visit_comp_if(self, node): # pylint: disable=invalid-name # comp_if ::= 'if' old_test [comp_iter] _AppendSubtypeRec(node, format_token.Subtype.COMP_IF) self.DefaultNodeVisit(node) + def Visit_old_comp_if(self, node): # pylint: disable=invalid-name + # Python 3.7 + self.Visit_comp_if(node) + def _ProcessArgLists(self, node): """Common method for processing argument lists.""" for child in node.children: diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 1dc461961..8728a7e54 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -16,6 +16,7 @@ import textwrap import unittest +from yapf.yapflib import py3compat from yapf.yapflib import reformatter from yapf.yapflib import style @@ -2487,6 +2488,7 @@ def testSplitAfterComment(self): finally: style.SetGlobalStyle(style.CreateChromiumStyle()) + @unittest.skipUnless(not py3compat.PY3, 'Requires Python 2.7') def testAsyncAsNonKeyword(self): try: style.SetGlobalStyle(style.CreatePEP8Style()) From 25b25eae0886e3b030e28b3d61ee39291408bf58 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 7 Sep 2018 03:41:00 -0700 Subject: [PATCH 315/719] Revert behavior of "no spaces" knob The old behavior broke in 0.23. Revert that change back to the old behavior. Closes #608 --- CHANGELOG | 1 + README.rst | 2 +- yapf/yapflib/style.py | 6 ++---- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 78b601707..e1d4f8121 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -21,6 +21,7 @@ split in a function call or other data literal. - Cloning a pytree node doesn't transfer its a annotations. Make sure we do that so that we don't lose information. +- Revert change that broke the "no_spaces_around_binary_operators" option. ## [0.23.0] 2018-08-27 ### Added diff --git a/README.rst b/README.rst index 8359ab4ee..b91a71fb4 100644 --- a/README.rst +++ b/README.rst @@ -458,7 +458,7 @@ Knobs 1 + 2 * 3 - 4 / 5 - will be formatted as follows when configured with ``"*/"``: + will be formatted as follows when configured with ``*,/``: .. code-block:: python diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 6ee828fba..88ee02692 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -161,7 +161,7 @@ def method(): 1 + 2 * 3 - 4 / 5 - will be formatted as follows when configured with *,/: + will be formatted as follows when configured with "*,/": 1 + 2*3 - 4/5 @@ -411,9 +411,7 @@ def _StringSetConverter(s): """Option value converter for a comma-separated set of strings.""" if len(s) > 2 and s[0] in '"\'': s = s[1:-1] - if ',' in s: - return set(part.strip() for part in s.split(',')) - return set(s.strip()) + return set(part.strip() for part in s.split(',')) def _BoolConverter(s): From 3418ff90ba75db9081381303b6a3d7e741aab7da Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 7 Sep 2018 03:56:57 -0700 Subject: [PATCH 316/719] Don't format the style output as a Python type Closes #609 --- CHANGELOG | 3 +++ yapf/__init__.py | 5 ++++- yapf/yapflib/style.py | 2 -- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e1d4f8121..faa32c235 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -22,6 +22,9 @@ - Cloning a pytree node doesn't transfer its a annotations. Make sure we do that so that we don't lose information. - Revert change that broke the "no_spaces_around_binary_operators" option. +- The "--style-help" option would output string lists and sets in Python types. + If the output was used as a style, then it wouldn't parse those values + correctly. ## [0.23.0] 2018-08-27 ### Added diff --git a/yapf/__init__.py b/yapf/__init__.py index 5d8a27c5d..a157c5b45 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -145,7 +145,10 @@ def main(argv): for option, docstring in sorted(style.Help().items()): for line in docstring.splitlines(): print('#', line and ' ' or '', line, sep='') - print(option.lower(), '=', style.Get(option), sep='') + option_value = style.Get(option) + if isinstance(option_value, set) or isinstance(option_value, list): + option_value = ', '.join(option_value) + print(option.lower(), '=', option_value, sep='') print() return 0 diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 88ee02692..ecead0a2a 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -402,8 +402,6 @@ def _ContinuationAlignStyleStringConverter(s): def _StringListConverter(s): """Option value converter for a comma-separated list of strings.""" - if len(s) > 2 and s[0] in '"\'': - s = s[1:-1] return [part.strip() for part in s.split(',')] From 5f1c00595a9db475f322be15630cd49828351dba Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 7 Sep 2018 04:02:43 -0700 Subject: [PATCH 317/719] Bump version to v0.24.0 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index faa32c235..076997fc7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.24.0] UNRELEASED +## [0.24.0] 2018-09-07 ### Added - Added 'SPLIT_BEFORE_DOT' knob to support "builder style" calls. The "builder style" option didn't work as advertised. Lines would split after the dots, diff --git a/yapf/__init__.py b/yapf/__init__.py index a157c5b45..c6ffc4d84 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.23.0' +__version__ = '0.24.0' def main(argv): From fcc9eed18ca5fb6b9886bcdaab482e4509c32050 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 7 Sep 2018 14:25:54 -0700 Subject: [PATCH 318/719] Remove some pylint errors. --- yapf/yapflib/pytree_utils.py | 2 +- yapftests/reformatter_basic_test.py | 7 +++++-- yapftests/reformatter_buganizer_test.py | 19 ------------------- 3 files changed, 6 insertions(+), 22 deletions(-) diff --git a/yapf/yapflib/pytree_utils.py b/yapf/yapflib/pytree_utils.py index 23f4a5b6f..75d4ca208 100644 --- a/yapf/yapflib/pytree_utils.py +++ b/yapf/yapflib/pytree_utils.py @@ -222,7 +222,7 @@ def _InsertNodeAt(new_node, target, after=False): def CopyYapfAnnotations(src, dst): """Copy all YAPF annotations from the source node to the destination node. - Argumsnts: + Arguments: src: the source node. dst: the destination node. """ diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 3de71a847..b12ad5005 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -157,14 +157,17 @@ def bar(): return 0 """) - expected_formatted_code = """class foo(object):\n \n def foobar(self):\n \n pass\n \n def barfoo(self, x, y): # bar\n \n if x:\n \n return y\n\n\ndef bar():\n \n return 0\n""" + expected_formatted_code = """\ +class foo(object):\n \n def foobar(self):\n \n pass\n \n def barfoo(self, x, y): # bar\n \n if x:\n \n return y\n\n\ndef bar():\n \n return 0 +""" uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: style.SetGlobalStyle(style.CreateChromiumStyle()) - unformatted_code, expected_formatted_code = expected_formatted_code, unformatted_code + unformatted_code, expected_formatted_code = (expected_formatted_code, + unformatted_code) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index f62181dcc..d888ce47b 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -78,25 +78,6 @@ def potato(feeditems, browse_use_case=None): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - def testB112651423(self): - unformatted_code = """\ -def potato(feeditems, browse_use_case=None): - for item in turnip: - if kumquat: - if not feeds_variants.variants['FEEDS_LOAD_PLAYLIST_VIDEOS_FOR_ALL_ITEMS'] and item.video: - continue -""" - expected_formatted_code = """\ -def potato(feeditems, browse_use_case=None): - for item in turnip: - if kumquat: - if not feeds_variants.variants[ - 'FEEDS_LOAD_PLAYLIST_VIDEOS_FOR_ALL_ITEMS'] and item.video: - continue -""" - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - def testB80484938(self): code = """\ for sssssss, aaaaaaaaaa in [ From 46d35e6e854762fffdc0c8ed8d96aeb7d8ebfeee Mon Sep 17 00:00:00 2001 From: Michael Grupp Date: Sun, 16 Sep 2018 19:34:02 +0200 Subject: [PATCH 319/719] Catch KeyboardInterrupt when reading from stdin. Do not print traceback and directly exit with error code. This is more consistent with other UNIX CLI tools. --- yapf/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/yapf/__init__.py b/yapf/__init__.py index c6ffc4d84..613ff078d 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -174,6 +174,8 @@ def main(argv): original_source.append(py3compat.raw_input()) except EOFError: break + except KeyboardInterrupt: + return 1 if style_config is None and not args.no_local_style: style_config = file_resources.GetDefaultStyleForDir(os.getcwd()) From 591d599510c5c96a36ea7e27a18a5d343c7ab388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Dalfors?= Date: Sat, 24 Mar 2018 10:02:23 +0100 Subject: [PATCH 320/719] look for exclude patterns in local CWD/.yapfignore fix spelling & linting use readlines() instead fix long line --- CHANGELOG | 4 ++++ README.rst | 8 ++++++++ yapf/__init__.py | 9 +++++++-- yapf/yapflib/file_resources.py | 30 ++++++++++++++++++++++++++++++ yapftests/file_resources_test.py | 24 ++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 698e6ea3b..504fcde74 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.26.0] UNRELEASED +### Added +- Support additional file exclude patterns in .yapfignore file. + ## [0.25.0] UNRELEASED ### Added - Added `INDENT_BLANK_LINES` knob to select whether the blank lines are empty diff --git a/README.rst b/README.rst index 366a80e47..f5773e0be 100644 --- a/README.rst +++ b/README.rst @@ -136,6 +136,14 @@ If ``--diff`` is supplied, YAPF returns zero when no changes were necessary, non otherwise (including program error). You can use this in a CI workflow to test that code has been YAPF-formatted. +--------------------------------------------- +Excluding files from formatting (.yapfignore) +--------------------------------------------- + +In addition to exlude patterns provided on commandline, YAPF looks for additional +patterns specified in a file named ``.yapfignore`` located in the working directory from +which YAPF is invoked. + Formatting style ================ diff --git a/yapf/__init__.py b/yapf/__init__.py index c6ffc4d84..bda5b8152 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -188,8 +188,13 @@ def main(argv): file_resources.WriteReformattedCode('', reformatted_source) return 0 - files = file_resources.GetCommandLineFiles(args.files, args.recursive, - args.exclude) + # Get additional exclude patterns from ignorefile + exclude_patterns_from_ignore_file = file_resources.GetExcludePatternsForDir( + os.getcwd()) + + files = file_resources.GetCommandLineFiles( + args.files, args.recursive, + (args.exclude or []) + exclude_patterns_from_ignore_file) if not files: raise errors.YapfError('Input filenames did not match any python files') diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 6e7202d10..18e6c6b31 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -32,6 +32,36 @@ CRLF = '\r\n' +def _GetExcludePatternsFromFile(filename): + ignore_patterns = [] + # See if we have a .yapfignore file. + if os.path.isfile(filename) and os.access(filename, os.R_OK): + for line in open(filename, 'r').readlines(): + if line.strip() and not line.startswith('#'): + ignore_patterns.append(line.strip()) + + if any(e.startswith('./') for e in ignore_patterns): + raise errors.YapfError('path in .yapfignore should not start with ./') + + return ignore_patterns + + +def GetExcludePatternsForDir(dirname): + """Return patterns of files to exclude from ignorefile in a given directory. + + Looks for .yapfignore in the directory dirname. + + Arguments: + dirname: (unicode) The name of the directory. + + Returns: + A List of file patterns to exclude if ignore file is found + , otherwhise empty List. + """ + ignore_file = os.path.join(dirname, '.yapfignore') + return _GetExcludePatternsFromFile(ignore_file) + + def GetDefaultStyleForDir(dirname): """Return default style name for a given directory. diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 8391e5f42..0f413f851 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -36,6 +36,30 @@ def _restore_working_dir(): os.chdir(curdir) +class GetExcludePatternsForDir(unittest.TestCase): + + def setUp(self): + self.test_tmpdir = tempfile.mkdtemp() + + def tearDown(self): + shutil.rmtree(self.test_tmpdir) + + def _make_test_dir(self, name): + fullpath = os.path.normpath(os.path.join(self.test_tmpdir, name)) + os.makedirs(fullpath) + return fullpath + + def test_get_exclude_file_patterns(self): + local_ignore_file = os.path.join(self.test_tmpdir, '.yapfignore') + ignore_patterns = ['temp/**/*.py', 'temp2/*.py'] + with open(local_ignore_file, 'w') as f: + f.writelines('\n'.join(ignore_patterns)) + + self.assertEqual( + sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)), + sorted(ignore_patterns)) + + class GetDefaultStyleForDirTest(unittest.TestCase): def setUp(self): From a1d7c440b2cc4f7340b322ff5c4f85850259c7bf Mon Sep 17 00:00:00 2001 From: Derek Date: Thu, 1 Nov 2018 23:00:44 -0700 Subject: [PATCH 321/719] Use canonical name for snake case in contributing docs --- CONTRIBUTING.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 0b113c0d8..d68dedb77 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -32,7 +32,7 @@ YAPF follows the `Chromium Python Style Guide as the Google Python Style guide with two exceptions: - 2 spaces for indentation rather than 4. -- CamelCase for function and method names rather than words_with_underscores. +- CamelCase for function and method names rather than snake_case. The rationale for this is that YAPF was initially developed at Google where these two exceptions are still part of the internal Python style guide. From 3ca2734a17102524222b76aab213075b4f67bc2d Mon Sep 17 00:00:00 2001 From: Michael Grupp Date: Mon, 5 Nov 2018 11:29:09 +0100 Subject: [PATCH 322/719] Allow custom default for GetDefaultStyleForDir() --- yapf/yapflib/file_resources.py | 8 +++++--- yapftests/file_resources_test.py | 6 ++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 6e7202d10..56e9dbbe1 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -32,16 +32,18 @@ CRLF = '\r\n' -def GetDefaultStyleForDir(dirname): +def GetDefaultStyleForDir(dirname, default_style=style.DEFAULT_STYLE): """Return default style name for a given directory. Looks for .style.yapf or setup.cfg in the parent directories. Arguments: dirname: (unicode) The name of the directory. + default_style: The style to return if nothing is found. Defaults to the + global default style ('pep8') unless otherwise specified. Returns: - The filename if found, otherwise return the global default (pep8). + The filename if found, otherwise return the default style. """ dirname = os.path.abspath(dirname) while True: @@ -68,7 +70,7 @@ def GetDefaultStyleForDir(dirname): if os.path.exists(global_file): return global_file - return style.DEFAULT_STYLE + return default_style def GetCommandLineFiles(command_line_file_list, recursive, exclude): diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 8391e5f42..78a0db460 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -49,6 +49,12 @@ def test_no_local_style(self): style_name = file_resources.GetDefaultStyleForDir(test_file) self.assertEqual(style_name, 'pep8') + def test_no_local_style_custom_default(self): + test_file = os.path.join(self.test_tmpdir, 'file.py') + style_name = file_resources.GetDefaultStyleForDir( + test_file, default_style='custom-default') + self.assertEqual(style_name, 'custom-default') + def test_with_local_style(self): # Create an empty .style.yapf file in test_tmpdir style_file = os.path.join(self.test_tmpdir, '.style.yapf') From 7b2f6da3c90d36c5d1ce4078321db735b09b3d5d Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 25 Nov 2018 00:08:31 -0800 Subject: [PATCH 323/719] Bump version to 0.25.0 --- CHANGELOG | 5 +---- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 504fcde74..4f5ba0997 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,14 +2,11 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.26.0] UNRELEASED -### Added -- Support additional file exclude patterns in .yapfignore file. - ## [0.25.0] UNRELEASED ### Added - Added `INDENT_BLANK_LINES` knob to select whether the blank lines are empty or indented consistently with the current block. +- Support additional file exclude patterns in .yapfignore file. ### Fixed - Correctly determine if a scope is the last in line. It avoids a wrong computation of the line end when determining if it must split after the diff --git a/yapf/__init__.py b/yapf/__init__.py index 773e17122..10a88858a 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.24.0' +__version__ = '0.25.0' def main(argv): From db09ad2f52469925bdb6f3f419a46abb47918b66 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 26 Nov 2018 06:08:37 -0800 Subject: [PATCH 324/719] Align trailing comments to columns --- README.rst | 5 + yapf/yapflib/format_decision_state.py | 11 +- yapf/yapflib/reformatter.py | 124 +++++++++++++ yapf/yapflib/style.py | 23 ++- yapf/yapflib/unwrapped_line.py | 14 +- yapftests/style_test.py | 9 + yapftests/yapf_test.py | 242 ++++++++++++++++++++++++++ 7 files changed, 424 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index f5773e0be..703ea1fc2 100644 --- a/README.rst +++ b/README.rst @@ -484,6 +484,11 @@ Knobs ``SPACES_BEFORE_COMMENT`` The number of spaces required before a trailing comment. + This can be a single value (representing the number of spaces + before each trailing comment) or list of of values (representing + alignment column values; trailing comments within a block will + be aligned to the first column value that is greater than the maximum + line length within the block). ``SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET`` Insert a space between the ending comma and closing bracket of a list, etc. diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 40b457174..9a14813bd 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -522,6 +522,11 @@ def _AddTokenOnCurrentLine(self, dry_run): previous = current.previous_token spaces = current.spaces_required_before + if isinstance(spaces, list): + # Don't set the value here, as we need to look at the lines near + # this one to determine the actual horizontal alignment value. + spaces = 0 + if not dry_run: current.AddWhitespacePrefix(newlines_before=0, spaces=spaces) @@ -742,7 +747,11 @@ def _GetNewlineColumn(self): previous = current.previous_token top_of_stack = self.stack[-1] - if current.spaces_required_before > 2 or self.line.disable: + if isinstance(current.spaces_required_before, list): + # Don't set the value here, as we need to look at the lines near + # this one to determine the actual horizontal alignment value. + return 0 + elif current.spaces_required_before > 2 or self.line.disable: return current.spaces_required_before if current.OpensScope(): diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 7d26038d0..e6f155585 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -95,6 +95,8 @@ def Reformat(uwlines, verify=False, lines=None): final_lines.append(uwline) prev_uwline = uwline + + _AlignTrailingComments(final_lines) return _FormatFinalLines(final_lines, verify) @@ -246,6 +248,128 @@ def _CanPlaceOnSingleLine(uwline): not any(tok.is_comment for tok in uwline.tokens[:last_index])) +def _AlignTrailingComments(final_lines): + final_lines_index = 0 + while final_lines_index < len(final_lines): + line = final_lines[final_lines_index] + assert line.tokens + + processed_content = False + + for tok in line.tokens: + if tok.is_comment and isinstance(tok.spaces_required_before, + list) and tok.value.startswith('#'): + # All trailing comments and comments that appear on a line by themselves in this block + # should be indented at the same level. The block is terminated by an empty line or EOF. + # Enumerate through each line in the block and calculate the max line length. Once complete, + # use the first col value greater than that value and create the necessary for each line + # accordingly. + all_pc_line_lengths = [] # All pre-comment line lengths + max_line_length = 0 + + while True: + # EOF + if final_lines_index + len(all_pc_line_lengths) == len(final_lines): + break + + this_line = final_lines[final_lines_index + len(all_pc_line_lengths)] + + # Blank line - note that content is preformatted so we don't need to worry + # about spaces/tabs; a blank line will always be '\n\n'. + assert this_line.tokens + if all_pc_line_lengths and this_line.tokens[ + 0].formatted_whitespace_prefix.startswith('\n\n'): + break + + # Calculate the length of each line in this unwrapped line. + line_content = '' + pc_line_lengths = [] + + for line_tok in this_line.tokens: + whitespace_prefix = line_tok.formatted_whitespace_prefix + + newline_index = whitespace_prefix.rfind('\n') + if newline_index != -1: + max_line_length = max(max_line_length, len(line_content)) + line_content = '' + + whitespace_prefix = whitespace_prefix[newline_index + 1:] + + if line_tok.is_comment: + pc_line_lengths.append(len(line_content)) + else: + line_content += "{}{}".format(whitespace_prefix, line_tok.value) + + if pc_line_lengths: + max_line_length = max(max_line_length, max(pc_line_lengths)) + + all_pc_line_lengths.append(pc_line_lengths) + + # Calculate the aligned column value + max_line_length += 2 + + aligned_col = None + for potential_col in tok.spaces_required_before: + if potential_col > max_line_length: + aligned_col = potential_col + break + + if aligned_col is None: + aligned_col = max_line_length + + # Update the comment token values based on the aligned values + for all_pc_line_lengths_index, pc_line_lengths in enumerate( + all_pc_line_lengths): + if not pc_line_lengths: + continue + + this_line = final_lines[final_lines_index + all_pc_line_lengths_index] + + pc_line_length_index = 0 + for line_tok in this_line.tokens: + if line_tok.is_comment: + assert pc_line_length_index < len(pc_line_lengths) + assert pc_line_lengths[pc_line_length_index] < aligned_col + + # Note that there may be newlines embedded in the comments, so + # we need to apply a whitespace prefix to each line. + whitespace = ' ' * ( + aligned_col - pc_line_lengths[pc_line_length_index] - 1) + pc_line_length_index += 1 + + line_content = [] + + for comment_line_index, comment_line in enumerate( + line_tok.value.split('\n')): + line_content.append("{}{}".format(whitespace, + comment_line.strip())) + + if comment_line_index == 0: + whitespace = ' ' * (aligned_col - 1) + + line_content = '\n'.join(line_content) + + # Account for initial whitespace already slated for the + # beginning of the line. + existing_whitespace_prefix = line_tok.formatted_whitespace_prefix.lstrip( + '\n') + + if line_content.startswith(existing_whitespace_prefix): + line_content = line_content[len(existing_whitespace_prefix):] + + line_tok.value = line_content + + assert pc_line_length_index == len(pc_line_lengths) + + final_lines_index += len(all_pc_line_lengths) + + processed_content = True + break + + if not processed_content: + final_lines_index += 1 + + def _FormatFinalLines(final_lines, verify): """Compose the final output from the finalized lines.""" formatted_code = [] diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 87f1b5448..c57f2ceb7 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -176,7 +176,12 @@ def method(): SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=textwrap.dedent("""\ Use spaces around default or named assigns."""), SPACES_BEFORE_COMMENT=textwrap.dedent("""\ - The number of spaces required before a trailing comment."""), + The number of spaces required before a trailing comment. + This can be a single value (representing the number of spaces + before each trailing comment) or list of of values (representing + alignment column values; trailing comments within a block will + be aligned to the first column value that is greater than the maximum + line length within the block)."""), SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=textwrap.dedent("""\ Split before arguments if the argument list is terminated by a comma."""), @@ -420,6 +425,20 @@ def _BoolConverter(s): return py3compat.CONFIGPARSER_BOOLEAN_STATES[s.lower()] +def _IntListConverter(s): + """Option value converter for a comma-separated list of integers.""" + s = s.strip() + if s.startswith('[') and s.endswith(']'): + s = s[1:-1] + + return [int(part.strip()) for part in s.split(',') if part.strip()] + + +def _IntOrIntListConverter(s): + """Option value converter for an integer or list of integers.""" + return _IntListConverter(s) if ',' in s else int(s) + + # Different style options need to have their values interpreted differently when # read from the config file. This dict maps an option name to a "converter" # function that accepts the string read for the option's value from the file and @@ -453,7 +472,7 @@ def _BoolConverter(s): SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=_BoolConverter, SPACES_AROUND_POWER_OPERATOR=_BoolConverter, SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=_BoolConverter, - SPACES_BEFORE_COMMENT=int, + SPACES_BEFORE_COMMENT=_IntOrIntListConverter, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter, SPLIT_ALL_COMMA_SEPARATED_VALUES=_BoolConverter, SPLIT_BEFORE_BITWISE_OPERATOR=_BoolConverter, diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 0bf4fba44..f37f3e48e 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -73,7 +73,19 @@ def CalculateFormattingInformation(self): token.spaces_required_before = 1 tok_len = len(token.value) if not token.is_pseudo_paren else 0 - token.total_length = prev_length + tok_len + token.spaces_required_before + + spaces_required_before = token.spaces_required_before + if isinstance(spaces_required_before, list): + assert token.is_comment, token + + # If here, we are looking at a comment token that appears on a line + # with other tokens (but because it is a comment, it is always the last token). + # Rather than specifying the actual number of spaces here, hard code a value of + # 0 and then set it later. This logic only works because this comment token is + # guaranteed to be the last token in the list. + spaces_required_before = 0 + + token.total_length = prev_length + tok_len + spaces_required_before # The split penalty has to be computed before {must|can}_break_before, # because these may use it for their decision. diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 7f4a4652a..f525a48ab 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -53,6 +53,15 @@ def testBoolConverter(self): self.assertEqual(style._BoolConverter('false'), False) self.assertEqual(style._BoolConverter('0'), False) + def testIntListConverter(self): + self.assertEqual(style._IntListConverter("1, 2, 3"), [1, 2, 3]) + self.assertEqual(style._IntListConverter("[ 1, 2, 3 ]"), [1, 2, 3]) + self.assertEqual(style._IntListConverter("[ 1, 2, 3, ]"), [1, 2, 3]) + + def testIntOrIntListConverter(self): + self.assertEqual(style._IntOrIntListConverter("10"), 10) + self.assertEqual(style._IntOrIntListConverter("1, 2, 3"), [1, 2, 3]) + def _LooksLikeChromiumStyle(cfg): return (cfg['INDENT_WIDTH'] == 2 and diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index c9302aa61..7769feb51 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1436,5 +1436,247 @@ def testSimple(self): self._Check(unformatted_code, expected_formatted_code) +class HorizontallyAlignedTrailingCommentsTest(unittest.TestCase): + + @staticmethod + def _OwnStyle(): + my_style = style.CreatePEP8Style() + my_style["SPACES_BEFORE_COMMENT"] = [ + 15, + 25, + 35, + ] + return my_style + + def _Check(self, unformatted_code, expected_formatted_code): + formatted_code, _ = yapf_api.FormatCode( + unformatted_code, style_config=style.SetGlobalStyle(self._OwnStyle())) + self.assertEqual(expected_formatted_code, formatted_code) + + def setUp(self): + self.maxDiff = None + + def testSimple(self): + unformatted_code = textwrap.dedent("""\ + foo = '1' # Aligned at first list value + + foo = '2__<15>' # Aligned at second list value + + foo = '3____________<25>' # Aligned at third list value + + foo = '4______________________<35>' # Aligned beyond list values + """) + expected_formatted_code = textwrap.dedent("""\ + foo = '1' # Aligned at first list value + + foo = '2__<15>' # Aligned at second list value + + foo = '3____________<25>' # Aligned at third list value + + foo = '4______________________<35>' # Aligned beyond list values + """) + self._Check(unformatted_code, expected_formatted_code) + + def testBlock(self): + unformatted_code = textwrap.dedent("""\ + func(1) # Line 1 + func(2) # Line 2 + # Line 3 + func(3) # Line 4 + # Line 5 + # Line 6 + """) + expected_formatted_code = textwrap.dedent("""\ + func(1) # Line 1 + func(2) # Line 2 + # Line 3 + func(3) # Line 4 + # Line 5 + # Line 6 + """) + self._Check(unformatted_code, expected_formatted_code) + + def testBlockWithLongLine(self): + unformatted_code = textwrap.dedent("""\ + func(1) # Line 1 + func___________________(2) # Line 2 + # Line 3 + func(3) # Line 4 + # Line 5 + # Line 6 + """) + expected_formatted_code = textwrap.dedent("""\ + func(1) # Line 1 + func___________________(2) # Line 2 + # Line 3 + func(3) # Line 4 + # Line 5 + # Line 6 + """) + self._Check(unformatted_code, expected_formatted_code) + + def testBlockFuncSuffix(self): + unformatted_code = textwrap.dedent("""\ + func(1) # Line 1 + func(2) # Line 2 + # Line 3 + func(3) # Line 4 + # Line 5 - SpliceComments makes this a new block + # Line 6 + + def Func(): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + func(1) # Line 1 + func(2) # Line 2 + # Line 3 + func(3) # Line 4 + + # Line 5 - SpliceComments makes this a new block + # Line 6 + + + def Func(): + pass + """) + self._Check(unformatted_code, expected_formatted_code) + + def testBlockCommentSuffix(self): + unformatted_code = textwrap.dedent("""\ + func(1) # Line 1 + func(2) # Line 2 + # Line 3 + func(3) # Line 4 + # Line 5 - SpliceComments makes this part of the previous block + # Line 6 + + # Aligned with prev comment block + """) + expected_formatted_code = textwrap.dedent("""\ + func(1) # Line 1 + func(2) # Line 2 + # Line 3 + func(3) # Line 4 + # Line 5 - SpliceComments makes this part of the previous block + # Line 6 + + # Aligned with prev comment block + """) + self._Check(unformatted_code, expected_formatted_code) + + def testBlockIndentedFuncSuffix(self): + unformatted_code = textwrap.dedent("""\ + if True: + func(1) # Line 1 + func(2) # Line 2 + # Line 3 + func(3) # Line 4 + # Line 5 - SpliceComments makes this a new block + # Line 6 + + # Aligned with Func + + def Func(): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + if True: + func(1) # Line 1 + func(2) # Line 2 + # Line 3 + func(3) # Line 4 + + # Line 5 - SpliceComments makes this a new block + # Line 6 + + # Aligned with Func + + + def Func(): + pass + """) + self._Check(unformatted_code, expected_formatted_code) + + def testBlockIndentedCommentSuffix(self): + unformatted_code = textwrap.dedent("""\ + if True: + func(1) # Line 1 + func(2) # Line 2 + # Line 3 + func(3) # Line 4 + # Line 5 + # Line 6 + + # Not aligned + """) + expected_formatted_code = textwrap.dedent("""\ + if True: + func(1) # Line 1 + func(2) # Line 2 + # Line 3 + func(3) # Line 4 + # Line 5 + # Line 6 + + # Not aligned + """) + self._Check(unformatted_code, expected_formatted_code) + + def testBlockMultiIndented(self): + unformatted_code = textwrap.dedent("""\ + if True: + if True: + if True: + func(1) # Line 1 + func(2) # Line 2 + # Line 3 + func(3) # Line 4 + # Line 5 + # Line 6 + + # Not aligned + """) + expected_formatted_code = textwrap.dedent("""\ + if True: + if True: + if True: + func(1) # Line 1 + func(2) # Line 2 + # Line 3 + func(3) # Line 4 + # Line 5 + # Line 6 + + # Not aligned + """) + self._Check(unformatted_code, expected_formatted_code) + + def testArgs(self): + unformatted_code = textwrap.dedent("""\ + def MyFunc( + arg1, # Desc 1 + arg2, # Desc 2 + a_longer_var_name, # Desc 3 + arg4, + arg5, # Desc 5 + arg6, + ): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def MyFunc( + arg1, # Desc 1 + arg2, # Desc 2 + a_longer_var_name, # Desc 3 + arg4, + arg5, # Desc 5 + arg6, + ): + pass + """) + self._Check(unformatted_code, expected_formatted_code) + + if __name__ == '__main__': unittest.main() From 5773f44199808ebc7b2749e18e6da45259beeaf1 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 27 Nov 2018 23:57:42 -0800 Subject: [PATCH 325/719] Return opening bracket If we search for the opening bracket, make sure it's an opening one instead of closing. --- CHANGELOG | 7 ++++++- yapf/yapflib/format_decision_state.py | 3 ++- yapftests/reformatter_basic_test.py | 7 +++---- yapftests/reformatter_buganizer_test.py | 12 +++++++++--- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4f5ba0997..6fbe81711 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,12 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.25.0] UNRELEASED +## [0.25.1] UNRELEASED +### Fixed +- When retrieving the opening bracket make sure that it's actually an opening + bracket. + +## [0.25.0] 2018-11-25 ### Added - Added `INDENT_BLANK_LINES` knob to select whether the blank lines are empty or indented consistently with the current block. diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 40b457174..beac62053 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -905,7 +905,8 @@ def _GetLengthOfSubtype(token, subtype, exclude=None): def _GetOpeningBracket(current): """Get the opening bracket containing the current token.""" if current.matching_bracket and not current.is_pseudo_paren: - return current.matching_bracket + return current if current.OpensScope() else current.matching_bracket + while current: if current.ClosesScope(): current = current.matching_bracket diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index b12ad5005..970c7cad2 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1255,10 +1255,9 @@ def testSplitStringsIfSurroundedByParens(self): a = foo.bar({'xxxxxxxxxxxxxxxxxxxxxxx' 'yyyyyyyyyyyyyyyyyyyyyyyyyy': baz[42]} + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbb' 'cccccccccccccccccccccccccccccccc' 'ddddddddddddddddddddddddddddd') """) expected_formatted_code = textwrap.dedent("""\ - a = foo.bar({ - 'xxxxxxxxxxxxxxxxxxxxxxx' - 'yyyyyyyyyyyyyyyyyyyyyyyyyy': baz[42] - } + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + a = foo.bar({'xxxxxxxxxxxxxxxxxxxxxxx' + 'yyyyyyyyyyyyyyyyyyyyyyyyyy': baz[42]} + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbb' 'cccccccccccccccccccccccccccccccc' 'ddddddddddddddddddddddddddddd') diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index d888ce47b..021026f9c 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,14 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB116825060(self): + code = """\ +result_df = pd.DataFrame({LEARNED_CTR_COLUMN: learned_ctr}, + index=df_metrics.index) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB112711217(self): code = """\ def _(): @@ -1767,9 +1775,7 @@ def f(): if True: if True: return aaaa.bbbbbbbbb( - ccccccc=dddddddddddddd({ - ('eeee', 'ffffffff'): str(j) - })) + ccccccc=dddddddddddddd({('eeee', 'ffffffff'): str(j)})) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) From fd687af7edc415c781f3a4a4f5238a1bce44c42e Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 28 Nov 2018 00:50:16 -0800 Subject: [PATCH 326/719] Don't make lambdas unbreakable. As a last resort we may need to split a lambda. --- CHANGELOG | 2 ++ yapf/yapflib/split_penalty.py | 2 +- yapftests/reformatter_buganizer_test.py | 14 ++++++++++++++ yapftests/split_penalty_test.py | 20 ++++++++++---------- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6fbe81711..0ba60d0b1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,8 @@ ### Fixed - When retrieving the opening bracket make sure that it's actually an opening bracket. +- Don't completely deny a lambda formatting if it goes over the column limit. + Split only if absolutely necessary. ## [0.25.0] 2018-11-25 ### Added diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 81e4d92a8..6eee4bfd3 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -126,7 +126,7 @@ def Visit_lambdef(self, node): # pylint: disable=invalid-name if allow_multiline_lambdas: _SetStronglyConnected(node) else: - self._SetUnbreakableOnChildren(node) + _SetVeryStronglyConnected(node) def Visit_parameters(self, node): # pylint: disable=invalid-name # parameters ::= '(' [typedargslist] ')' diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 021026f9c..ddfc3e723 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,20 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB111764402(self): + unformatted_code = """\ +x = self.stubs.stub(video_classification_map, 'read_video_classifications', (lambda external_ids, **unused_kwargs: {external_id: self._get_serving_classification('video') for external_id in external_ids})) +""" + expected_formatted_code = """\ +x = self.stubs.stub(video_classification_map, 'read_video_classifications', + (lambda external_ids, **unused_kwargs: { + external_id: self._get_serving_classification('video') + for external_id in external_ids + })) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB116825060(self): code = """\ result_df = pd.DataFrame({LEARNED_CTR_COLUMN: learned_ctr}, diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index 027b7ebfc..881b639a3 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -139,12 +139,12 @@ class B(A): """) tree = self._ParseAndComputePenalties(code) self._CheckPenalties(tree, [ - ('lambda', None), - ('a', UNBREAKABLE), - (',', UNBREAKABLE), - ('b', UNBREAKABLE), - (':', UNBREAKABLE), - ('None', UNBREAKABLE), + ('lambda', VERY_STRONGLY_CONNECTED), + ('a', VERY_STRONGLY_CONNECTED), + (',', VERY_STRONGLY_CONNECTED), + ('b', VERY_STRONGLY_CONNECTED), + (':', VERY_STRONGLY_CONNECTED), + ('None', VERY_STRONGLY_CONNECTED), ]) # Test dotted names. @@ -180,10 +180,10 @@ def testStronglyConnected(self): (',', None), ('y', None), ('(', UNBREAKABLE), - ('lambda', STRONGLY_CONNECTED), - ('a', UNBREAKABLE), - (':', UNBREAKABLE), - ('23', UNBREAKABLE), + ('lambda', VERY_STRONGLY_CONNECTED), + ('a', VERY_STRONGLY_CONNECTED), + (':', VERY_STRONGLY_CONNECTED), + ('23', VERY_STRONGLY_CONNECTED), (')', VERY_STRONGLY_CONNECTED), (':', STRONGLY_CONNECTED), ('37', None), From 37afb7f5f64d61e93a15545201997cf98b68ff5c Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 28 Nov 2018 01:04:08 -0800 Subject: [PATCH 327/719] Bump up penalty for splitting around a dot. --- CHANGELOG | 1 + yapf/yapflib/format_decision_state.py | 4 ++-- yapf/yapflib/split_penalty.py | 4 ++-- yapftests/reformatter_buganizer_test.py | 16 ++++++++++++++++ yapftests/split_penalty_test.py | 6 +++--- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0ba60d0b1..9423591f2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,7 @@ bracket. - Don't completely deny a lambda formatting if it goes over the column limit. Split only if absolutely necessary. +- Bump up penalty for splitting before a dot ('.'). ## [0.25.0] 2018-11-25 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index beac62053..86dfd3926 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -339,8 +339,8 @@ def SurroundedByParens(token): ########################################################################### # Argument List Splitting if (style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and not current.is_comment and - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in current - .subtypes): + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in + current.subtypes): if (previous.value not in {'=', ':', '*', '**'} and current.value not in ':=,)' and not _IsFunctionDefinition(previous)): # If we're going to split the lines because of named arguments, then we diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 6eee4bfd3..457e1f482 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -196,9 +196,9 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name if node.children[0].value == '.': before = style.Get('SPLIT_BEFORE_DOT') _SetSplitPenalty(node.children[0], - STRONGLY_CONNECTED if before else DOTTED_NAME) + VERY_STRONGLY_CONNECTED if before else DOTTED_NAME) _SetSplitPenalty(node.children[1], - DOTTED_NAME if before else STRONGLY_CONNECTED) + DOTTED_NAME if before else VERY_STRONGLY_CONNECTED) elif len(node.children) == 2: # Don't split an empty argument list if at all possible. _SetSplitPenalty(node.children[1], VERY_STRONGLY_CONNECTED) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index ddfc3e723..1780e4b87 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,22 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB117841880(self): + code = """\ +def xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( + aaaaaaaaaaaaaaaaaaa: AnyStr, + bbbbbbbbbbbb: Optional[Sequence[AnyStr]] = None, + cccccccccc: AnyStr = cst.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD, + dddddddddd: Sequence[SliceDimension] = (), + eeeeeeeeeeee: AnyStr = cst.DEFAULT_CONTROL_NAME, + ffffffffffffffffffff: Optional[ + Callable[[pd.DataFrame], pd.DataFrame]] = None, + gggggggggggggg: ooooooooooooo = ooooooooooooo()) -> pd.DataFrame: + pass +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB111764402(self): unformatted_code = """\ x = self.stubs.stub(video_classification_map, 'read_video_classifications', (lambda external_ids, **unused_kwargs: {external_id: self._get_serving_classification('video') for external_id in external_ids})) diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index 881b639a3..efcebfb22 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -205,7 +205,7 @@ def testStronglyConnected(self): ('foo', STRONGLY_CONNECTED), ('if', 0), ('a', STRONGLY_CONNECTED), - ('.', STRONGLY_CONNECTED), + ('.', VERY_STRONGLY_CONNECTED), ('x', DOTTED_NAME), ('==', STRONGLY_CONNECTED), ('37', STRONGLY_CONNECTED), @@ -231,9 +231,9 @@ def testFuncCalls(self): tree = self._ParseAndComputePenalties(code) self._CheckPenalties(tree, [ ('foo', None), - ('.', STRONGLY_CONNECTED), + ('.', VERY_STRONGLY_CONNECTED), ('bar', DOTTED_NAME), - ('.', STRONGLY_CONNECTED), + ('.', VERY_STRONGLY_CONNECTED), ('baz', DOTTED_NAME), ('(', STRONGLY_CONNECTED), ('1', None), From 2a91f7a5a699383ebba31b3a66a7f4f110fd85cf Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 28 Nov 2018 16:28:58 -0800 Subject: [PATCH 328/719] Remove lint warnings. --- yapf/__init__.py | 1 + yapf/yapflib/file_resources.py | 22 ++++++++++++---------- yapf/yapflib/format_decision_state.py | 4 ++-- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 10a88858a..dfa15fbca 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -272,6 +272,7 @@ def _FormatFile(filename, print_diff=False, verify=False, verbose=False): + """Format an individual file.""" if verbose: print('Reformatting %s' % filename) if style_config is None and not no_local_style: diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 8317cfc59..6de0b292d 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -33,12 +33,14 @@ def _GetExcludePatternsFromFile(filename): + """Get a list of file patterns to ignore.""" ignore_patterns = [] # See if we have a .yapfignore file. if os.path.isfile(filename) and os.access(filename, os.R_OK): - for line in open(filename, 'r').readlines(): - if line.strip() and not line.startswith('#'): - ignore_patterns.append(line.strip()) + with open(filename, 'r') as fd: + for line in fd: + if line.strip() and not line.startswith('#'): + ignore_patterns.append(line.strip()) if any(e.startswith('./') for e in ignore_patterns): raise errors.YapfError('path in .yapfignore should not start with ./') @@ -49,15 +51,15 @@ def _GetExcludePatternsFromFile(filename): def GetExcludePatternsForDir(dirname): """Return patterns of files to exclude from ignorefile in a given directory. - Looks for .yapfignore in the directory dirname. + Looks for .yapfignore in the directory dirname. - Arguments: - dirname: (unicode) The name of the directory. + Arguments: + dirname: (unicode) The name of the directory. - Returns: - A List of file patterns to exclude if ignore file is found - , otherwhise empty List. - """ + Returns: + A List of file patterns to exclude if ignore file is found, otherwise empty + List. + """ ignore_file = os.path.join(dirname, '.yapfignore') return _GetExcludePatternsFromFile(ignore_file) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 86dfd3926..b08235e3c 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -837,8 +837,8 @@ def ImplicitStringConcatenation(tok): else: current = current.next_token - # At this point, current is the closing bracket. Go back one to get the the - # end of the dictionary entry. + # At this point, current is the closing bracket. Go back one to get the end + # of the dictionary entry. current = PreviousNonCommentToken(current) length = current.total_length - entry_start.total_length length += len(entry_start.value) From d72f2801027d3e0e104b07ca53c8d262bf299cb4 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 29 Nov 2018 08:42:58 -0800 Subject: [PATCH 329/719] Updated description to include examples --- README.rst | 32 +++++++++++++++++++++++++++++++- yapf/yapflib/style.py | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 703ea1fc2..493b4eddc 100644 --- a/README.rst +++ b/README.rst @@ -488,7 +488,37 @@ Knobs before each trailing comment) or list of of values (representing alignment column values; trailing comments within a block will be aligned to the first column value that is greater than the maximum - line length within the block). + line length within the block). For example: + + With spaces_before_comment=5: + + 1 + 1 # Adding values + + will be formatted as: + + 1 + 1 # Adding values <-- 5 spaces between the end of the statement and comment + + With spaces_before_comment=15, 20: + + 1 + 1 # Adding values + two + two # More adding + + longer_statement # This is a longer statement + short # This is a shorter statement + + a_very_long_statement_that_extends_beyond_the_final_column # Comment + short # This is a shorter statement + + will be formatted as: + + 1 + 1 # Adding values <-- end of line comments in block aligned to col 15 + two + two # More adding + + longer_statement # This is a longer statement <-- end of line comments in block aligned to col 20 + short # This is a shorter statement + + a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length + short # This is a shorter statement ``SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET`` Insert a space between the ending comma and closing bracket of a list, etc. diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index c57f2ceb7..0fe598274 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -181,7 +181,39 @@ def method(): before each trailing comment) or list of of values (representing alignment column values; trailing comments within a block will be aligned to the first column value that is greater than the maximum - line length within the block)."""), + line length within the block). For example: + + With spaces_before_comment=5: + + 1 + 1 # Adding values + + will be formatted as: + + 1 + 1 # Adding values <-- 5 spaces between the end of the statement and comment + + With spaces_before_comment=15, 20: + + 1 + 1 # Adding values + two + two # More adding + + longer_statement # This is a longer statement + short # This is a shorter statement + + a_very_long_statement_that_extends_beyond_the_final_column # Comment + short # This is a shorter statement + + will be formatted as: + + 1 + 1 # Adding values <-- end of line comments in block aligned to col 15 + two + two # More adding + + longer_statement # This is a longer statement <-- end of line comments in block aligned to col 20 + short # This is a shorter statement + + a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length + short # This is a shorter statement + + """), SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=textwrap.dedent("""\ Split before arguments if the argument list is terminated by a comma."""), From bcfbb3af9f60f3d6a4b649bc6ced8d0185874dfb Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 29 Nov 2018 08:50:09 -0800 Subject: [PATCH 330/719] Wrapping some if statements in parens to help line-splitting algorithm --- yapf/yapflib/reformatter.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index e6f155585..06505864e 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -257,8 +257,8 @@ def _AlignTrailingComments(final_lines): processed_content = False for tok in line.tokens: - if tok.is_comment and isinstance(tok.spaces_required_before, - list) and tok.value.startswith('#'): + if (tok.is_comment and isinstance(tok.spaces_required_before, list) and + tok.value.startswith('#')): # All trailing comments and comments that appear on a line by themselves in this block # should be indented at the same level. The block is terminated by an empty line or EOF. # Enumerate through each line in the block and calculate the max line length. Once complete, @@ -277,8 +277,9 @@ def _AlignTrailingComments(final_lines): # Blank line - note that content is preformatted so we don't need to worry # about spaces/tabs; a blank line will always be '\n\n'. assert this_line.tokens - if all_pc_line_lengths and this_line.tokens[ - 0].formatted_whitespace_prefix.startswith('\n\n'): + if (all_pc_line_lengths and + this_line.tokens[0].formatted_whitespace_prefix.startswith('\n\n') + ): break # Calculate the length of each line in this unwrapped line. From 80084107c3b03ce4c1b0e94960b57e27a8bf8057 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 29 Nov 2018 08:58:53 -0800 Subject: [PATCH 331/719] Limiting comments and lines to column value of 80 --- yapf/yapflib/reformatter.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 06505864e..642008748 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -259,11 +259,12 @@ def _AlignTrailingComments(final_lines): for tok in line.tokens: if (tok.is_comment and isinstance(tok.spaces_required_before, list) and tok.value.startswith('#')): - # All trailing comments and comments that appear on a line by themselves in this block - # should be indented at the same level. The block is terminated by an empty line or EOF. - # Enumerate through each line in the block and calculate the max line length. Once complete, - # use the first col value greater than that value and create the necessary for each line - # accordingly. + # All trailing comments and comments that appear on a line by themselves + # in this block should be indented at the same level. The block is + # terminated by an empty line or EOF. Enumerate through each line in + # the block and calculate the max line length. Once complete, use the + # first col value greater than that value and create the necessary for + # each line accordingly. all_pc_line_lengths = [] # All pre-comment line lengths max_line_length = 0 @@ -274,8 +275,8 @@ def _AlignTrailingComments(final_lines): this_line = final_lines[final_lines_index + len(all_pc_line_lengths)] - # Blank line - note that content is preformatted so we don't need to worry - # about spaces/tabs; a blank line will always be '\n\n'. + # Blank line - note that content is preformatted so we don't need to + # worry about spaces/tabs; a blank line will always be '\n\n'. assert this_line.tokens if (all_pc_line_lengths and this_line.tokens[0].formatted_whitespace_prefix.startswith('\n\n') @@ -352,8 +353,8 @@ def _AlignTrailingComments(final_lines): # Account for initial whitespace already slated for the # beginning of the line. - existing_whitespace_prefix = line_tok.formatted_whitespace_prefix.lstrip( - '\n') + existing_whitespace_prefix = \ + line_tok.formatted_whitespace_prefix.lstrip('\n') if line_content.startswith(existing_whitespace_prefix): line_content = line_content[len(existing_whitespace_prefix):] From fd711ab4e4b06a8d0dab96311380983486851d32 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Fri, 30 Nov 2018 19:57:15 -0800 Subject: [PATCH 332/719] Support for disabled lines --- yapf/yapflib/reformatter.py | 4 ++++ yapftests/yapf_test.py | 42 +++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 642008748..23c40ddfd 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -283,6 +283,10 @@ def _AlignTrailingComments(final_lines): ): break + if this_line.disable: + all_pc_line_lengths.append([]) + continue + # Calculate the length of each line in this unwrapped line. line_content = '' pc_line_lengths = [] diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 7769feb51..24a1adc06 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1677,6 +1677,48 @@ def MyFunc( """) self._Check(unformatted_code, expected_formatted_code) + def testDisableBlock(self): + unformatted_code = textwrap.dedent("""\ + a() # comment 1 + b() # comment 2 + + # yapf: disable + c() # comment 3 + d() # comment 4 + # yapf: enable + + e() # comment 5 + f() # comment 6 + """) + expected_formatted_code = textwrap.dedent("""\ + a() # comment 1 + b() # comment 2 + + # yapf: disable + c() # comment 3 + d() # comment 4 + # yapf: enable + + e() # comment 5 + f() # comment 6 + """) + self._Check(unformatted_code, expected_formatted_code) + + def testDisabledLine(self): + unformatted_code = textwrap.dedent("""\ + short # comment 1 + do_not_touch1 # yapf: disable + do_not_touch2 # yapf: disable + a_longer_statement # comment 2 + """) + expected_formatted_code = textwrap.dedent("""\ + short # comment 1 + do_not_touch1 # yapf: disable + do_not_touch2 # yapf: disable + a_longer_statement # comment 2 + """) + self._Check(unformatted_code, expected_formatted_code) + if __name__ == '__main__': unittest.main() From 484828cd236ab4d7476d9a5c42bc2452f74db9b7 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sun, 2 Dec 2018 10:03:24 -0800 Subject: [PATCH 333/719] Updated CHANGELOG to include SPACES_BEFORE_COMMENT modification --- CHANGELOG | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 9423591f2..7e41048cd 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,11 @@ # This project adheres to [Semantic Versioning](http://semver.org/). ## [0.25.1] UNRELEASED +### Changed +- `SPACES_BEFORE_COMMENT` can now be assigned to a specific value (standard + behavior) or a list of column values. When assigned to a list, trailing + comments will be horizontally aligned to the first column value within + the list that is greater than the maximum line length in the block. ### Fixed - When retrieving the opening bracket make sure that it's actually an opening bracket. From 1625914a17ad6d6f685439bab92ac257cb0145ef Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 4 Dec 2018 16:35:24 -0800 Subject: [PATCH 334/719] Increase penalty for splitting before subscript This also ignores pseudo tokens when calculating split penalties. --- CHANGELOG | 2 ++ yapf/yapflib/split_penalty.py | 14 +++++++++++++- yapftests/reformatter_buganizer_test.py | 18 ++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 7e41048cd..aaae378fd 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,8 @@ - Don't completely deny a lambda formatting if it goes over the column limit. Split only if absolutely necessary. - Bump up penalty for splitting before a dot ('.'). +- Ignore pseudo tokens when calculating split penalties. +- Increase the penalty for splitting before the first bit of a subscript. ## [0.25.0] 2018-11-25 ### Added diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 457e1f482..9279a36f1 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -65,6 +65,10 @@ class _SplitPenaltyAssigner(pytree_visitor.PyTreeVisitor): Split penalties are attached as annotations to tokens. """ + def Visit(self, node): + if not hasattr(node, 'is_pseudo'): # Ignore pseudo tokens. + super(_SplitPenaltyAssigner, self).Visit(node) + def Visit_import_as_names(self, node): # pyline: disable=invalid-name # import_as_names ::= import_as_name (',' import_as_name)* [','] self.DefaultNodeVisit(node) @@ -244,6 +248,13 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name pytree_utils.FirstLeafNode(node), pytree_utils.Annotation.SUBTYPE) if subtypes and format_token.Subtype.SUBSCRIPT_BRACKET in subtypes: _IncreasePenalty(node, SUBSCRIPT) + + # Bump up the split penalty for the first part of a subscript. We + # would rather not split there. + first_leaf = pytree_utils.FirstLeafNode(node.children[1]) + penalty = pytree_utils.GetNodeAnnotation( + first_leaf, pytree_utils.Annotation.SPLIT_PENALTY, default=0) + _SetSplitPenalty(first_leaf, penalty + CONNECTED) else: _SetStronglyConnected(node.children[1], node.children[2]) @@ -472,7 +483,8 @@ def Visit_atom(self, node): # pylint: disable=invalid-name # '[' [listmaker] ']' | # '{' [dictsetmaker] '}') self.DefaultNodeVisit(node) - if node.children[0].value == '(': + if (node.children[0].value == '(' and + not hasattr(node.children[0], 'is_pseudo')): if node.children[-1].value == ')': if pytree_utils.NodeName(node.parent) == 'if_stmt': _SetSplitPenalty(node.children[-1], STRONGLY_CONNECTED) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 1780e4b87..558661b7d 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,24 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB120245013(self): + unformatted_code = """\ +class Foo(object): + def testNoAlertForShortPeriod(self, rutabaga): + self.targets[:][streamz_path,self._fillInOtherFields(streamz_path, {streamz_field_of_interest:True})] = series.Counter('1s', '+ 500x10000') +""" + expected_formatted_code = """\ +class Foo(object): + + def testNoAlertForShortPeriod(self, rutabaga): + self.targets[:][streamz_path, + self._fillInOtherFields( + streamz_path, {streamz_field_of_interest: True} + )] = series.Counter('1s', '+ 500x10000') +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB117841880(self): code = """\ def xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( From 3a6c0ec36e4c7653fc4c22584b594546de56e4f5 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 4 Dec 2018 17:27:59 -0800 Subject: [PATCH 335/719] Don't enforce dict split if it's a container A container split over multiple lines doesn't necessarily indicate that all dictionary values should be split. Check more closely for that situation. --- CHANGELOG | 4 ++++ yapf/yapflib/format_decision_state.py | 26 +++++++++++++++++++++---- yapftests/reformatter_buganizer_test.py | 24 +++++++++++++++++++++++ 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index aaae378fd..3ac66a236 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,10 @@ - Bump up penalty for splitting before a dot ('.'). - Ignore pseudo tokens when calculating split penalties. - Increase the penalty for splitting before the first bit of a subscript. +- Improve splitting before dictionary values. Look more closely to see if the + dictionary entry is a container. If so, then it's probably split over + multiple lines with the opening bracket on the same line as the key. + Therefore, we shouldn't enforce a split because of that. ## [0.25.0] 2018-11-25 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 27ff540f7..8dd5e55c4 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -810,6 +810,21 @@ def ImplicitStringConcatenation(tok): tok = tok.next_token return num_strings > 1 + def DictValueIsContainer(opening, closing): + if not opening or not closing: + return False + colon = opening.previous_token + while colon: + if not colon.is_pseudo_paren: + break + colon = colon.previous_token + if not colon or colon.value != ':': + return False + key = colon.previous_token + if not key: + return False + return format_token.Subtype.DICTIONARY_KEY_PART in key.subtypes + closing = opening.matching_bracket entry_start = opening.next_token current = opening.next_token.next_token @@ -817,10 +832,13 @@ def ImplicitStringConcatenation(tok): while current and current != closing: if format_token.Subtype.DICTIONARY_KEY in current.subtypes: prev = PreviousNonCommentToken(current) - length = prev.total_length - entry_start.total_length - length += len(entry_start.value) - if length + self.stack[-2].indent >= self.column_limit: - return False + if prev.value == ',': + prev = PreviousNonCommentToken(prev.previous_token) + if not DictValueIsContainer(prev.matching_bracket, prev): + length = prev.total_length - entry_start.total_length + length += len(entry_start.value) + if length + self.stack[-2].indent >= self.column_limit: + return False entry_start = current if current.OpensScope(): if ((current.value == '{' or diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 558661b7d..2c47ce7bf 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,30 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB120047670(self): + unformatted_code = """\ +X = { + 'NO_PING_COMPONENTS': [ + 79775, # Releases / FOO API + 79770, # Releases / BAZ API + 79780], # Releases / MUX API + + 'PING_BLOCKED_BUGS': False, +} +""" + expected_formatted_code = """\ +X = { + 'NO_PING_COMPONENTS': [ + 79775, # Releases / FOO API + 79770, # Releases / BAZ API + 79780 + ], # Releases / MUX API + 'PING_BLOCKED_BUGS': False, +} +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB120245013(self): unformatted_code = """\ class Foo(object): From e26c7ed85dbea866501a6ed978295bdab3863544 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 4 Dec 2018 19:14:10 -0800 Subject: [PATCH 336/719] Exclude "pylint: disable=line-too-long" lines If a line is marked as being "too long", then don't modify its veritical spacing. --- CHANGELOG | 2 ++ yapf/yapflib/reformatter.py | 19 +++++++++++++++++-- yapftests/reformatter_buganizer_test.py | 12 ++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 3ac66a236..67ebfa9aa 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,8 @@ behavior) or a list of column values. When assigned to a list, trailing comments will be horizontally aligned to the first column value within the list that is greater than the maximum line length in the block. +- Don't modify the vertical spacing of a line that has a comment "pylint: + disable=line-too-long". The line is expected to be too long. ### Fixed - When retrieving the opening bracket make sure that it's actually an opening bracket. diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 23c40ddfd..922c6c4ac 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -73,16 +73,23 @@ def Reformat(uwlines, verify=False, lines=None): if any(tok.is_comment for tok in uwline.tokens): _RetainVerticalSpacingBeforeComments(uwline) - if (_LineContainsI18n(uwline) or uwline.disable or - _LineHasContinuationMarkers(uwline)): + if uwline.disable or _LineHasContinuationMarkers(uwline): _RetainHorizontalSpacing(uwline) _RetainRequiredVerticalSpacing(uwline, prev_uwline, lines) _EmitLineUnformatted(state) + + elif (_LineContainsPylintDisableLineTooLong(uwline) or + _LineContainsI18n(uwline)): + # Don't modify vertical spacing, but fix any horizontal spacing issues. + _RetainRequiredVerticalSpacing(uwline, prev_uwline, lines) + _EmitLineUnformatted(state) + elif _CanPlaceOnSingleLine(uwline) and not any(tok.must_split for tok in uwline.tokens): # The unwrapped line fits on one line. while state.next_token: state.AddTokenToState(newline=False, dry_run=False) + else: if not _AnalyzeSolutionSpace(state): # Failsafe mode. If there isn't a solution to the line, then just emit @@ -222,6 +229,14 @@ def _LineContainsI18n(uwline): return False +def _LineContainsPylintDisableLineTooLong(uwline): + """Return true if there is a "pylint: disable=line-too-long" comment.""" + return any( + re.search(r'\bpylint:\s+disable=line-too-long\b', tok.value) + for tok in uwline.tokens + if tok.is_comment) + + def _LineHasContinuationMarkers(uwline): """Return true if the line has continuation markers in it.""" return any(tok.is_continuation for tok in uwline.tokens) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 2c47ce7bf..569c677ee 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,18 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB35417079(self): + code = """\ +class _(): + + def _(): + X = ( + _ares_label_prefix + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') # pylint: disable=line-too-long +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB120047670(self): unformatted_code = """\ X = { From 2eaff1738bdae04e3b1cffed3fabee0b17743961 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 4 Dec 2018 19:40:12 -0800 Subject: [PATCH 337/719] Add option to allow splitting before named assigns --- CHANGELOG | 5 ++++- README.rst | 3 +++ yapf/yapflib/style.py | 6 ++++++ yapf/yapflib/unwrapped_line.py | 4 ++++ yapftests/reformatter_buganizer_test.py | 13 +++++++++++++ 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 67ebfa9aa..d72274f8b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.25.1] UNRELEASED +## [0.26.0] UNRELEASED +### Added +- `ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS` allows us to split before + default / named assignments. ### Changed - `SPACES_BEFORE_COMMENT` can now be assigned to a specific value (standard behavior) or a list of column values. When assigned to a list, trailing diff --git a/README.rst b/README.rst index 493b4eddc..ade8ffc7a 100644 --- a/README.rst +++ b/README.rst @@ -327,6 +327,9 @@ Knobs value, } +``ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS`` + Allow splitting before a default / named assignment in an argument list. + ``ALLOW_SPLIT_BEFORE_DICT_VALUE`` Allow splits before the dictionary value. diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 0fe598274..627b95b34 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -59,6 +59,9 @@ def SetGlobalStyle(style): 'this is the second element of a tuple'): value, }"""), + ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=textwrap.dedent("""\ + Allow splitting before a default / named assignment in an argument list. + """), ALLOW_SPLIT_BEFORE_DICT_VALUE=textwrap.dedent("""\ Allow splits before the dictionary value."""), BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=textwrap.dedent("""\ @@ -314,6 +317,7 @@ def CreatePEP8Style(): ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=True, ALLOW_MULTILINE_LAMBDAS=False, ALLOW_MULTILINE_DICTIONARY_KEYS=False, + ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=True, ALLOW_SPLIT_BEFORE_DICT_VALUE=True, BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=False, BLANK_LINE_BEFORE_CLASS_DOCSTRING=False, @@ -381,6 +385,7 @@ def CreateGoogleStyle(): def CreateChromiumStyle(): style = CreateGoogleStyle() style['ALLOW_MULTILINE_DICTIONARY_KEYS'] = True + style['ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS'] = False style['INDENT_DICTIONARY_VALUE'] = True style['INDENT_WIDTH'] = 2 style['JOIN_MULTIPLE_LINES'] = False @@ -482,6 +487,7 @@ def _IntOrIntListConverter(s): ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=_BoolConverter, ALLOW_MULTILINE_LAMBDAS=_BoolConverter, ALLOW_MULTILINE_DICTIONARY_KEYS=_BoolConverter, + ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=_BoolConverter, ALLOW_SPLIT_BEFORE_DICT_VALUE=_BoolConverter, BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=_BoolConverter, BLANK_LINE_BEFORE_CLASS_DOCSTRING=_BoolConverter, diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index f37f3e48e..a27007dd5 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -436,6 +436,10 @@ def _CanBreakBefore(prev_token, cur_token): if format_token.Subtype.UNARY_OPERATOR in prev_token.subtypes: # Don't break after a unary token. return False + if not style.Get('ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS'): + if (format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in cur_token.subtypes or + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in prev_token.subtypes): + return False return True diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 569c677ee..8f353d8e6 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,19 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB118624921(self): + code = """\ +def _(): + function_call( + alert_name='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', + time_delta='1h', + alert_level='bbbbbbbb', + metric='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + bork=foo) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB35417079(self): code = """\ class _(): From fdeb4ba8decc812c9cd3bd44600e2cd38c33986c Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 4 Dec 2018 20:56:38 -0800 Subject: [PATCH 338/719] Fix lint errors --- yapf/yapflib/unwrapped_line.py | 9 +++++---- yapftests/file_resources_test.py | 20 ++++++++++---------- yapftests/yapf_test.py | 8 ++++---- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index a27007dd5..44bdc3145 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -79,10 +79,11 @@ def CalculateFormattingInformation(self): assert token.is_comment, token # If here, we are looking at a comment token that appears on a line - # with other tokens (but because it is a comment, it is always the last token). - # Rather than specifying the actual number of spaces here, hard code a value of - # 0 and then set it later. This logic only works because this comment token is - # guaranteed to be the last token in the list. + # with other tokens (but because it is a comment, it is always the last + # token). Rather than specifying the actual number of spaces here, + # hard code a value of 0 and then set it later. This logic only works + # because this comment token is guaranteed to be the last token in the + # list. spaces_required_before = 0 token.total_length = prev_length + tok_len + spaces_required_before diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 838eaf533..eaf4b8be3 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -38,10 +38,10 @@ def _restore_working_dir(): class GetExcludePatternsForDir(unittest.TestCase): - def setUp(self): + def setUp(self): # pylint: disable=g-missing-super-call self.test_tmpdir = tempfile.mkdtemp() - def tearDown(self): + def tearDown(self): # pylint: disable=g-missing-super-call shutil.rmtree(self.test_tmpdir) def _make_test_dir(self, name): @@ -62,10 +62,10 @@ def test_get_exclude_file_patterns(self): class GetDefaultStyleForDirTest(unittest.TestCase): - def setUp(self): + def setUp(self): # pylint: disable=g-missing-super-call self.test_tmpdir = tempfile.mkdtemp() - def tearDown(self): + def tearDown(self): # pylint: disable=g-missing-super-call shutil.rmtree(self.test_tmpdir) def test_no_local_style(self): @@ -100,11 +100,11 @@ def _touch_files(filenames): class GetCommandLineFilesTest(unittest.TestCase): - def setUp(self): + def setUp(self): # pylint: disable=g-missing-super-call self.test_tmpdir = tempfile.mkdtemp() self.old_dir = os.getcwd() - def tearDown(self): + def tearDown(self): # pylint: disable=g-missing-super-call shutil.rmtree(self.test_tmpdir) os.chdir(self.old_dir) @@ -285,10 +285,10 @@ def test_find_with_excluded_current_dir(self): class IsPythonFileTest(unittest.TestCase): - def setUp(self): + def setUp(self): # pylint: disable=g-missing-super-call self.test_tmpdir = tempfile.mkdtemp() - def tearDown(self): + def tearDown(self): # pylint: disable=g-missing-super-call shutil.rmtree(self.test_tmpdir) def test_with_py_extension(self): @@ -358,11 +358,11 @@ def buffer(self): class WriteReformattedCodeTest(unittest.TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls): # pylint: disable=g-missing-super-call cls.test_tmpdir = tempfile.mkdtemp() @classmethod - def tearDownClass(cls): + def tearDownClass(cls): # pylint: disable=g-missing-super-call shutil.rmtree(cls.test_tmpdir) def test_write_to_file(self): diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 24a1adc06..ca9c58f4d 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -67,10 +67,10 @@ def testPrintAfterPeriod(self): class FormatFileTest(unittest.TestCase): - def setUp(self): + def setUp(self): # pylint: disable=g-missing-super-call self.test_tmpdir = tempfile.mkdtemp() - def tearDown(self): + def tearDown(self): # pylint: disable=g-missing-super-call shutil.rmtree(self.test_tmpdir) def assertCodeEqual(self, expected_code, code): @@ -381,11 +381,11 @@ class CommandLineTest(unittest.TestCase): """Test how calling yapf from the command line acts.""" @classmethod - def setUpClass(cls): + def setUpClass(cls): # pylint: disable=g-missing-super-call cls.test_tmpdir = tempfile.mkdtemp() @classmethod - def tearDownClass(cls): + def tearDownClass(cls): # pylint: disable=g-missing-super-call shutil.rmtree(cls.test_tmpdir) def assertYapfReformats(self, From ba750ce1746ec0dac835041b8f37a161a147a224 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 4 Dec 2018 22:47:25 -0800 Subject: [PATCH 339/719] Remove lint errors. --- yapf/yapflib/reformatter.py | 4 ++-- yapf/yapflib/style.py | 2 +- yapftests/style_test.py | 20 ++++++++++---------- yapftests/yapf_test.py | 5 +---- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 922c6c4ac..b7c749106 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -319,7 +319,7 @@ def _AlignTrailingComments(final_lines): if line_tok.is_comment: pc_line_lengths.append(len(line_content)) else: - line_content += "{}{}".format(whitespace_prefix, line_tok.value) + line_content += '{}{}'.format(whitespace_prefix, line_tok.value) if pc_line_lengths: max_line_length = max(max_line_length, max(pc_line_lengths)) @@ -362,7 +362,7 @@ def _AlignTrailingComments(final_lines): for comment_line_index, comment_line in enumerate( line_tok.value.split('\n')): - line_content.append("{}{}".format(whitespace, + line_content.append('{}{}'.format(whitespace, comment_line.strip())) if comment_line_index == 0: diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 627b95b34..8345304b8 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -181,7 +181,7 @@ def method(): SPACES_BEFORE_COMMENT=textwrap.dedent("""\ The number of spaces required before a trailing comment. This can be a single value (representing the number of spaces - before each trailing comment) or list of of values (representing + before each trailing comment) or list of values (representing alignment column values; trailing comments within a block will be aligned to the first column value that is greater than the maximum line length within the block). For example: diff --git a/yapftests/style_test.py b/yapftests/style_test.py index f525a48ab..ff4643e67 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -54,13 +54,13 @@ def testBoolConverter(self): self.assertEqual(style._BoolConverter('0'), False) def testIntListConverter(self): - self.assertEqual(style._IntListConverter("1, 2, 3"), [1, 2, 3]) - self.assertEqual(style._IntListConverter("[ 1, 2, 3 ]"), [1, 2, 3]) - self.assertEqual(style._IntListConverter("[ 1, 2, 3, ]"), [1, 2, 3]) + self.assertEqual(style._IntListConverter('1, 2, 3'), [1, 2, 3]) + self.assertEqual(style._IntListConverter('[ 1, 2, 3 ]'), [1, 2, 3]) + self.assertEqual(style._IntListConverter('[ 1, 2, 3, ]'), [1, 2, 3]) def testIntOrIntListConverter(self): - self.assertEqual(style._IntOrIntListConverter("10"), 10) - self.assertEqual(style._IntOrIntListConverter("1, 2, 3"), [1, 2, 3]) + self.assertEqual(style._IntOrIntListConverter('10'), 10) + self.assertEqual(style._IntOrIntListConverter('1, 2, 3'), [1, 2, 3]) def _LooksLikeChromiumStyle(cfg): @@ -85,7 +85,7 @@ def _LooksLikeFacebookStyle(cfg): class PredefinedStylesByNameTest(unittest.TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls): # pylint: disable=g-missing-super-call style.SetGlobalStyle(style.CreatePEP8Style()) def testDefault(self): @@ -117,12 +117,12 @@ def testFacebookByName(self): class StyleFromFileTest(unittest.TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls): # pylint: disable=g-missing-super-call cls.test_tmpdir = tempfile.mkdtemp() style.SetGlobalStyle(style.CreatePEP8Style()) @classmethod - def tearDownClass(cls): + def tearDownClass(cls): # pylint: disable=g-missing-super-call shutil.rmtree(cls.test_tmpdir) def testDefaultBasedOnStyle(self): @@ -233,7 +233,7 @@ def testErrorUnknownStyleOption(self): class StyleFromDict(unittest.TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls): # pylint: disable=g-missing-super-call style.SetGlobalStyle(style.CreatePEP8Style()) def testDefaultBasedOnStyle(self): @@ -258,7 +258,7 @@ def testDefaultBasedOnStyleBadDict(self): class StyleFromCommandLine(unittest.TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls): # pylint: disable=g-missing-super-call style.SetGlobalStyle(style.CreatePEP8Style()) def testDefaultBasedOnStyle(self): diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index ca9c58f4d..fbf563737 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -229,7 +229,7 @@ def testFormatFileDiff(self): """) with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: diff, _, _ = yapf_api.FormatFile(filepath, print_diff=True) - self.assertTrue(u'+ pass' in diff) + self.assertIn(u'+ pass', diff) def testFormatFileInPlace(self): unformatted_code = u'True==False\n' @@ -1453,9 +1453,6 @@ def _Check(self, unformatted_code, expected_formatted_code): unformatted_code, style_config=style.SetGlobalStyle(self._OwnStyle())) self.assertEqual(expected_formatted_code, formatted_code) - def setUp(self): - self.maxDiff = None - def testSimple(self): unformatted_code = textwrap.dedent("""\ foo = '1' # Aligned at first list value From 85d7f2d792dcaca13c24a9d2fa6a8f7657747d0c Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 5 Dec 2018 03:44:47 -0800 Subject: [PATCH 340/719] Increase split penalty around exponent operator --- CHANGELOG | 1 + yapf/yapflib/split_penalty.py | 16 +++++++--------- yapf/yapflib/unwrapped_line.py | 4 +++- yapftests/reformatter_buganizer_test.py | 10 ++++++++++ 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d72274f8b..214f01364 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -25,6 +25,7 @@ dictionary entry is a container. If so, then it's probably split over multiple lines with the opening bracket on the same line as the key. Therefore, we shouldn't enforce a split because of that. +- Increase split penalty around exponent operator. ## [0.25.0] 2018-11-25 ### Added diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 9279a36f1..7d84d8a3d 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -144,12 +144,12 @@ def Visit_parameters(self, node): # pylint: disable=invalid-name def Visit_arglist(self, node): # pylint: disable=invalid-name # arglist ::= argument (',' argument)* [','] self.DefaultNodeVisit(node) - index = 1 - while index < len(node.children): + + for index in py3compat.range(1, len(node.children)): child = node.children[index] if isinstance(child, pytree.Leaf) and child.value == ',': _SetUnbreakable(child) - index += 1 + for child in node.children: if pytree_utils.NodeName(child) == 'atom': _IncreasePenalty(child, CONNECTED) @@ -157,28 +157,26 @@ def Visit_arglist(self, node): # pylint: disable=invalid-name def Visit_argument(self, node): # pylint: disable=invalid-name # argument ::= test [comp_for] | test '=' test # Really [keyword '='] test self.DefaultNodeVisit(node) - index = 1 - while index < len(node.children) - 1: + + for index in py3compat.range(1, len(node.children) - 1): child = node.children[index] if isinstance(child, pytree.Leaf) and child.value == '=': _SetSplitPenalty( pytree_utils.FirstLeafNode(node.children[index]), NAMED_ASSIGN) _SetSplitPenalty( pytree_utils.FirstLeafNode(node.children[index + 1]), NAMED_ASSIGN) - index += 1 def Visit_tname(self, node): # pylint: disable=invalid-name # tname ::= NAME [':' test] self.DefaultNodeVisit(node) - index = 1 - while index < len(node.children) - 1: + + for index in py3compat.range(1, len(node.children) - 1): child = node.children[index] if isinstance(child, pytree.Leaf) and child.value == ':': _SetSplitPenalty( pytree_utils.FirstLeafNode(node.children[index]), NAMED_ASSIGN) _SetSplitPenalty( pytree_utils.FirstLeafNode(node.children[index + 1]), NAMED_ASSIGN) - index += 1 def Visit_dotted_name(self, node): # pylint: disable=invalid-name # dotted_name ::= NAME ('.' NAME)* diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 44bdc3145..40f129571 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -528,7 +528,9 @@ def _SplitPenalty(prev_token, cur_token): return 0 if prev_token.is_binary_op: # We would rather not split after an equality operator. - return 20 + return split_penalty.CONNECTED + if pval == '**' or cval == '**': + return split_penalty.STRONGLY_CONNECTED if (format_token.Subtype.VARARGS_STAR in prev_token.subtypes or format_token.Subtype.KWARGS_STAR_STAR in prev_token.subtypes): # Don't split after a varargs * or kwargs **. diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 8f353d8e6..38e4437f1 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,16 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB73166511(self): + code = """\ +def _(): + if min_std is not None: + groundtruth_age_variances = tf.maximum(groundtruth_age_variances, + min_std**2) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB118624921(self): code = """\ def _(): From 314472d29c09ea10e4f83fa06dc16af78951725c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Furkan=C3=96zbek?= <45393818+MrNightcall@users.noreply.github.com> Date: Thu, 6 Dec 2018 11:19:12 +0100 Subject: [PATCH 341/719] grammar fix --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index ade8ffc7a..fe9a777f3 100644 --- a/README.rst +++ b/README.rst @@ -140,7 +140,7 @@ has been YAPF-formatted. Excluding files from formatting (.yapfignore) --------------------------------------------- -In addition to exlude patterns provided on commandline, YAPF looks for additional +In addition to exclude patterns provided on commandline, YAPF looks for additional patterns specified in a file named ``.yapfignore`` located in the working directory from which YAPF is invoked. From 79d87e2a1850bc2f225145a433823084f875bea5 Mon Sep 17 00:00:00 2001 From: Socheng Date: Wed, 2 Jan 2019 02:26:35 +0000 Subject: [PATCH 342/719] Fix SPACES_BEFORE_COMMENT code block The code in the section SPACES_BEFORE_COMMENT was using quote style rather than code block style, which has resulted in inconsistencies and several displaying problems. The code was meant to illustrate the number of spaces before a trailing comment, but quote style in Markdown does not implement it that way. This was corrected in the commit. --- README.rst | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/README.rst b/README.rst index fe9a777f3..2465ebca9 100644 --- a/README.rst +++ b/README.rst @@ -495,33 +495,41 @@ Knobs With spaces_before_comment=5: - 1 + 1 # Adding values + .. code-block:: python + + 1 + 1 # Adding values will be formatted as: - 1 + 1 # Adding values <-- 5 spaces between the end of the statement and comment + .. code-block:: python + + 1 + 1 # Adding values <-- 5 spaces between the end of the statement and comment With spaces_before_comment=15, 20: - 1 + 1 # Adding values - two + two # More adding + .. code-block:: python + + 1 + 1 # Adding values + two + two # More adding - longer_statement # This is a longer statement - short # This is a shorter statement + longer_statement # This is a longer statement + short # This is a shorter statement - a_very_long_statement_that_extends_beyond_the_final_column # Comment - short # This is a shorter statement + a_very_long_statement_that_extends_beyond_the_final_column # Comment + short # This is a shorter statement will be formatted as: - 1 + 1 # Adding values <-- end of line comments in block aligned to col 15 - two + two # More adding + .. code-block:: python + + 1 + 1 # Adding values <-- end of line comments in block aligned to col 15 + two + two # More adding - longer_statement # This is a longer statement <-- end of line comments in block aligned to col 20 - short # This is a shorter statement + longer_statement # This is a longer statement <-- end of line comments in block aligned to col 20 + short # This is a shorter statement - a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length - short # This is a shorter statement + a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length + short # This is a shorter statement ``SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET`` Insert a space between the ending comma and closing bracket of a list, etc. From 609de6f72015017018b6474c3cf8753b1f6a2d62 Mon Sep 17 00:00:00 2001 From: Mpho Mphego Date: Wed, 5 Dec 2018 14:23:47 +0200 Subject: [PATCH 343/719] Updated pre-commit shell script Updated shebang from `#!/bin/bash` to `#!/usr/bin/env bash` for portability(https://en.wikipedia.org/wiki/Shebang_%28Unix%29#Portability) related issues. Double quote to prevent globbing and word splitting. Using `command -v` instead of `which`: The reason to select the former over the latter is that it avoids a dependency on something that is outside your shell. Signed-off-by: Mpho Mphego --- plugins/pre-commit.sh | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-) mode change 100644 => 100755 plugins/pre-commit.sh diff --git a/plugins/pre-commit.sh b/plugins/pre-commit.sh old mode 100644 new mode 100755 index 896f0ffba..1552e9368 --- a/plugins/pre-commit.sh +++ b/plugins/pre-commit.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Git pre-commit hook to check staged Python files for formatting issues with # yapf. @@ -21,15 +21,14 @@ # is used. # Find all staged Python files, and exit early if there aren't any. -PYTHON_FILES=(`git diff --name-only --cached --diff-filter=AM | \ - grep --color=never '.py$'`) -if [ ! "$PYTHON_FILES" ]; then +PYTHON_FILES=$(git diff --name-only --cached --diff-filter=AM | grep --color=never '.py$') +if [ -z "${PYTHON_FILES}" ]; then exit 0 fi ########## PIP VERSION ############# # Verify that yapf is installed; if not, warn and exit. -if [ -z $(which yapf) ]; then +if ! command -v yapf >/dev/null; then echo 'yapf not on path; can not format. Please install yapf:' echo ' pip install yapf' exit 2 @@ -37,7 +36,7 @@ fi ######### END PIP VERSION ########## ########## PIPENV VERSION ########## -# if [ -z $(pipenv run which yapf) ]; then +# if ! pipenv run yapf --version 2>/dev/null 2>&1; then # echo 'yapf not on path; can not format. Please install yapf:' # echo ' pipenv install yapf' # exit 2 @@ -46,16 +45,12 @@ fi # Check for unstaged changes to files in the index. -CHANGED_FILES=(`git diff --name-only ${PYTHON_FILES[@]}`) -if [ "$CHANGED_FILES" ]; then +CHANGED_FILES=$(git diff --name-only "${PYTHON_FILES[@]}") +if [ -n "${CHANGED_FILES}" ]; then echo 'You have unstaged changes to some files in your commit; skipping ' echo 'auto-format. Please stage, stash, or revert these changes. You may ' echo 'find `git stash -k` helpful here.' - echo - echo 'Files with unstaged changes:' - for file in ${CHANGED_FILES[@]}; do - echo " $file" - done + echo 'Files with unstaged changes:' "${CHANGED_FILES[@]}" exit 1 fi @@ -64,22 +59,18 @@ fi echo 'Formatting staged Python files . . .' ########## PIP VERSION ############# -yapf -i -r ${PYTHON_FILES[@]} +yapf -i -r "${PYTHON_FILES[@]}" ######### END PIP VERSION ########## ########## PIPENV VERSION ########## -# pipenv run yapf -i -r ${PYTHON_FILES[@]} +# pipenv run yapf -i -r "${PYTHON_FILES[@]}" ###### END PIPENV VERSION ########## -CHANGED_FILES=(`git diff --name-only ${PYTHON_FILES[@]}`) -if [ "$CHANGED_FILES" ]; then +CHANGED_FILES=$(git diff --name-only "${PYTHON_FILES[@]}") +if [ -n "${CHANGED_FILES}" ]; then echo 'Reformatted staged files. Please review and stage the changes.' - echo - echo 'Files updated:' - for file in ${CHANGED_FILES[@]}; do - echo " $file" - done + echo 'Files updated: ' "${CHANGED_FILES[@]}" exit 1 else exit 0 From bc611e0f229ea0499b1c5e6f386633107d5b4523 Mon Sep 17 00:00:00 2001 From: Yinyin L Date: Sun, 20 Jan 2019 01:36:57 +0800 Subject: [PATCH 344/719] improve option parsing of `CONTINUATION_ALIGN_STYLE` accepts quoted or underline-separated option values for continuation valign style. fix: #616, #646 --- CHANGELOG | 2 ++ yapf/yapflib/style.py | 2 +- yapftests/style_test.py | 27 +++++++++++++++++++-------- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 214f01364..00f226f83 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,8 @@ the list that is greater than the maximum line length in the block. - Don't modify the vertical spacing of a line that has a comment "pylint: disable=line-too-long". The line is expected to be too long. +- improved `CONTINUATION_ALIGN_STYLE` to accept quoted or underline-separated + option value for passing option with command line arguments. ### Fixed - When retrieving the opening bracket make sure that it's actually an opening bracket. diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 8345304b8..f5a002a4d 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -437,7 +437,7 @@ def _ContinuationAlignStyleStringConverter(s): """Option value converter for a continuation align style string.""" accepted_styles = ('SPACE', 'FIXED', 'VALIGN-RIGHT') if s: - r = s.upper() + r = s.strip('"\'').replace('_', '-').upper() if r not in accepted_styles: raise ValueError('unknown continuation align style: %r' % (s,)) else: diff --git a/yapftests/style_test.py b/yapftests/style_test.py index ff4643e67..3d4e1b141 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -27,14 +27,25 @@ class UtilsTest(unittest.TestCase): def testContinuationAlignStyleStringConverter(self): - self.assertEqual(style._ContinuationAlignStyleStringConverter(''), 'SPACE') - self.assertEqual( - style._ContinuationAlignStyleStringConverter('space'), 'SPACE') - self.assertEqual( - style._ContinuationAlignStyleStringConverter('fixed'), 'FIXED') - self.assertEqual( - style._ContinuationAlignStyleStringConverter('valign-right'), - 'VALIGN-RIGHT') + for cont_align_space in ('', 'space', '"space"', '\'space\''): + self.assertEqual( + style._ContinuationAlignStyleStringConverter(cont_align_space), + 'SPACE') + for cont_align_fixed in ('fixed', '"fixed"', '\'fixed\''): + self.assertEqual( + style._ContinuationAlignStyleStringConverter(cont_align_fixed), + 'FIXED') + for cont_align_valignright in ( + 'valign-right', + '"valign-right"', + '\'valign-right\'', + 'valign_right', + '"valign_right"', + '\'valign_right\'', + ): + self.assertEqual( + style._ContinuationAlignStyleStringConverter(cont_align_valignright), + 'VALIGN-RIGHT') with self.assertRaises(ValueError) as ctx: style._ContinuationAlignStyleStringConverter('blahblah') self.assertIn("unknown continuation align style: 'blahblah'", From 57d4c02d5fd9f953eac3e73a7bb6badc4e44dbf3 Mon Sep 17 00:00:00 2001 From: Harald Husum Date: Thu, 7 Feb 2019 13:08:01 +0100 Subject: [PATCH 345/719] Arithmetic precedence indication Add an option to remove spaces around highest priority operations in complex arithmetic expressions. This is motivated by the PEP8 suggestion to to do this. --- README.rst | 23 ++++++ yapf/yapflib/style.py | 22 ++++++ yapf/yapflib/unwrapped_line.py | 86 +++++++++++++++++++++- yapftests/reformatter_style_config_test.py | 37 ++++++++++ 4 files changed, 167 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 2465ebca9..388ddaaf0 100644 --- a/README.rst +++ b/README.rst @@ -333,6 +333,29 @@ Knobs ``ALLOW_SPLIT_BEFORE_DICT_VALUE`` Allow splits before the dictionary value. +``ARITHMETIC_PRECEDENCE_INDICATION`` + Let spacing indicate operator precedence. For example: + + .. code-block:: python + + a = 1 * 2 + 3 / 4 + b = 1 / 2 - 3 * 4 + c = (1 + 2) * (3 - 4) + d = (1 - 2) / (3 + 4) + e = 1 * 2 - 3 + f = 1 + 2 + 3 + 4 + + will be formatted as follows to indicate precedence: + + .. code-block:: python + + a = 1*2 + 3/4 + b = 1/2 - 3*4 + c = (1+2) * (3-4) + d = (1-2) / (3+4) + e = 1*2 - 3 + f = 1 + 2 + 3 + 4 + ``BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF`` Insert a blank line before a ``def`` or ``class`` immediately nested within another ``def`` or ``class``. For example: diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 8345304b8..d7371350f 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -64,6 +64,26 @@ def SetGlobalStyle(style): """), ALLOW_SPLIT_BEFORE_DICT_VALUE=textwrap.dedent("""\ Allow splits before the dictionary value."""), + ARITHMETIC_PRECEDENCE_INDICATION=textwrap.dedent("""\ + Let spacing indicate operator precedence. For example: + + a = 1 * 2 + 3 / 4 + b = 1 / 2 - 3 * 4 + c = (1 + 2) * (3 - 4) + d = (1 - 2) / (3 + 4) + e = 1 * 2 - 3 + f = 1 + 2 + 3 + 4 + + will be formatted as follows to indicate precedence: + + a = 1*2 + 3/4 + b = 1/2 - 3*4 + c = (1+2) * (3-4) + d = (1-2) / (3+4) + e = 1*2 - 3 + f = 1 + 2 + 3 + 4 + + """), BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=textwrap.dedent("""\ Insert a blank line before a 'def' or 'class' immediately nested within another 'def' or 'class'. For example: @@ -319,6 +339,7 @@ def CreatePEP8Style(): ALLOW_MULTILINE_DICTIONARY_KEYS=False, ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=True, ALLOW_SPLIT_BEFORE_DICT_VALUE=True, + ARITHMETIC_PRECEDENCE_INDICATION=False, BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=False, BLANK_LINE_BEFORE_CLASS_DOCSTRING=False, BLANK_LINE_BEFORE_MODULE_DOCSTRING=False, @@ -489,6 +510,7 @@ def _IntOrIntListConverter(s): ALLOW_MULTILINE_DICTIONARY_KEYS=_BoolConverter, ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=_BoolConverter, ALLOW_SPLIT_BEFORE_DICT_VALUE=_BoolConverter, + ARITHMETIC_PRECEDENCE_INDICATION=_BoolConverter, BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=_BoolConverter, BLANK_LINE_BEFORE_CLASS_DOCSTRING=_BoolConverter, BLANK_LINE_BEFORE_MODULE_DOCSTRING=_BoolConverter, diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 40f129571..28da18ddb 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -227,6 +227,82 @@ def _IsUnaryOperator(tok): return format_token.Subtype.UNARY_OPERATOR in tok.subtypes +def _IsMOperator(leaf): + """ See definition of an m_expr un the python reference: + https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations + """ + return leaf.value in ["*", "@", "//", "%", "/"] + + +def _IsAOperator(leaf): + """ See definition of an a_expr un the python reference: + https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations + """ + return leaf.value in ["+", "-"] + + +def _IsBinaryArithmeticOperator(leaf): + return _IsMOperator(leaf) or _IsAOperator(leaf) + + +def _IsIndependentOperator(leaf): + """Tests whether the operator's operands are leaf nodes.""" + siblings = leaf.parent.children + return all(map(lambda s: len(s.children) == 0, siblings)) + + +def _HasPrecedence(tok): + """Determines whether a binary arithmetic operation has higher priority than + another operation in the same expression. + """ + node = tok.node + try: + # We let ancestor be the statement surrounding the operation that tok + # is the operator in. + ancestor = node.parent.parent + except AttributeError: + # If there is no such statement then the operator cannot have precedence + # over it. + return False + + while ancestor is not None: + # Search through the ancestor nodes in the parse tree for operators with + # lower precedence. + predecessor_type = pytree_utils.NodeName(ancestor) + if predecessor_type in ["arith_expr", "term"]: + # An ancestor "arith_expr" or "term" means we have found an operator + # with lower presedence than our tok. + return True + if predecessor_type != "atom": + # We understand the context to look for precedence within as an + # arbitrary nesting of "arith_expr", "term", and "atom" nodes. If we + # leave this context we have not found a lower presedence operator. + return False + if hasattr(ancestor, 'parent'): + ancestor = ancestor.parent + else: + ancestor = None + return False + + +def _PriorityIndicatingNoSpace(tok): + """Determines whether to indicate that an operator has highest presedence in + an arithmetic expression by removing spaces around it. + + This is motivated by the advice given for spacing around binary arithmetic + operators in PEP8: + + https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations + """ + if not _IsBinaryArithmeticOperator(tok.node): + # Limit space removal to arithmetic operators + return False + if not _IsIndependentOperator(tok.node): + # Limit space removal to highest priority operators + return False + return _HasPrecedence(tok) + + def _SpaceRequiredBetween(left, right): """Return True if a space is required between the left and right token.""" lval = left.value @@ -310,7 +386,15 @@ def _SpaceRequiredBetween(left, right): return style.Get('SPACES_AROUND_POWER_OPERATOR') # Enforce spaces around binary operators except the blacklisted ones. blacklist = style.Get('NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS') - return lval not in blacklist and rval not in blacklist + if lval in blacklist or rval in blacklist: + return False + if style.Get('ARITHMETIC_PRECEDENCE_INDICATION'): + if _PriorityIndicatingNoSpace(left) or _PriorityIndicatingNoSpace(right): + return False + else: + return True + else: + return True if (_IsUnaryOperator(left) and lval != 'not' and (right.is_name or right.is_number or rval == '(')): # The previous token was a unary op. No space is desired between it and diff --git a/yapftests/reformatter_style_config_test.py b/yapftests/reformatter_style_config_test.py index 5afd805b4..643ef00de 100644 --- a/yapftests/reformatter_style_config_test.py +++ b/yapftests/reformatter_style_config_test.py @@ -76,6 +76,43 @@ def testOperatorStyle(self): style.SetGlobalStyle(style.CreatePEP8Style()) style.DEFAULT_STYLE = self.current_style + def testOperatorPrecedenceStyle(self): + try: + pep8_with_precedence = style.CreatePEP8Style() + pep8_with_precedence['ARITHMETIC_PRECEDENCE_INDICATION'] = True + style.SetGlobalStyle(pep8_with_precedence) + unformatted_code = textwrap.dedent("""\ + a = 1 * 2 + 3 / 4 + b = 1 / 2 - 3 * 4 + c = (1 + 2) * (3 - 4) + d = (1 - 2) / (3 + 4) + e = 1 * 2 - 3 + f = 1 + 2 + 3 + 4 + g = 1 * 2 * 3 * 4 + h = 1 + 2 - 3 + 4 + i = 1 * 2 / 3 * 4 + j = (1 * 2 - 3) + 4 + """) + expected_formatted_code = textwrap.dedent("""\ + a = 1*2 + 3/4 + b = 1/2 - 3*4 + c = (1+2) * (3-4) + d = (1-2) / (3+4) + e = 1*2 - 3 + f = 1 + 2 + 3 + 4 + g = 1 * 2 * 3 * 4 + h = 1 + 2 - 3 + 4 + i = 1 * 2 / 3 * 4 + j = (1*2 - 3) + 4 + """) + + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreatePEP8Style()) + style.DEFAULT_STYLE = self.current_style + if __name__ == '__main__': unittest.main() From 1d8bcafa0ed0fb82dca96bc22d140b0569f0f7f9 Mon Sep 17 00:00:00 2001 From: Harald Husum Date: Thu, 7 Feb 2019 13:56:25 +0100 Subject: [PATCH 346/719] Increased coverage of test --- yapftests/reformatter_style_config_test.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/yapftests/reformatter_style_config_test.py b/yapftests/reformatter_style_config_test.py index 643ef00de..2388a3643 100644 --- a/yapftests/reformatter_style_config_test.py +++ b/yapftests/reformatter_style_config_test.py @@ -82,6 +82,8 @@ def testOperatorPrecedenceStyle(self): pep8_with_precedence['ARITHMETIC_PRECEDENCE_INDICATION'] = True style.SetGlobalStyle(pep8_with_precedence) unformatted_code = textwrap.dedent("""\ + 1+2 + (1 + 2) * (3 - (4 / 5)) a = 1 * 2 + 3 / 4 b = 1 / 2 - 3 * 4 c = (1 + 2) * (3 - 4) @@ -94,6 +96,8 @@ def testOperatorPrecedenceStyle(self): j = (1 * 2 - 3) + 4 """) expected_formatted_code = textwrap.dedent("""\ + 1 + 2 + (1+2) * (3 - (4/5)) a = 1*2 + 3/4 b = 1/2 - 3*4 c = (1+2) * (3-4) From 59511385ac0b45f49fd7b6d2abb5dbcab0833589 Mon Sep 17 00:00:00 2001 From: Harald Husum Date: Thu, 7 Feb 2019 14:10:01 +0100 Subject: [PATCH 347/719] Fixed typos in docstrings --- yapf/yapflib/unwrapped_line.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 28da18ddb..55c50a37d 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -228,14 +228,14 @@ def _IsUnaryOperator(tok): def _IsMOperator(leaf): - """ See definition of an m_expr un the python reference: + """ See definition of an m_expr in the python reference: https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations """ return leaf.value in ["*", "@", "//", "%", "/"] def _IsAOperator(leaf): - """ See definition of an a_expr un the python reference: + """ See definition of an a_expr in the python reference: https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations """ return leaf.value in ["+", "-"] From d0ccc900f1ef203f717fa2c465d871fe76c0d7b2 Mon Sep 17 00:00:00 2001 From: Harald Husum Date: Thu, 7 Feb 2019 14:29:49 +0100 Subject: [PATCH 348/719] Simplified code to increase coverage --- yapf/yapflib/unwrapped_line.py | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 55c50a37d..524977ce7 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -256,14 +256,10 @@ def _HasPrecedence(tok): another operation in the same expression. """ node = tok.node - try: - # We let ancestor be the statement surrounding the operation that tok - # is the operator in. - ancestor = node.parent.parent - except AttributeError: - # If there is no such statement then the operator cannot have precedence - # over it. - return False + + # We let ancestor be the statement surrounding the operation that tok + # is the operator in. + ancestor = node.parent.parent while ancestor is not None: # Search through the ancestor nodes in the parse tree for operators with @@ -278,11 +274,9 @@ def _HasPrecedence(tok): # arbitrary nesting of "arith_expr", "term", and "atom" nodes. If we # leave this context we have not found a lower presedence operator. return False - if hasattr(ancestor, 'parent'): - ancestor = ancestor.parent - else: - ancestor = None - return False + # Under normal usage we expect a complete parse tree to be available and + # we will return before we get an AttributeError from the root. + ancestor = ancestor.parent def _PriorityIndicatingNoSpace(tok): From 81ffb909fb0ad11fd7bdc7fcfab999d7309dbc2e Mon Sep 17 00:00:00 2001 From: Harald Husum Date: Fri, 8 Feb 2019 11:15:17 +0100 Subject: [PATCH 349/719] Update CHANGELOG Updated CHANGELOG with reference to the addition of new option: ARITHMETIC_PRECEDENCE_INDICATION --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 214f01364..d5e24066b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,8 @@ ### Added - `ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS` allows us to split before default / named assignments. +- `ARITHMETIC_PRECEDENCE_INDICATION` removes spacing around binary operators + if they have higher precedence than other operators in the same expression. ### Changed - `SPACES_BEFORE_COMMENT` can now be assigned to a specific value (standard behavior) or a list of column values. When assigned to a list, trailing From bc1c4ee89d48b6da1c96fa5543009ed5d8be10f5 Mon Sep 17 00:00:00 2001 From: Harald Husum Date: Fri, 8 Feb 2019 11:22:52 +0100 Subject: [PATCH 350/719] Shorten docstrings --- yapf/yapflib/unwrapped_line.py | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 524977ce7..63f5ad428 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -231,14 +231,14 @@ def _IsMOperator(leaf): """ See definition of an m_expr in the python reference: https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations """ - return leaf.value in ["*", "@", "//", "%", "/"] + return leaf.value in ['*', '@', '//', '%', '/'] def _IsAOperator(leaf): """ See definition of an a_expr in the python reference: https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations """ - return leaf.value in ["+", "-"] + return leaf.value in ['+', '-'] def _IsBinaryArithmeticOperator(leaf): @@ -252,13 +252,11 @@ def _IsIndependentOperator(leaf): def _HasPrecedence(tok): - """Determines whether a binary arithmetic operation has higher priority than - another operation in the same expression. - """ + """Whether a binary operation has presedence within its context.""" node = tok.node - # We let ancestor be the statement surrounding the operation that tok - # is the operator in. + # We let ancestor be the statement surrounding the operation that tok is the + # operator in. ancestor = node.parent.parent while ancestor is not None: @@ -280,14 +278,7 @@ def _HasPrecedence(tok): def _PriorityIndicatingNoSpace(tok): - """Determines whether to indicate that an operator has highest presedence in - an arithmetic expression by removing spaces around it. - - This is motivated by the advice given for spacing around binary arithmetic - operators in PEP8: - - https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations - """ + """Whether to remove spaces around an operator due to presedence.""" if not _IsBinaryArithmeticOperator(tok.node): # Limit space removal to arithmetic operators return False From b779e34b4411dac80818268369e803a4c0bfb926 Mon Sep 17 00:00:00 2001 From: Harald Husum Date: Fri, 8 Feb 2019 11:45:03 +0100 Subject: [PATCH 351/719] Move logic for detecting arithmetic operators --- yapf/yapflib/format_token.py | 8 ++++++++ yapf/yapflib/subtype_assigner.py | 2 ++ yapf/yapflib/unwrapped_line.py | 20 +------------------- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 9b428b3c5..54a6c794a 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -36,6 +36,8 @@ class Subtype(object): NONE = 0 UNARY_OPERATOR = 1 BINARY_OPERATOR = 2 + A_EXPR_OPERATOR = 22 + M_EXPR_OPERATOR = 23 SUBSCRIPT_COLON = 3 SUBSCRIPT_BRACKET = 4 DEFAULT_OR_NAMED_ASSIGN = 5 @@ -280,6 +282,12 @@ def is_binary_op(self): """Token is a binary operator.""" return Subtype.BINARY_OPERATOR in self.subtypes + @property + @py3compat.lru_cache() + def is_arithmetic_op(self): + """Token is an arithmetic operator.""" + return Subtype.A_EXPR_OPERATOR in self.subtypes or Subtype.M_EXPR_OPERATOR in self.subtypes + @property @py3compat.lru_cache() def name(self): diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index beb805243..d4d865444 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -189,6 +189,7 @@ def Visit_arith_expr(self, node): # pylint: disable=invalid-name self.Visit(child) if isinstance(child, pytree.Leaf) and child.value in '+-': _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, format_token.Subtype.A_EXPR_OPERATOR) def Visit_term(self, node): # pylint: disable=invalid-name # term ::= factor (('*'|'/'|'%'|'//') factor)* @@ -197,6 +198,7 @@ def Visit_term(self, node): # pylint: disable=invalid-name if (isinstance(child, pytree.Leaf) and child.value in {'*', '/', '%', '//', '@'}): _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, format_token.Subtype.M_EXPR_OPERATOR) def Visit_factor(self, node): # pylint: disable=invalid-name # factor ::= ('+'|'-'|'~') factor | power diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 63f5ad428..ba3d3855f 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -227,24 +227,6 @@ def _IsUnaryOperator(tok): return format_token.Subtype.UNARY_OPERATOR in tok.subtypes -def _IsMOperator(leaf): - """ See definition of an m_expr in the python reference: - https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations - """ - return leaf.value in ['*', '@', '//', '%', '/'] - - -def _IsAOperator(leaf): - """ See definition of an a_expr in the python reference: - https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations - """ - return leaf.value in ['+', '-'] - - -def _IsBinaryArithmeticOperator(leaf): - return _IsMOperator(leaf) or _IsAOperator(leaf) - - def _IsIndependentOperator(leaf): """Tests whether the operator's operands are leaf nodes.""" siblings = leaf.parent.children @@ -279,7 +261,7 @@ def _HasPrecedence(tok): def _PriorityIndicatingNoSpace(tok): """Whether to remove spaces around an operator due to presedence.""" - if not _IsBinaryArithmeticOperator(tok.node): + if not tok.is_arithmetic_op: # Limit space removal to arithmetic operators return False if not _IsIndependentOperator(tok.node): From 52deb7a8d0429d7e0eb0a14705dd5930253a57b0 Mon Sep 17 00:00:00 2001 From: Harald Husum Date: Fri, 8 Feb 2019 12:41:42 +0100 Subject: [PATCH 352/719] Moved logic for detecting simple expressions --- yapf/yapflib/format_token.py | 21 ++++++++++++++++++++- yapf/yapflib/subtype_assigner.py | 31 +++++++++++++++++++++++++++---- yapf/yapflib/unwrapped_line.py | 13 ++----------- 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 54a6c794a..8d41b900c 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -57,6 +57,7 @@ class Subtype(object): DECORATOR = 18 TYPED_NAME = 19 TYPED_NAME_ARG_LIST = 20 + SIMPLE_EXPRESSION = 24 def _TabbedContinuationAlignPadding(spaces, align_style, tab_width, @@ -282,11 +283,29 @@ def is_binary_op(self): """Token is a binary operator.""" return Subtype.BINARY_OPERATOR in self.subtypes + @property + @py3compat.lru_cache() + def is_a_expr_op(self): + """Token is an a_expr operator.""" + return Subtype.A_EXPR_OPERATOR in self.subtypes + + @property + @py3compat.lru_cache() + def is_m_expr_op(self): + """Token is an m_expr operator.""" + return Subtype.M_EXPR_OPERATOR in self.subtypes + @property @py3compat.lru_cache() def is_arithmetic_op(self): """Token is an arithmetic operator.""" - return Subtype.A_EXPR_OPERATOR in self.subtypes or Subtype.M_EXPR_OPERATOR in self.subtypes + return self.is_a_expr_op or self.is_m_expr_op + + @property + @py3compat.lru_cache() + def is_simple_expr(self): + """Token is an operator in a simple expression.""" + return Subtype.SIMPLE_EXPRESSION in self.subtypes @property @py3compat.lru_cache() diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index d4d865444..af1e0ad20 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -187,19 +187,28 @@ def Visit_arith_expr(self, node): # pylint: disable=invalid-name # arith_expr ::= term (('+'|'-') term)* for child in node.children: self.Visit(child) - if isinstance(child, pytree.Leaf) and child.value in '+-': + if _IsAExprOperator(child): _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) _AppendTokenSubtype(child, format_token.Subtype.A_EXPR_OPERATOR) + if _IsSimpleExpression(node): + for child in node.children: + if _IsAExprOperator(child): + _AppendTokenSubtype(child, format_token.Subtype.SIMPLE_EXPRESSION) + def Visit_term(self, node): # pylint: disable=invalid-name - # term ::= factor (('*'|'/'|'%'|'//') factor)* + # term ::= factor (('*'|'/'|'%'|'//'|'@') factor)* for child in node.children: self.Visit(child) - if (isinstance(child, pytree.Leaf) and - child.value in {'*', '/', '%', '//', '@'}): + if _IsMExprOperator(child): _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) _AppendTokenSubtype(child, format_token.Subtype.M_EXPR_OPERATOR) + if _IsSimpleExpression(node): + for child in node.children: + if _IsMExprOperator(child): + _AppendTokenSubtype(child, format_token.Subtype.SIMPLE_EXPRESSION) + def Visit_factor(self, node): # pylint: disable=invalid-name # factor ::= ('+'|'-'|'~') factor | power for child in node.children: @@ -448,3 +457,17 @@ def _InsertPseudoParentheses(node): new_node = pytree.Node(syms.atom, [lparen, clone, rparen]) node.replace(new_node) _AppendFirstLeafTokenSubtype(clone, format_token.Subtype.DICTIONARY_VALUE) + + +def _IsAExprOperator(node): + return isinstance(node, pytree.Leaf) and node.value in {'+', '-'} + + +def _IsMExprOperator(node): + return isinstance(node, + pytree.Leaf) and node.value in {'*', '/', '%', '//', '@'} + + +def _IsSimpleExpression(node): + """A node with only leafs as children.""" + return all(map(lambda c: isinstance(c, pytree.Leaf), node.children)) diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index ba3d3855f..00238b164 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -227,12 +227,6 @@ def _IsUnaryOperator(tok): return format_token.Subtype.UNARY_OPERATOR in tok.subtypes -def _IsIndependentOperator(leaf): - """Tests whether the operator's operands are leaf nodes.""" - siblings = leaf.parent.children - return all(map(lambda s: len(s.children) == 0, siblings)) - - def _HasPrecedence(tok): """Whether a binary operation has presedence within its context.""" node = tok.node @@ -261,11 +255,8 @@ def _HasPrecedence(tok): def _PriorityIndicatingNoSpace(tok): """Whether to remove spaces around an operator due to presedence.""" - if not tok.is_arithmetic_op: - # Limit space removal to arithmetic operators - return False - if not _IsIndependentOperator(tok.node): - # Limit space removal to highest priority operators + if not tok.is_arithmetic_op or not tok.is_simple_expr: + # Limit space removal to highest priority arithmetic operators return False return _HasPrecedence(tok) From 62e5e39bf8b475d54324693ece963cb0449291ac Mon Sep 17 00:00:00 2001 From: Harald Husum Date: Fri, 8 Feb 2019 14:07:07 +0100 Subject: [PATCH 353/719] Add test for arithetic expressions in subtype_assigner --- yapftests/subtype_assigner_test.py | 42 ++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index 8daead94c..ef864f83a 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -162,6 +162,48 @@ def testBitwiseOperators(self): ('1', [format_token.Subtype.NONE]),], ]) # yapf: disable + def testArithmeticOperators(self): + code = textwrap.dedent("""\ + x = ((a + (b - 3) * (1 % c) @ d) / 3) // 1 + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckFormatTokenSubtypes(uwlines, [ + [('x', [format_token.Subtype.NONE]), + ('=', {format_token.Subtype.ASSIGN_OPERATOR}), + ('(', [format_token.Subtype.NONE]), + ('(', [format_token.Subtype.NONE]), + ('a', [format_token.Subtype.NONE]), + ('+', {format_token.Subtype.BINARY_OPERATOR, + format_token.Subtype.A_EXPR_OPERATOR}), + ('(', [format_token.Subtype.NONE]), + ('b', [format_token.Subtype.NONE]), + ('-', {format_token.Subtype.BINARY_OPERATOR, + format_token.Subtype.A_EXPR_OPERATOR, + format_token.Subtype.SIMPLE_EXPRESSION}), + ('3', [format_token.Subtype.NONE]), + (')', [format_token.Subtype.NONE]), + ('*', {format_token.Subtype.BINARY_OPERATOR, + format_token.Subtype.M_EXPR_OPERATOR}), + ('(', [format_token.Subtype.NONE]), + ('1', [format_token.Subtype.NONE]), + ('%', {format_token.Subtype.BINARY_OPERATOR, + format_token.Subtype.M_EXPR_OPERATOR, + format_token.Subtype.SIMPLE_EXPRESSION}), + ('c', [format_token.Subtype.NONE]), + (')', [format_token.Subtype.NONE]), + ('@', {format_token.Subtype.BINARY_OPERATOR, + format_token.Subtype.M_EXPR_OPERATOR}), + ('d', [format_token.Subtype.NONE]), + (')', [format_token.Subtype.NONE]), + ('/', {format_token.Subtype.BINARY_OPERATOR, + format_token.Subtype.M_EXPR_OPERATOR}), + ('3', [format_token.Subtype.NONE]), + (')', [format_token.Subtype.NONE]), + ('//', {format_token.Subtype.BINARY_OPERATOR, + format_token.Subtype.M_EXPR_OPERATOR}), + ('1', [format_token.Subtype.NONE]),], + ]) # yapf: disable + def testSubscriptColon(self): code = textwrap.dedent("""\ x[0:42:1] From 62f7484f5873160ae0d78e86fe91efbab57e31d5 Mon Sep 17 00:00:00 2001 From: Harald Husum Date: Fri, 8 Feb 2019 16:31:41 +0100 Subject: [PATCH 354/719] BUGFIX: Operator spacing Fixes a bug where applying binary operators to strings would result in the blacklist specified in `NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS` to not take effect. --- CHANGELOG | 2 ++ yapf/yapflib/unwrapped_line.py | 4 ++-- yapftests/reformatter_style_config_test.py | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 214f01364..f9c03be76 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -26,6 +26,8 @@ multiple lines with the opening bracket on the same line as the key. Therefore, we shouldn't enforce a split because of that. - Increase split penalty around exponent operator. +- Correct spacing when using binary operators on strings with the + `NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS` option enabled. ## [0.25.0] 2018-11-25 ### Added diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 40f129571..6b37389a8 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -291,9 +291,9 @@ def _SpaceRequiredBetween(left, right): # If there is a type hint, then we don't want to add a space between the # equal sign and the hint. return False - if rval not in '[)]}.': + if rval not in '[)]}.' and not right.is_binary_op: # A string followed by something other than a subscript, closing bracket, - # or dot should have a space after it. + # dot, or a binary op should have a space after it. return True if left.is_binary_op and lval != '**' and _IsUnaryOperator(right): # Space between the binary operator and the unary operator. diff --git a/yapftests/reformatter_style_config_test.py b/yapftests/reformatter_style_config_test.py index 5afd805b4..167b3d95a 100644 --- a/yapftests/reformatter_style_config_test.py +++ b/yapftests/reformatter_style_config_test.py @@ -56,7 +56,7 @@ def testSetGlobalStyle(self): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - def testOperatorStyle(self): + def testOperatorNoSpaceStyle(self): try: sympy_style = style.CreatePEP8Style() sympy_style['NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS'] = \ @@ -64,9 +64,11 @@ def testOperatorStyle(self): style.SetGlobalStyle(sympy_style) unformatted_code = textwrap.dedent("""\ a = 1+2 * 3 - 4 / 5 + b = '0' * 1 """) expected_formatted_code = textwrap.dedent("""\ a = 1 + 2*3 - 4/5 + b = '0'*1 """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) From 2e8f45f9e4d25efdd4b85c2334d5cb5f8e614489 Mon Sep 17 00:00:00 2001 From: Harald Husum Date: Fri, 8 Feb 2019 21:44:51 +0100 Subject: [PATCH 355/719] Use single quotes --- yapf/yapflib/unwrapped_line.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 00238b164..7308dab99 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -239,11 +239,11 @@ def _HasPrecedence(tok): # Search through the ancestor nodes in the parse tree for operators with # lower precedence. predecessor_type = pytree_utils.NodeName(ancestor) - if predecessor_type in ["arith_expr", "term"]: + if predecessor_type in ['arith_expr', 'term']: # An ancestor "arith_expr" or "term" means we have found an operator # with lower presedence than our tok. return True - if predecessor_type != "atom": + if predecessor_type != 'atom': # We understand the context to look for precedence within as an # arbitrary nesting of "arith_expr", "term", and "atom" nodes. If we # leave this context we have not found a lower presedence operator. From 2e3c10d169ef981854abadd9e1bac237b4fb3dc2 Mon Sep 17 00:00:00 2001 From: Harald Husum Date: Fri, 8 Feb 2019 21:45:17 +0100 Subject: [PATCH 356/719] Add extra test statement --- yapftests/reformatter_style_config_test.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/yapftests/reformatter_style_config_test.py b/yapftests/reformatter_style_config_test.py index 2388a3643..c2ff4bb16 100644 --- a/yapftests/reformatter_style_config_test.py +++ b/yapftests/reformatter_style_config_test.py @@ -94,6 +94,7 @@ def testOperatorPrecedenceStyle(self): h = 1 + 2 - 3 + 4 i = 1 * 2 / 3 * 4 j = (1 * 2 - 3) + 4 + k = (1 * 2 * 3) + (4 * 5 * 6 * 7 * 8) """) expected_formatted_code = textwrap.dedent("""\ 1 + 2 @@ -108,6 +109,7 @@ def testOperatorPrecedenceStyle(self): h = 1 + 2 - 3 + 4 i = 1 * 2 / 3 * 4 j = (1*2 - 3) + 4 + k = (1*2*3) + (4*5*6*7*8) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) From 6440e8a10fde188ca996ab1c5c2caa17bdb967f8 Mon Sep 17 00:00:00 2001 From: Harald Husum Date: Fri, 8 Feb 2019 23:29:48 +0100 Subject: [PATCH 357/719] Retain coverage --- yapftests/reformatter_basic_test.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 970c7cad2..2e6fd2eeb 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -729,6 +729,13 @@ def testMultilineComment(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testSpaceBetweenStringAndParentheses(self): + code = textwrap.dedent("""\ + b = '0' ('hello') + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testMultilineString(self): code = textwrap.dedent("""\ code = textwrap.dedent('''\ From 0ca7bdd002712093bc8b0bda29009a549b0f2670 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 8 Feb 2019 23:07:28 -0800 Subject: [PATCH 358/719] Bump version to 0.26.0 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d291200c6..02b0026aa 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.26.0] UNRELEASED +## [0.26.0] 2019-02-08 ### Added - `ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS` allows us to split before default / named assignments. diff --git a/yapf/__init__.py b/yapf/__init__.py index dfa15fbca..65584f895 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.25.0' +__version__ = '0.26.0' def main(argv): From 3e8edd7fca950bac5401e65290a6b2be03e709cc Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 9 Feb 2019 06:01:29 -0800 Subject: [PATCH 359/719] Parse integer lists correctly. Remove quotes around the integer list if need be. Closes #667 --- CHANGELOG | 5 +++++ yapf/yapflib/style.py | 3 ++- yapftests/yapf_test.py | 21 ++++++++++++++++++++- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 02b0026aa..92760a8f0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,11 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.26.1] UNRELEASED +### Fixed +- Parse integer lists correctly, removing quotes if the list is within a + string. + ## [0.26.0] 2019-02-08 ### Added - `ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS` allows us to split before diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 579458d74..7d2839497 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -189,7 +189,6 @@ def method(): will be formatted as follows when configured with "*,/": 1 + 2*3 - 4/5 - """), SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=textwrap.dedent("""\ Insert a space between the ending comma and closing bracket of a list, @@ -494,6 +493,8 @@ def _IntListConverter(s): def _IntOrIntListConverter(s): """Option value converter for an integer or list of integers.""" + if len(s) > 2 and s[0] in '"\'': + s = s[1:-1] return _IntListConverter(s) if ',' in s else int(s) diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index fbf563737..c468d2d5c 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -512,7 +512,26 @@ def foo(): # trail style_file = textwrap.dedent(u'''\ [style] based_on_style = chromium - SPACES_BEFORE_COMMENT = 4 + spaces_before_comment = 4 + ''') + with utils.TempFileContents(self.test_tmpdir, style_file) as stylepath: + self.assertYapfReformats( + unformatted_code, + expected_formatted_code, + extra_options=['--style={0}'.format(stylepath)]) + + def testSetCustomStyleSpacesBeforeComment(self): + unformatted_code = textwrap.dedent("""\ + a_very_long_statement_that_extends_way_beyond # Comment + short # This is a shorter statement + """) + expected_formatted_code = textwrap.dedent("""\ + a_very_long_statement_that_extends_way_beyond # Comment + short # This is a shorter statement + """) + style_file = textwrap.dedent(u'''\ + [style] + spaces_before_comment = 15, 20 ''') with utils.TempFileContents(self.test_tmpdir, style_file) as stylepath: self.assertYapfReformats( From ed2f25fe30f124cd6e2538ca12f8f07f27943911 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 10 Feb 2019 02:06:37 -0800 Subject: [PATCH 360/719] Adjust bitwise operand split penalties for & and ^ Closes #665 --- CHANGELOG | 1 + yapf/yapflib/split_penalty.py | 52 ++++++++++++++---------------- yapftests/reformatter_pep8_test.py | 23 +++++++++++++ 3 files changed, 49 insertions(+), 27 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 92760a8f0..107404d0f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,7 @@ ### Fixed - Parse integer lists correctly, removing quotes if the list is within a string. +- Adjust the penalties of bitwise operands for '&' and '^', similar to '|'. ## [0.26.0] 2019-02-08 ### Added diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 7d84d8a3d..3ae6538b4 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -414,27 +414,19 @@ def Visit_expr(self, node): # pylint: disable=invalid-name # expr ::= xor_expr ('|' xor_expr)* self.DefaultNodeVisit(node) _IncreasePenalty(node, EXPR) - index = 1 - while index < len(node.children) - 1: - child = node.children[index] - if isinstance(child, pytree.Leaf) and child.value == '|': - if style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'): - _SetSplitPenalty(child, style.Get('SPLIT_PENALTY_BITWISE_OPERATOR')) - else: - _SetSplitPenalty( - pytree_utils.FirstLeafNode(node.children[index + 1]), - style.Get('SPLIT_PENALTY_BITWISE_OPERATOR')) - index += 1 + _SetBitwiseOperandPenalty(node, '|') def Visit_xor_expr(self, node): # pylint: disable=invalid-name # xor_expr ::= and_expr ('^' and_expr)* self.DefaultNodeVisit(node) _IncreasePenalty(node, XOR_EXPR) + _SetBitwiseOperandPenalty(node, '^') def Visit_and_expr(self, node): # pylint: disable=invalid-name # and_expr ::= shift_expr ('&' shift_expr)* self.DefaultNodeVisit(node) _IncreasePenalty(node, AND_EXPR) + _SetBitwiseOperandPenalty(node, '&') def Visit_shift_expr(self, node): # pylint: disable=invalid-name # shift_expr ::= arith_expr (('<<'|'>>') arith_expr)* @@ -447,14 +439,7 @@ def Visit_arith_expr(self, node): # pylint: disable=invalid-name # arith_expr ::= term (('+'|'-') term)* self.DefaultNodeVisit(node) _IncreasePenalty(node, ARITH_EXPR) - - index = 1 - while index < len(node.children) - 1: - child = node.children[index] - if pytree_utils.NodeName(child) in self._ARITH_OPS: - next_node = pytree_utils.FirstLeafNode(node.children[index + 1]) - _SetSplitPenalty(next_node, ARITH_EXPR) - index += 1 + _SetExpressionOperandPenalty(node, self._ARITH_OPS, ARITH_EXPR) _TERM_OPS = frozenset({'STAR', 'AT', 'SLASH', 'PERCENT', 'DOUBLESLASH'}) @@ -462,14 +447,7 @@ def Visit_term(self, node): # pylint: disable=invalid-name # term ::= factor (('*'|'@'|'/'|'%'|'//') factor)* self.DefaultNodeVisit(node) _IncreasePenalty(node, TERM) - - index = 1 - while index < len(node.children) - 1: - child = node.children[index] - if pytree_utils.NodeName(child) in self._TERM_OPS: - next_node = pytree_utils.FirstLeafNode(node.children[index + 1]) - _SetSplitPenalty(next_node, TERM) - index += 1 + _SetExpressionOperandPenalty(node, self._TERM_OPS, TERM) def Visit_factor(self, node): # pyline: disable=invalid-name # factor ::= ('+'|'-'|'~') factor | power @@ -558,6 +536,26 @@ def RecExpression(node, first_child_leaf): RecExpression(node, pytree_utils.FirstLeafNode(node)) +def _SetBitwiseOperandPenalty(node, op): + for index in py3compat.range(1, len(node.children) - 1): + child = node.children[index] + if isinstance(child, pytree.Leaf) and child.value == op: + if style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'): + _SetSplitPenalty(child, style.Get('SPLIT_PENALTY_BITWISE_OPERATOR')) + else: + _SetSplitPenalty( + pytree_utils.FirstLeafNode(node.children[index + 1]), + style.Get('SPLIT_PENALTY_BITWISE_OPERATOR')) + + +def _SetExpressionOperandPenalty(node, ops, penalty): + for index in py3compat.range(1, len(node.children) - 1): + child = node.children[index] + if pytree_utils.NodeName(child) in ops: + next_node = pytree_utils.FirstLeafNode(node.children[index + 1]) + _SetSplitPenalty(next_node, penalty) + + def _IncreasePenalty(node, amt): """Increase a penalty annotation on children nodes.""" diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index a6f736f7a..635760ade 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -431,6 +431,29 @@ def testNoSplitBeforeDictValue(self): finally: style.SetGlobalStyle(style.CreatePEP8Style()) + def testBitwiseOperandSplitting(self): + unformatted_code = """\ +def _(): + include_values = np.where( + (cdffile['Quality_Flag'][:] >= 5) & ( + cdffile['Day_Night_Flag'][:] == 1) & ( + cdffile['Longitude'][:] >= select_lon - radius) & ( + cdffile['Longitude'][:] <= select_lon + radius) & ( + cdffile['Latitude'][:] >= select_lat - radius) & ( + cdffile['Latitude'][:] <= select_lat + radius)) +""" + expected_code = """\ +def _(): + include_values = np.where( + (cdffile['Quality_Flag'][:] >= 5) & (cdffile['Day_Night_Flag'][:] == 1) + & (cdffile['Longitude'][:] >= select_lon - radius) + & (cdffile['Longitude'][:] <= select_lon + radius) + & (cdffile['Latitude'][:] >= select_lat - radius) + & (cdffile['Latitude'][:] <= select_lat + radius)) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From 69ce39121d7980840cda21e543b50eb2a991bbd6 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 10 Feb 2019 02:48:32 -0800 Subject: [PATCH 361/719] Add knobs to split before an arithmetic operator. Closes #658 --- CHANGELOG | 6 +++++- README.rst | 13 ++++++++++--- yapf/yapflib/comment_splicer.py | 4 ++-- yapf/yapflib/format_token.py | 12 ++++++------ yapf/yapflib/split_penalty.py | 18 +++++++++++------- yapf/yapflib/style.py | 10 ++++++++++ yapf/yapflib/subtype_assigner.py | 2 +- yapf/yapflib/unwrapped_line.py | 15 +++++---------- yapftests/reformatter_buganizer_test.py | 8 ++++---- yapftests/reformatter_pep8_test.py | 25 +++++++++++++++++++++++-- yapftests/yapf_test.py | 2 +- 11 files changed, 78 insertions(+), 37 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 107404d0f..ee72fdb4d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,11 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.26.1] UNRELEASED +## [0.27.0] UNRELEASED +### Added +- `SPLIT_BEFORE_ARITHMETIC_OPERATOR` splits before an arithmetic operator when + set. `SPLIT_PENALTY_ARITHMETIC_OPERATOR` allows you to set the split penalty + around arithmetic operators. ### Fixed - Parse integer lists correctly, removing quotes if the list is within a string. diff --git a/README.rst b/README.rst index 388ddaaf0..d435334c0 100644 --- a/README.rst +++ b/README.rst @@ -564,9 +564,12 @@ Knobs If a comma separated list (dict, list, tuple, or function def) is on a line that is too long, split such that all elements are on a single line. -``SPLIT_BEFORE_BITWISE_OPERATOR`` - Set to ``True`` to prefer splitting before ``&``, ``|`` or ``^`` rather - than after. +``SPLIT_BEFORE__OPERATOR`` + Set to True to prefer splitting before '&', '|' or '^' rather than after. + +``SPLIT_BEFORE_ARITHMETIC_OPERATOR`` + Set to True to prefer splitting before '+', '-', '*', '/', '//', or '@' + rather than after. ``SPLIT_BEFORE_CLOSING_BRACKET`` Split before the closing bracket if a list or dict literal doesn't fit on @@ -639,6 +642,10 @@ Knobs ``SPLIT_PENALTY_AFTER_UNARY_OPERATOR`` The penalty for splitting the line after a unary operator. +``SPLIT_PENALTY_ARITHMETIC_OPERATOR`` + The penalty of splitting the line around the ``+``, ``-``, ``*``, ``/``, + ``//``, ``%``, and ``@`` operators. + ``SPLIT_PENALTY_BEFORE_IF_EXPR`` The penalty for splitting right before an ``if`` expression. diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index af999d260..8717394f0 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -177,8 +177,8 @@ def _VisitNodeRec(node): rindex = (0 if '\n' not in comment_prefix.rstrip() else comment_prefix.rstrip().rindex('\n') + 1) comment_column = ( - len(comment_prefix[rindex:]) - len( - comment_prefix[rindex:].lstrip())) + len(comment_prefix[rindex:]) - + len(comment_prefix[rindex:].lstrip())) comments = _CreateCommentsFromPrefix( comment_prefix, comment_lineno, diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 8d41b900c..e7ed764a4 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -169,8 +169,8 @@ def AddWhitespacePrefix(self, newlines_before, spaces=0, indent_level=0): else: indent_before = '\t' * indent_level + ' ' * spaces else: - indent_before = ( - ' ' * indent_level * style.Get('INDENT_WIDTH') + ' ' * spaces) + indent_before = (' ' * indent_level * style.Get('INDENT_WIDTH') + + ' ' * spaces) if self.is_comment: comment_lines = [s.lstrip() for s in self.value.splitlines()] @@ -180,15 +180,15 @@ def AddWhitespacePrefix(self, newlines_before, spaces=0, indent_level=0): self.value = self.node.value if not self.whitespace_prefix: - self.whitespace_prefix = ( - '\n' * (self.newlines or newlines_before) + indent_before) + self.whitespace_prefix = ('\n' * (self.newlines or newlines_before) + + indent_before) else: self.whitespace_prefix += indent_before def AdjustNewlinesBefore(self, newlines_before): """Change the number of newlines before this token.""" - self.whitespace_prefix = ( - '\n' * newlines_before + self.whitespace_prefix.lstrip('\n')) + self.whitespace_prefix = ('\n' * newlines_before + + self.whitespace_prefix.lstrip('\n')) def RetainHorizontalSpacing(self, first_column, depth): """Retains a token's horizontal spacing.""" diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 3ae6538b4..3df8f2ec4 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -439,7 +439,7 @@ def Visit_arith_expr(self, node): # pylint: disable=invalid-name # arith_expr ::= term (('+'|'-') term)* self.DefaultNodeVisit(node) _IncreasePenalty(node, ARITH_EXPR) - _SetExpressionOperandPenalty(node, self._ARITH_OPS, ARITH_EXPR) + _SetExpressionOperandPenalty(node, self._ARITH_OPS) _TERM_OPS = frozenset({'STAR', 'AT', 'SLASH', 'PERCENT', 'DOUBLESLASH'}) @@ -447,7 +447,7 @@ def Visit_term(self, node): # pylint: disable=invalid-name # term ::= factor (('*'|'@'|'/'|'%'|'//') factor)* self.DefaultNodeVisit(node) _IncreasePenalty(node, TERM) - _SetExpressionOperandPenalty(node, self._TERM_OPS, TERM) + _SetExpressionOperandPenalty(node, self._TERM_OPS) def Visit_factor(self, node): # pyline: disable=invalid-name # factor ::= ('+'|'-'|'~') factor | power @@ -548,12 +548,16 @@ def _SetBitwiseOperandPenalty(node, op): style.Get('SPLIT_PENALTY_BITWISE_OPERATOR')) -def _SetExpressionOperandPenalty(node, ops, penalty): +def _SetExpressionOperandPenalty(node, ops): for index in py3compat.range(1, len(node.children) - 1): - child = node.children[index] - if pytree_utils.NodeName(child) in ops: - next_node = pytree_utils.FirstLeafNode(node.children[index + 1]) - _SetSplitPenalty(next_node, penalty) + child = node.children[index] + if pytree_utils.NodeName(child) in ops: + if style.Get('SPLIT_BEFORE_ARITHMETIC_OPERATOR'): + _SetSplitPenalty(child, style.Get('SPLIT_PENALTY_ARITHMETIC_OPERATOR')) + else: + _SetSplitPenalty( + pytree_utils.FirstLeafNode(node.children[index + 1]), + style.Get('SPLIT_PENALTY_ARITHMETIC_OPERATOR')) def _IncreasePenalty(node, amt): diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 7d2839497..c01e7a2db 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -241,6 +241,9 @@ def method(): comma."""), SPLIT_ALL_COMMA_SEPARATED_VALUES=textwrap.dedent("""\ Split before arguments"""), + SPLIT_BEFORE_ARITHMETIC_OPERATOR=textwrap.dedent("""\ + Set to True to prefer splitting before '+', '-', '*', '/', '//', or '@' + rather than after."""), SPLIT_BEFORE_BITWISE_OPERATOR=textwrap.dedent("""\ Set to True to prefer splitting before '&', '|' or '^' rather than after."""), @@ -297,6 +300,9 @@ def method(): The penalty for splitting right after the opening bracket."""), SPLIT_PENALTY_AFTER_UNARY_OPERATOR=textwrap.dedent("""\ The penalty for splitting the line after a unary operator."""), + SPLIT_PENALTY_ARITHMETIC_OPERATOR=textwrap.dedent("""\ + The penalty of splitting the line around the '+', '-', '*', '/', '//', + ``%``, and '@' operators."""), SPLIT_PENALTY_BEFORE_IF_EXPR=textwrap.dedent("""\ The penalty for splitting right before an if expression."""), SPLIT_PENALTY_BITWISE_OPERATOR=textwrap.dedent("""\ @@ -363,6 +369,7 @@ def CreatePEP8Style(): SPACES_BEFORE_COMMENT=2, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False, SPLIT_ALL_COMMA_SEPARATED_VALUES=False, + SPLIT_BEFORE_ARITHMETIC_OPERATOR=False, SPLIT_BEFORE_BITWISE_OPERATOR=True, SPLIT_BEFORE_CLOSING_BRACKET=True, SPLIT_BEFORE_DICT_SET_GENERATOR=True, @@ -374,6 +381,7 @@ def CreatePEP8Style(): SPLIT_COMPLEX_COMPREHENSION=False, SPLIT_PENALTY_AFTER_OPENING_BRACKET=30, SPLIT_PENALTY_AFTER_UNARY_OPERATOR=10000, + SPLIT_PENALTY_ARITHMETIC_OPERATOR=300, SPLIT_PENALTY_BEFORE_IF_EXPR=0, SPLIT_PENALTY_BITWISE_OPERATOR=300, SPLIT_PENALTY_COMPREHENSION=80, @@ -536,6 +544,7 @@ def _IntOrIntListConverter(s): SPACES_BEFORE_COMMENT=_IntOrIntListConverter, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter, SPLIT_ALL_COMMA_SEPARATED_VALUES=_BoolConverter, + SPLIT_BEFORE_ARITHMETIC_OPERATOR=_BoolConverter, SPLIT_BEFORE_BITWISE_OPERATOR=_BoolConverter, SPLIT_BEFORE_CLOSING_BRACKET=_BoolConverter, SPLIT_BEFORE_DICT_SET_GENERATOR=_BoolConverter, @@ -547,6 +556,7 @@ def _IntOrIntListConverter(s): SPLIT_COMPLEX_COMPREHENSION=_BoolConverter, SPLIT_PENALTY_AFTER_OPENING_BRACKET=int, SPLIT_PENALTY_AFTER_UNARY_OPERATOR=int, + SPLIT_PENALTY_ARITHMETIC_OPERATOR=int, SPLIT_PENALTY_BEFORE_IF_EXPR=int, SPLIT_PENALTY_BITWISE_OPERATOR=int, SPLIT_PENALTY_COMPREHENSION=int, diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index af1e0ad20..dc36bbb64 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -470,4 +470,4 @@ def _IsMExprOperator(node): def _IsSimpleExpression(node): """A node with only leafs as children.""" - return all(map(lambda c: isinstance(c, pytree.Leaf), node.children)) + return all(isinstance(child, pytree.Leaf) for child in node.children) diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index b45d12a9f..fb1275583 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -228,7 +228,7 @@ def _IsUnaryOperator(tok): def _HasPrecedence(tok): - """Whether a binary operation has presedence within its context.""" + """Whether a binary operation has precedence within its context.""" node = tok.node # We let ancestor be the statement surrounding the operation that tok is the @@ -241,12 +241,12 @@ def _HasPrecedence(tok): predecessor_type = pytree_utils.NodeName(ancestor) if predecessor_type in ['arith_expr', 'term']: # An ancestor "arith_expr" or "term" means we have found an operator - # with lower presedence than our tok. + # with lower precedence than our tok. return True if predecessor_type != 'atom': # We understand the context to look for precedence within as an # arbitrary nesting of "arith_expr", "term", and "atom" nodes. If we - # leave this context we have not found a lower presedence operator. + # leave this context we have not found a lower precedence operator. return False # Under normal usage we expect a complete parse tree to be available and # we will return before we get an AttributeError from the root. @@ -254,7 +254,7 @@ def _HasPrecedence(tok): def _PriorityIndicatingNoSpace(tok): - """Whether to remove spaces around an operator due to presedence.""" + """Whether to remove spaces around an operator due to precedence.""" if not tok.is_arithmetic_op or not tok.is_simple_expr: # Limit space removal to highest priority arithmetic operators return False @@ -519,7 +519,7 @@ def IsSurroundedByBrackets(tok): _LOGICAL_OPERATORS = frozenset({'and', 'or'}) _BITWISE_OPERATORS = frozenset({'&', '|', '^'}) -_TERM_OPERATORS = frozenset({'*', '/', '%', '//', '@'}) +_ARITHMETIC_OPERATORS = frozenset({'+', '-', '*', '/', '%', '//', '@'}) def _SplitPenalty(prev_token, cur_token): @@ -568,9 +568,6 @@ def _SplitPenalty(prev_token, cur_token): if pval == ',': # Breaking after a comma is fine, if need be. return 0 - if prev_token.is_binary_op: - # We would rather not split after an equality operator. - return split_penalty.CONNECTED if pval == '**' or cval == '**': return split_penalty.STRONGLY_CONNECTED if (format_token.Subtype.VARARGS_STAR in prev_token.subtypes or @@ -596,6 +593,4 @@ def _SplitPenalty(prev_token, cur_token): if cur_token.ClosesScope(): # Give a slight penalty for splitting before the closing scope. return 100 - if pval in _TERM_OPERATORS or cval in _TERM_OPERATORS: - return 50 return 0 diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 38e4437f1..22309ac34 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -840,8 +840,8 @@ def _(): expected_formatted_code = textwrap.dedent("""\ class _(): def _(): - hints.append(('hg tag -f -l -r %s %s # %s' % (short( - ctx.node()), candidatetag, firstline))[:78]) + hints.append(('hg tag -f -l -r %s %s # %s' % + (short(ctx.node()), candidatetag, firstline))[:78]) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1457,8 +1457,8 @@ def foo(): expected_formatted_code = textwrap.dedent("""\ def foo(): if True: - return ( - struct.pack('aaaa', bbbbbbbbbb, ccccccccccccccc, dddddddd) + eeeeeee) + return (struct.pack('aaaa', bbbbbbbbbb, ccccccccccccccc, dddddddd) + + eeeeeee) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 635760ade..729b33cf1 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -165,8 +165,8 @@ def testIndentSizeChanging(self): """) expected_formatted_code = textwrap.dedent("""\ if True: - runtime_mins = ( - program_end_time - program_start_time).total_seconds() / 60.0 + runtime_mins = (program_end_time - + program_start_time).total_seconds() / 60.0 """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -454,6 +454,27 @@ def _(): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + def testSplitBeforeArithmeticOperators(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: pep8, split_before_arithmetic_operator: true}')) + + unformatted_code = """\ +def _(): + raise ValueError('This is a long message that ends with an argument: ' + str(42)) +""" + expected_formatted_code = """\ +def _(): + raise ValueError('This is a long message that ends with an argument: ' + + str(42)) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreatePEP8Style()) + if __name__ == '__main__': unittest.main() diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index c468d2d5c..a676e1940 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1460,7 +1460,7 @@ class HorizontallyAlignedTrailingCommentsTest(unittest.TestCase): @staticmethod def _OwnStyle(): my_style = style.CreatePEP8Style() - my_style["SPACES_BEFORE_COMMENT"] = [ + my_style['SPACES_BEFORE_COMMENT'] = [ 15, 25, 35, From 141eb68089623039d48fb4edabc9946dcbd548f9 Mon Sep 17 00:00:00 2001 From: Stephen Thorne Date: Thu, 14 Feb 2019 11:53:36 +1100 Subject: [PATCH 362/719] Test if a string is a multiline string without using a regex. The approach of using a regex makes sure to exclude any token that isn't a multiline string by only matching valid multiline strings. But at this point all tokens are already known to be valid, so a faster heuristic can be used. Instead by taking the approach of checking to see if the last 3 characters are a triple quotation mark, testing for a multiline string is significantly faster. --- yapf/yapflib/format_token.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index e7ed764a4..9bae9cb6c 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -342,18 +342,14 @@ def is_string(self): @property @py3compat.lru_cache() def is_multiline_string(self): - """A multiline string.""" - if py3compat.PY3: - prefix = '(' - prefix += 'r|u|R|U|f|F|fr|Fr|fR|FR|rf|rF|Rf|RF' # strings - prefix += '|b|B|br|Br|bR|BR|rb|rB|Rb|RB' # bytes - prefix += ')?' - else: - prefix = '[uUbB]?[rR]?' + """Test if this string is a multiline string. - regex = r'^{prefix}(?P"""|\'\'\').*(?P=delim)$'.format(prefix=prefix) - return (self.is_string and - re.match(regex, self.value, re.DOTALL) is not None) + Returns: + A multiline string always ends with triple quotes, so if it is a string + token, inspect the last 3 characters and return True if it is a triple + double or triple single quote mark. + """ + return self.is_string and self.value.endswith(('"""', "'''")) @property @py3compat.lru_cache() From bbe88f5197bd3b2f9dbeee20c8ef6511ab72ff19 Mon Sep 17 00:00:00 2001 From: Alessandro Pietro Bardelli Date: Fri, 22 Feb 2019 09:38:11 +0100 Subject: [PATCH 363/719] Add note about YAPF sometimes not PEP8 compliant Addresses and Closes #680 --- README.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/README.rst b/README.rst index d435334c0..387fda810 100644 --- a/README.rst +++ b/README.rst @@ -746,6 +746,31 @@ Can I Use YAPF In My Program? Please do! YAPF was designed to be used as a library as well as a command line tool. This means that a tool or IDE plugin is free to use YAPF. +----------------------------------------- +I still get non Pep8 compliant code! Why? +----------------------------------------- + +YAPF tries very hard to be fully PEP 8 compliant. However, it is paramount +to not risk altering the semantics of your code. Thus, YAPF tries to be as +safe as possible and does not change the token stream +(e.g., by adding parenthesis). +All these cases however, can be easily fixed manually. For instance, + +.. code-block:: python + + from my_package import my_function_1, my_function_2, my_function_3, my_function_4, my_function_5 + + FOO = my_variable_1 + my_variable_2 + my_variable_3 + my_variable_4 + my_variable_5 + my_variable_6 + my_variable_7 + my_variable_8 + +won't be split, but you can easily get it right by just adding parenthesis: + +.. code-block:: python + + from my_package import (my_function_1, my_function_2, my_function_3, + my_function_4, my_function_5) + + FOO = (my_variable_1 + my_variable_2 + my_variable_3 + my_variable_4 + + my_variable_5 + my_variable_6 + my_variable_7 + my_variable_8) Gory Details ============ From 2b28ced2b039ceaaca304c7d69b4f8b5c8213691 Mon Sep 17 00:00:00 2001 From: Chayoung You Date: Thu, 21 Feb 2019 18:41:55 +0900 Subject: [PATCH 364/719] Fix bugs of handling arrays in pre-commit.sh PYTHON_FILES, CHANGED_FILES are assigned by =$(...), so they're not arrays. This leads running `yapf -i -r "${PYTHON_FILES[@]}"` to be equivalent to running `yapf -i -r "$PYTHON_FILES"`, and that keeps yapf from handling multiple files properly. Note that `${#ARRAY[@]}` gives the number of elements in `ARRAY`. See: https://github.com/koalaman/shellcheck/wiki/SC2207 --- plugins/pre-commit.sh | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/plugins/pre-commit.sh b/plugins/pre-commit.sh index 1552e9368..3e6873949 100755 --- a/plugins/pre-commit.sh +++ b/plugins/pre-commit.sh @@ -21,8 +21,10 @@ # is used. # Find all staged Python files, and exit early if there aren't any. -PYTHON_FILES=$(git diff --name-only --cached --diff-filter=AM | grep --color=never '.py$') -if [ -z "${PYTHON_FILES}" ]; then +PYTHON_FILES=() +while IFS=$'\n' read -r line; do PYTHON_FILES+=("$line"); done \ + < <(git diff --name-only --cached --diff-filter=AM | grep --color=never '.py$') +if [ ${#PYTHON_FILES[@]} -eq 0 ]; then exit 0 fi @@ -45,8 +47,10 @@ fi # Check for unstaged changes to files in the index. -CHANGED_FILES=$(git diff --name-only "${PYTHON_FILES[@]}") -if [ -n "${CHANGED_FILES}" ]; then +CHANGED_FILES=() +while IFS=$'\n' read -r line; do CHANGED_FILES+=("$line"); done \ + < <(git diff --name-only "${PYTHON_FILES[@]}") +if [ ${#CHANGED_FILES[@]} -gt 0 ]; then echo 'You have unstaged changes to some files in your commit; skipping ' echo 'auto-format. Please stage, stash, or revert these changes. You may ' echo 'find `git stash -k` helpful here.' @@ -67,8 +71,10 @@ yapf -i -r "${PYTHON_FILES[@]}" ###### END PIPENV VERSION ########## -CHANGED_FILES=$(git diff --name-only "${PYTHON_FILES[@]}") -if [ -n "${CHANGED_FILES}" ]; then +CHANGED_FILES=() +while IFS=$'\n' read -r line; do CHANGED_FILES+=("$line"); done \ + < <(git diff --name-only "${PYTHON_FILES[@]}") +if [ ${#CHANGED_FILES[@]} -gt 0 ]; then echo 'Reformatted staged files. Please review and stage the changes.' echo 'Files updated: ' "${CHANGED_FILES[@]}" exit 1 From be01b215a00e093c4c4198055b4667054d8d2722 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Sun, 24 Feb 2019 23:43:31 -0500 Subject: [PATCH 365/719] Fix SPLIT_BEFORE_BITWISE_OPERATOR in README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 387fda810..ead684331 100644 --- a/README.rst +++ b/README.rst @@ -564,7 +564,7 @@ Knobs If a comma separated list (dict, list, tuple, or function def) is on a line that is too long, split such that all elements are on a single line. -``SPLIT_BEFORE__OPERATOR`` +``SPLIT_BEFORE_BITWISE_OPERATOR`` Set to True to prefer splitting before '&', '|' or '^' rather than after. ``SPLIT_BEFORE_ARITHMETIC_OPERATOR`` From eb16730428e066196f2ac2a66a78c1001754f268 Mon Sep 17 00:00:00 2001 From: Alessandro Pietro Bardelli Date: Mon, 11 Mar 2019 14:45:46 +0100 Subject: [PATCH 366/719] MAINT: remove invalid option LESS for CONTINUATION_ALIGN_STYLE The LESS option for CONTINUATION_ALIGN_STYLE is not supported anymore. Closes #687 --- yapf/yapflib/style.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index c01e7a2db..c94da3c46 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -125,8 +125,6 @@ def method(): - FIXED: Use fixed number (CONTINUATION_INDENT_WIDTH) of columns (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs) for continuation alignment. - - LESS: Slightly left if cannot vertically align continuation lines with - indent characters. - VALIGN-RIGHT: Vertically align continuation lines with indent characters. Slightly right (one more indent character) if cannot vertically align continuation lines with indent characters. From 3bf3aa075984c7740e7611711b1da78242174e30 Mon Sep 17 00:00:00 2001 From: Alessandro Pietro Bardelli Date: Tue, 12 Mar 2019 17:19:27 +0100 Subject: [PATCH 367/719] FIX: avoid split_before_first_argument if set to False If the option split_before_first_argument is set to false try to not split the line if not needed Resolves #424, #556, #590, #684 --- CHANGELOG | 5 +- yapf/__init__.py | 6 +- yapf/yapflib/format_decision_state.py | 39 ++++++++++-- yapf/yapflib/reformatter.py | 5 +- yapf/yapflib/style.py | 4 +- yapftests/reformatter_buganizer_test.py | 6 +- yapftests/reformatter_pep8_test.py | 6 +- yapftests/reformatter_style_config_test.py | 72 ++++++++++++++++++++++ 8 files changed, 126 insertions(+), 17 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ee72fdb4d..1df010a73 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,9 @@ - Parse integer lists correctly, removing quotes if the list is within a string. - Adjust the penalties of bitwise operands for '&' and '^', similar to '|'. +- Avoid splitting after opening parens if SPLIT_BEFORE_FIRST_ARGUMENT is set + to False. +- Adjust default SPLIT_PENALTY_AFTER_OPENING_BRACKET. ## [0.26.0] 2019-02-08 ### Added @@ -20,7 +23,7 @@ if they have higher precedence than other operators in the same expression. ### Changed - `SPACES_BEFORE_COMMENT` can now be assigned to a specific value (standard - behavior) or a list of column values. When assigned to a list, trailing + behavior) or a list of column values. When assigned to a list, trailing comments will be horizontally aligned to the first column value within the list that is greater than the maximum line length in the block. - Don't modify the vertical spacing of a line that has a comment "pylint: diff --git a/yapf/__init__.py b/yapf/__init__.py index 65584f895..97a963355 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -195,9 +195,9 @@ def main(argv): exclude_patterns_from_ignore_file = file_resources.GetExcludePatternsForDir( os.getcwd()) - files = file_resources.GetCommandLineFiles( - args.files, args.recursive, - (args.exclude or []) + exclude_patterns_from_ignore_file) + files = file_resources.GetCommandLineFiles(args.files, args.recursive, + (args.exclude or []) + + exclude_patterns_from_ignore_file) if not files: raise errors.YapfError('Input filenames did not match any python files') diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 8dd5e55c4..486be8bce 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -359,6 +359,11 @@ def SurroundedByParens(token): # assigns. return False + # Don't split if not required + if (not style.Get('SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN') and + not style.Get('SPLIT_BEFORE_FIRST_ARGUMENT')): + return False + column = self.column - self.stack[-1].last_space return column > style.Get('CONTINUATION_INDENT_WIDTH') @@ -412,12 +417,14 @@ def SurroundedByParens(token): pprevious = previous.previous_token if (current.is_name and pprevious and pprevious.is_name and previous.value == '('): + if (not self._FitsOnLine(previous, previous.matching_bracket) and _IsFunctionCallWithArguments(current)): # There is a function call, with more than 1 argument, where the first - # argument is itself a function call with arguments. In this specific - # case, if we split after the first argument's opening '(', then the - # formatting will look bad for the rest of the arguments. E.g.: + # argument is itself a function call with arguments that does not fit + # into the line. In this specific case, if we split after the first + # argument's opening '(', then the formatting will look bad for the + # rest of the arguments. E.g.: # # outer_function_call(inner_function_call( # inner_arg1, inner_arg2), @@ -425,7 +432,31 @@ def SurroundedByParens(token): # # Instead, enforce a split before that argument to keep things looking # good. - return True + if (style.Get('SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN') or + style.Get('SPLIT_BEFORE_FIRST_ARGUMENT')): + return True + + opening = _GetOpeningBracket(current) + if (opening and opening.value == '(' and opening.previous_token and + (opening.previous_token.is_name or + opening.previous_token.value in {'*', '**'})): + is_func_call = False + opening = current + while opening: + if opening.value == '(': + is_func_call = True + break + if (not (opening.is_name or opening.value in {'*', '**'}) and + opening.value != '.'): + break + opening = opening.next_token + + if is_func_call: + if (not self._FitsOnLine(current, opening.matching_bracket) or + (opening.matching_bracket.next_token and + opening.matching_bracket.next_token.value != ',' and + not opening.matching_bracket.next_token.ClosesScope())): + return True if (previous.OpensScope() and not current.OpensScope() and not current.is_comment and diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index b7c749106..48858a38f 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -660,8 +660,9 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, prev_last_token.AdjustNewlinesBefore( 1 + style.Get('BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION')) if first_token.newlines is not None: - pytree_utils.SetNodeAnnotation( - first_token.node, pytree_utils.Annotation.NEWLINES, None) + pytree_utils.SetNodeAnnotation(first_token.node, + pytree_utils.Annotation.NEWLINES, + None) return NO_BLANK_LINES elif _IsClassOrDef(prev_uwline): if not style.Get('BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'): diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index c01e7a2db..13899a7e3 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -204,7 +204,7 @@ def method(): alignment column values; trailing comments within a block will be aligned to the first column value that is greater than the maximum line length within the block). For example: - + With spaces_before_comment=5: 1 + 1 # Adding values @@ -379,7 +379,7 @@ def CreatePEP8Style(): SPLIT_BEFORE_LOGICAL_OPERATOR=True, SPLIT_BEFORE_NAMED_ASSIGNS=True, SPLIT_COMPLEX_COMPREHENSION=False, - SPLIT_PENALTY_AFTER_OPENING_BRACKET=30, + SPLIT_PENALTY_AFTER_OPENING_BRACKET=300, SPLIT_PENALTY_AFTER_UNARY_OPERATOR=10000, SPLIT_PENALTY_ARITHMETIC_OPERATOR=300, SPLIT_PENALTY_BEFORE_IF_EXPR=0, diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 22309ac34..4d555e35b 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -1546,7 +1546,7 @@ def testB20016122(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig( - '{based_on_style: pep8, split_penalty_import_names: 35}')) + '{based_on_style: pep8, split_penalty_import_names: 350}')) unformatted_code = textwrap.dedent("""\ from a_very_long_or_indented_module_name_yada_yada import (long_argument_1, long_argument_2) @@ -2193,8 +2193,8 @@ def testB67935687(self): }) """) expected_formatted_code = textwrap.dedent("""\ - shelf_renderer.expand_text = text.translate_to_unicode( - expand_text % {'creator': creator}) + shelf_renderer.expand_text = text.translate_to_unicode(expand_text % + {'creator': creator}) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 729b33cf1..05d2cf090 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -190,8 +190,10 @@ def h(): if (aaaaaaaaaaaaaa + bbbbbbbbbbbbbbbb == ccccccccccccccccc and xxxxxxxxxxxxx or yyyyyyyyyyyyyyyyy): pass - elif (xxxxxxxxxxxxxxx( - aaaaaaaaaaa, bbbbbbbbbbbbbb, cccccccccccc, dddddddddd=None)): + elif (xxxxxxxxxxxxxxx(aaaaaaaaaaa, + bbbbbbbbbbbbbb, + cccccccccccc, + dddddddddd=None)): pass diff --git a/yapftests/reformatter_style_config_test.py b/yapftests/reformatter_style_config_test.py index a36927928..5fe9709c1 100644 --- a/yapftests/reformatter_style_config_test.py +++ b/yapftests/reformatter_style_config_test.py @@ -121,6 +121,78 @@ def testOperatorPrecedenceStyle(self): style.SetGlobalStyle(style.CreatePEP8Style()) style.DEFAULT_STYLE = self.current_style + def testNoSplitBeforeFirstArgumentStyle1(self): + try: + pep8_no_split_before_first = style.CreatePEP8Style() + pep8_no_split_before_first['SPLIT_BEFORE_FIRST_ARGUMENT'] = False + pep8_no_split_before_first['SPLIT_BEFORE_NAMED_ASSIGNS'] = False + style.SetGlobalStyle(pep8_no_split_before_first) + formatted_code = textwrap.dedent("""\ + # Example from in-code MustSplit comments + foo = outer_function_call(fitting_inner_function_call(inner_arg1, inner_arg2), + outer_arg1, outer_arg2) + + foo = outer_function_call( + not_fitting_inner_function_call(inner_arg1, inner_arg2), outer_arg1, + outer_arg2) + + # Examples Issue#424 + a_super_long_version_of_print(argument1, argument2, argument3, argument4, + argument5, argument6, argument7) + + CREDS_FILE = os.path.join(os.path.expanduser('~'), + 'apis/super-secret-admin-creds.json') + + # Examples Issue#556 + i_take_a_lot_of_params(arg1, param1=very_long_expression1(), + param2=very_long_expression2(), + param3=very_long_expression3(), + param4=very_long_expression4()) + + # Examples Issue#590 + plt.plot(numpy.linspace(0, 1, 10), numpy.linspace(0, 1, 10), marker="x", + color="r") + + plt.plot(veryverylongvariablename, veryverylongvariablename, marker="x", + color="r") + """) + uwlines = yapf_test_helper.ParseAndUnwrap(formatted_code) + self.assertCodeEqual(formatted_code, reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreatePEP8Style()) + style.DEFAULT_STYLE = self.current_style + + def testNoSplitBeforeFirstArgumentStyle2(self): + try: + pep8_no_split_before_first = style.CreatePEP8Style() + pep8_no_split_before_first['SPLIT_BEFORE_FIRST_ARGUMENT'] = False + pep8_no_split_before_first['SPLIT_BEFORE_NAMED_ASSIGNS'] = True + style.SetGlobalStyle(pep8_no_split_before_first) + formatted_code = textwrap.dedent("""\ + # Examples Issue#556 + i_take_a_lot_of_params(arg1, + param1=very_long_expression1(), + param2=very_long_expression2(), + param3=very_long_expression3(), + param4=very_long_expression4()) + + # Examples Issue#590 + plt.plot(numpy.linspace(0, 1, 10), + numpy.linspace(0, 1, 10), + marker="x", + color="r") + + plt.plot(veryverylongvariablename, + veryverylongvariablename, + marker="x", + color="r") + """) + uwlines = yapf_test_helper.ParseAndUnwrap(formatted_code) + self.assertCodeEqual(formatted_code, reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreatePEP8Style()) + style.DEFAULT_STYLE = self.current_style + if __name__ == '__main__': unittest.main() From aafcb4cb04abaad1a23e2324b2a0123abf88d75d Mon Sep 17 00:00:00 2001 From: Kevin Cox Date: Thu, 14 Mar 2019 14:18:34 +0000 Subject: [PATCH 368/719] Fix removing of extra lines on the edge of enabled lines boundaries. --- CHANGELOG | 1 + yapf/yapflib/reformatter.py | 11 ++++- yapftests/blank_line_calculator_test.py | 66 +++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ee72fdb4d..9397c49a1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,7 @@ - Parse integer lists correctly, removing quotes if the list is within a string. - Adjust the penalties of bitwise operands for '&' and '^', similar to '|'. +- Re-enable removal of extra lines on the boundaries of formatted regions. ## [0.26.0] 2019-02-08 ### Added diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index b7c749106..f0c149367 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -114,12 +114,21 @@ def _RetainHorizontalSpacing(uwline): def _RetainRequiredVerticalSpacing(cur_uwline, prev_uwline, lines): + if cur_uwline.disable and (not prev_uwline or prev_uwline.disable): + # If both lines are disabled we aren't allowed to reformat anything. + lines = set() + prev_tok = None if prev_uwline is not None: prev_tok = prev_uwline.last for cur_tok in cur_uwline.tokens: _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines) + prev_tok = cur_tok + if cur_uwline.disable: + # After the first token we are acting on a single line. So if it is + # disabled we must not reformat. + lines = set() def _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines): @@ -151,8 +160,6 @@ def _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines): pass elif lines and (cur_lineno in lines or prev_lineno in lines): desired_newlines = cur_tok.whitespace_prefix.count('\n') - if desired_newlines < required_newlines: - desired_newlines = required_newlines whitespace_lines = range(prev_lineno + 1, cur_lineno) deletable_lines = len(lines.intersection(whitespace_lines)) required_newlines = max(required_newlines - deletable_lines, diff --git a/yapftests/blank_line_calculator_test.py b/yapftests/blank_line_calculator_test.py index 2a27a2f89..afc65bdf0 100644 --- a/yapftests/blank_line_calculator_test.py +++ b/yapftests/blank_line_calculator_test.py @@ -350,6 +350,72 @@ def C(): self.assertCodeEqual(expected_formatted_code, code) self.assertFalse(changed) + def testLinesRangeRemove(self): + unformatted_code = textwrap.dedent(u"""\ + def A(): + pass + + + + def B(): # 6 + pass # 7 + + + + + def C(): + pass + """) + expected_formatted_code = textwrap.dedent(u"""\ + def A(): + pass + + + def B(): # 6 + pass # 7 + + + def C(): + pass + """) + code, changed = yapf_api.FormatCode(unformatted_code, lines=[(5, 9)]) + self.assertCodeEqual(expected_formatted_code, code) + + def testLinesRangeRemoveSome(self): + unformatted_code = textwrap.dedent(u"""\ + def A(): + pass + + + + + def B(): # 7 + pass # 8 + + + + + def C(): + pass + """) + expected_formatted_code = textwrap.dedent(u"""\ + def A(): + pass + + + + def B(): # 7 + pass # 8 + + + + def C(): + pass + """) + code, changed = yapf_api.FormatCode(unformatted_code, lines=[(6, 9)]) + self.assertCodeEqual(expected_formatted_code, code) + self.assertTrue(changed) + if __name__ == '__main__': unittest.main() From 3ea0d1b45781bfeb183a499296b6e25091a09dc2 Mon Sep 17 00:00:00 2001 From: Tim 'mithro' Ansell Date: Wed, 20 Mar 2019 14:10:08 -0700 Subject: [PATCH 369/719] Adding test for Github Issue #678. Signed-off-by: Tim 'mithro' Ansell --- yapftests/reformatter_buganizer_test.py | 27 +++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 22309ac34..e7c05b085 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -236,6 +236,33 @@ def testB80484938(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB120771563(self): + code = """\ +class A: + + def b(): + d = { + "123456": [{ + "12": "aa" + }, { + "12": "bb" + }, { + "12": "cc", + "1234567890": { + "1234567": [{ + "12": "dd", + "12345": "text 1" + }, { + "12": "ee", + "12345": "text 2" + }] + } + }] + } +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB79462249(self): code = """\ foo.bar(baz, [ From 355f2690dcf5e598b696c3e386cb4af7cf765c30 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 26 Mar 2019 17:07:58 -0700 Subject: [PATCH 370/719] Don't split before a too long dictionary elem A dictionary element in a list that's too long to fit on the line will probably be split itself, so there's no reason to split before it in the list. Closes #678 --- CHANGELOG | 3 ++ yapf/yapflib/format_decision_state.py | 3 +- yapftests/reformatter_basic_test.py | 53 +++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index b35219199..74bbac642 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -15,6 +15,9 @@ to False. - Adjust default SPLIT_PENALTY_AFTER_OPENING_BRACKET. - Re-enable removal of extra lines on the boundaries of formatted regions. +- Adjust list splitting to avoid splitting before a dictionary element, because + those are likely to be split anyway. If we do split, it leads to horrible + looking code. ## [0.26.0] 2019-02-08 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 486be8bce..cba880e58 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -281,7 +281,8 @@ def SurroundedByParens(token): if not self._FitsOnLine(current, tok.matching_bracket): return True - if current.OpensScope() and previous.value == ',': + if (current.OpensScope() and previous.value == ',' and + format_token.Subtype.DICTIONARY_KEY not in current.next_token.subtypes): # If we have a list of tuples, then we can get a similar look as above. If # the full list cannot fit on the line, then we want a split. open_bracket = unwrapped_line.IsSurroundedByBrackets(current) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 2e6fd2eeb..c1e9ae644 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2598,6 +2598,59 @@ def function( finally: style.SetGlobalStyle(style.CreateChromiumStyle()) + def testMultipleDictionariesInList(self): + unformatted_code = """\ +class A: + def b(): + d = { + "123456": [ + { + "12": "aa" + }, + { + "12": "bb" + }, + { + "12": "cc", + "1234567890": { + "1234567": [{ + "12": "dd", + "12345": "text 1" + }, { + "12": "ee", + "12345": "text 2" + }] + } + } + ] + } +""" + expected_formatted_code = """\ +class A: + + def b(): + d = { + "123456": [{ + "12": "aa" + }, { + "12": "bb" + }, { + "12": "cc", + "1234567890": { + "1234567": [{ + "12": "dd", + "12345": "text 1" + }, { + "12": "ee", + "12345": "text 2" + }] + } + }] + } +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From 5bb072f2ba553a6d8d1b29ff62c70ee99de2797f Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 26 Mar 2019 17:41:16 -0700 Subject: [PATCH 371/719] Fix lint errors. --- yapf/yapflib/format_token.py | 3 ++- yapf/yapflib/reformatter.py | 1 + yapftests/blank_line_calculator_test.py | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 9bae9cb6c..9bd2f7027 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -89,6 +89,7 @@ class FormatToken(object): the code. Attributes: + node: The PyTree node this token represents. next_token: The token in the unwrapped line after this token or None if this is the last token in the unwrapped line. previous_token: The token in the unwrapped line before this token or None if @@ -345,7 +346,7 @@ def is_multiline_string(self): """Test if this string is a multiline string. Returns: - A multiline string always ends with triple quotes, so if it is a string + A multiline string always ends with triple quotes, so if it is a string token, inspect the last 3 characters and return True if it is a triple double or triple single quote mark. """ diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 3492ffc54..38de3cbb4 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -114,6 +114,7 @@ def _RetainHorizontalSpacing(uwline): def _RetainRequiredVerticalSpacing(cur_uwline, prev_uwline, lines): + """Retain all vertical spacing between lines.""" if cur_uwline.disable and (not prev_uwline or prev_uwline.disable): # If both lines are disabled we aren't allowed to reformat anything. lines = set() diff --git a/yapftests/blank_line_calculator_test.py b/yapftests/blank_line_calculator_test.py index afc65bdf0..8738c73df 100644 --- a/yapftests/blank_line_calculator_test.py +++ b/yapftests/blank_line_calculator_test.py @@ -380,6 +380,7 @@ def C(): """) code, changed = yapf_api.FormatCode(unformatted_code, lines=[(5, 9)]) self.assertCodeEqual(expected_formatted_code, code) + self.assertTrue(changed) def testLinesRangeRemoveSome(self): unformatted_code = textwrap.dedent(u"""\ From 0006c6241105d7ec2ba7c1baf632238d2afa641a Mon Sep 17 00:00:00 2001 From: deepcommit <48901781+deepcommit@users.noreply.github.com> Date: Sat, 30 Mar 2019 10:37:28 -0700 Subject: [PATCH 372/719] Fixed PYTHON_E231 issues in yapftests/subtype_assigner_test.py --- yapftests/subtype_assigner_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index ef864f83a..8132c6894 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -159,7 +159,7 @@ def testBitwiseOperators(self): ('3', [format_token.Subtype.NONE]), (')', [format_token.Subtype.NONE]), ('>>', {format_token.Subtype.BINARY_OPERATOR}), - ('1', [format_token.Subtype.NONE]),], + ('1', [format_token.Subtype.NONE]), ], ]) # yapf: disable def testArithmeticOperators(self): @@ -201,7 +201,7 @@ def testArithmeticOperators(self): (')', [format_token.Subtype.NONE]), ('//', {format_token.Subtype.BINARY_OPERATOR, format_token.Subtype.M_EXPR_OPERATOR}), - ('1', [format_token.Subtype.NONE]),], + ('1', [format_token.Subtype.NONE]), ], ]) # yapf: disable def testSubscriptColon(self): @@ -234,7 +234,7 @@ def testFunctionCallWithStarExpression(self): ('*', {format_token.Subtype.UNARY_OPERATOR, format_token.Subtype.VARARGS_STAR}), ('b', [format_token.Subtype.NONE]), - (']', [format_token.Subtype.NONE]),], + (']', [format_token.Subtype.NONE]), ], ]) # yapf: disable From 3a929ef803d750eb0de5c8e00427d386fe496110 Mon Sep 17 00:00:00 2001 From: JeongUkJae Date: Wed, 3 Apr 2019 01:20:49 +0900 Subject: [PATCH 373/719] Update README.rst --- README.rst | 105 ++++++++++++++++++++++++++++------------------------- 1 file changed, 55 insertions(+), 50 deletions(-) diff --git a/README.rst b/README.rst index ead684331..4c076833f 100644 --- a/README.rst +++ b/README.rst @@ -23,14 +23,15 @@ are made to remove lint errors from code. This has some obvious limitations. For instance, code that conforms to the PEP 8 guidelines may not be reformatted. But it doesn't mean that the code looks good. -YAPF takes a different approach. It's based off of 'clang-format', developed by -Daniel Jasper. In essence, the algorithm takes the code and reformats it to the -best formatting that conforms to the style guide, even if the original code -didn't violate the style guide. The idea is also similar to the 'gofmt' tool for -the Go programming language: end all holy wars about formatting - if the whole -codebase of a project is simply piped through YAPF whenever modifications are -made, the style remains consistent throughout the project and there's no point -arguing about style in every code review. +YAPF takes a different approach. It's based off of `'clang-format' `_, developed by Daniel Jasper. In essence, +the algorithm takes the code and reformats it to the best formatting that +conforms to the style guide, even if the original code didn't violate the +style guide. The idea is also similar to the `'gofmt' `_ tool for the Go programming language: end all holy wars about +formatting - if the whole codebase of a project is simply piped through YAPF +whenever modifications are made, the style remains consistent throughout the +project and there's no point arguing about style in every code review. The ultimate goal is that the code YAPF produces is as good as the code that a programmer would write if they were following the style guide. It takes away @@ -140,8 +141,8 @@ has been YAPF-formatted. Excluding files from formatting (.yapfignore) --------------------------------------------- -In addition to exclude patterns provided on commandline, YAPF looks for additional -patterns specified in a file named ``.yapfignore`` located in the working directory from +In addition to exclude patterns provided on commandline, YAPF looks for additional +patterns specified in a file named ``.yapfignore`` located in the working directory from which YAPF is invoked. @@ -182,11 +183,12 @@ indentations. YAPF will search for the formatting style in the following manner: 1. Specified on the command line -2. In the `[style]` section of a `.style.yapf` file in either the current +2. In the ``[style]`` section of a ``.style.yapf`` file in either the current directory or one of its parent directories. -3. In the `[yapf]` section of a `setup.cfg` file in either the current +3. In the ``[yapf]`` section of a ``setup.cfg`` file in either the current directory or one of its parent directories. -4. In the `~/.config/yapf/style` file in your home directory. +4. In the ``[style]`` section of a ``~/.config/yapf/style`` file in your home + directory. If none of those files are found, the default style is used (PEP8). @@ -296,7 +298,7 @@ the diff, the default is ````. >>> FormatFile("foo.py") ('a == b\n', 'utf-8') -The ``in-place`` argument saves the reformatted code back to the file: +The ``in_place`` argument saves the reformatted code back to the file: .. code-block:: python @@ -415,13 +417,14 @@ Knobs ``CONTINUATION_ALIGN_STYLE`` The style for continuation alignment. Possible values are: - - SPACE: Use spaces for continuation alignment. This is default behavior. - - FIXED: Use fixed number (CONTINUATION_INDENT_WIDTH) of columns + - ``SPACE``: Use spaces for continuation alignment. This is default + behavior. + - ``FIXED``: Use fixed number (CONTINUATION_INDENT_WIDTH) of columns (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs) for continuation alignment. - - VALIGN-RIGHT: Vertically align continuation lines with indent characters. - Slightly right (one more indent character) if cannot vertically align - continuation lines with indent characters. + - ``VALIGN-RIGHT``: Vertically align continuation lines with indent + characters. Slightly right (one more indent character) if cannot + vertically align continuation lines with indent characters. For options ``FIXED``, and ``VALIGN-RIGHT`` are only available when ``USE_TABS`` is enabled. @@ -495,7 +498,7 @@ Knobs 1 + 2 * 3 - 4 / 5 - will be formatted as follows when configured with ``*,/``: + will be formatted as follows when configured with ``*``, ``/``: .. code-block:: python @@ -515,42 +518,42 @@ Knobs alignment column values; trailing comments within a block will be aligned to the first column value that is greater than the maximum line length within the block). For example: - - With spaces_before_comment=5: - + + With ``spaces_before_comment=5``: + .. code-block:: python - + 1 + 1 # Adding values - + will be formatted as: - + .. code-block:: python - + 1 + 1 # Adding values <-- 5 spaces between the end of the statement and comment - - With spaces_before_comment=15, 20: - + + With ``spaces_before_comment=15, 20``: + .. code-block:: python - + 1 + 1 # Adding values two + two # More adding - + longer_statement # This is a longer statement short # This is a shorter statement - + a_very_long_statement_that_extends_beyond_the_final_column # Comment short # This is a shorter statement - + will be formatted as: - + .. code-block:: python - + 1 + 1 # Adding values <-- end of line comments in block aligned to col 15 two + two # More adding - + longer_statement # This is a longer statement <-- end of line comments in block aligned to col 20 short # This is a shorter statement - + a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length short # This is a shorter statement @@ -561,19 +564,21 @@ Knobs Split before arguments if the argument list is terminated by a comma. ``SPLIT_ALL_COMMA_SEPARATED_VALUES`` - If a comma separated list (dict, list, tuple, or function def) is on a - line that is too long, split such that all elements are on a single line. + If a comma separated list (``dict``, ``list``, ``tuple``, or function + ``def``) is on a line that is too long, split such that all elements + are on a single line. ``SPLIT_BEFORE_BITWISE_OPERATOR`` - Set to True to prefer splitting before '&', '|' or '^' rather than after. + Set to ``True`` to prefer splitting before ``&``, ``|`` or ``^`` rather + than after. ``SPLIT_BEFORE_ARITHMETIC_OPERATOR`` - Set to True to prefer splitting before '+', '-', '*', '/', '//', or '@' - rather than after. + Set to ``True`` to prefer splitting before ``+``, ``-``, ``*``, ``/``, ``//``, + or ``@`` rather than after. ``SPLIT_BEFORE_CLOSING_BRACKET`` - Split before the closing bracket if a list or dict literal doesn't fit on - a single line. + Split before the closing bracket if a ``list`` or ``dict`` literal doesn't + fit on a single line. ``SPLIT_BEFORE_DICT_SET_GENERATOR`` Split before a dictionary or set generator (comp_for). For example, note @@ -587,7 +592,7 @@ Knobs } ``SPLIT_BEFORE_DOT`` - Split before the '.' if we need to split a longer expression: + Split before the ``.`` if we need to split a longer expression: .. code-block:: python @@ -617,8 +622,8 @@ Knobs ``SPLIT_COMPLEX_COMPREHENSION`` For list comprehensions and generator expressions with multiple clauses - (e.g multiple "for" calls, "if" filter expressions) and which need to be - reflowed, split each clause onto its own line. For example: + (e.g multiple ``for`` calls, ``if`` filter expressions) and which need to + be reflowed, split each clause onto its own line. For example: .. code-block:: python @@ -751,8 +756,8 @@ I still get non Pep8 compliant code! Why? ----------------------------------------- YAPF tries very hard to be fully PEP 8 compliant. However, it is paramount -to not risk altering the semantics of your code. Thus, YAPF tries to be as -safe as possible and does not change the token stream +to not risk altering the semantics of your code. Thus, YAPF tries to be as +safe as possible and does not change the token stream (e.g., by adding parenthesis). All these cases however, can be easily fixed manually. For instance, From 780dcc20f48c698bdc5c8e6e32868987409667b7 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 7 Apr 2019 01:43:39 -0700 Subject: [PATCH 374/719] Catch lib2to3's TokenError exception and emit informative message --- CHANGELOG | 2 ++ yapf/__init__.py | 21 +++++++++++++++------ yapftests/yapf_test.py | 6 ++++++ 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 74bbac642..27d72d84f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,8 @@ - `SPLIT_BEFORE_ARITHMETIC_OPERATOR` splits before an arithmetic operator when set. `SPLIT_PENALTY_ARITHMETIC_OPERATOR` allows you to set the split penalty around arithmetic operators. +### Changed +- Catch lib2to3's "TokenError" exception and output a nicer message. ### Fixed - Parse integer lists correctly, removing quotes if the list is within a string. diff --git a/yapf/__init__.py b/yapf/__init__.py index 97a963355..a7e7fc613 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -32,6 +32,8 @@ import os import sys +from lib2to3.pgen2 import tokenize + from yapf.yapflib import errors from yapf.yapflib import file_resources from yapf.yapflib import py3compat @@ -182,12 +184,17 @@ def main(argv): source = [line.rstrip() for line in original_source] source[0] = py3compat.removeBOM(source[0]) - reformatted_source, _ = yapf_api.FormatCode( - py3compat.unicode('\n'.join(source) + '\n'), - filename='', - style_config=style_config, - lines=lines, - verify=args.verify) + + try: + reformatted_source, _ = yapf_api.FormatCode( + py3compat.unicode('\n'.join(source) + '\n'), + filename='', + style_config=style_config, + lines=lines, + verify=args.verify) + except tokenize.TokenError as e: + raise errors.YapfError('%s:%s' % (e.args[1][0], e.args[0])) + file_resources.WriteReformattedCode('', reformatted_source) return 0 @@ -291,6 +298,8 @@ def _FormatFile(filename, file_resources.WriteReformattedCode(filename, reformatted_code, encoding, in_place) return has_change + except tokenize.TokenError as e: + raise errors.YapfError('%s:%s:%s' % (filename, e.args[1][0], e.args[0])) except SyntaxError as e: e.filename = filename raise diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index a676e1940..3313a3f9b 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -24,6 +24,8 @@ import textwrap import unittest +from lib2to3.pgen2 import tokenize + from yapf.yapflib import py3compat from yapf.yapflib import style from yapf.yapflib import yapf_api @@ -1428,6 +1430,10 @@ def testBadSyntax(self): code = ' a = 1\n' self.assertRaises(SyntaxError, yapf_api.FormatCode, code) + def testBadCode(self): + code = 'x = """hello\n' + self.assertRaises(tokenize.TokenError, yapf_api.FormatCode, code) + class DiffIndentTest(unittest.TestCase): From f541d8fbb38f9d203aae37d7c5139c9da0c526ff Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 7 Apr 2019 02:15:26 -0700 Subject: [PATCH 375/719] Split before dictionary argument When a dictionary is the first arugment and doesn't fit on a single line, then split to avoid unreadable formatting. --- CHANGELOG | 4 ++++ yapf/yapflib/format_decision_state.py | 18 ++++++++++++++++++ yapftests/reformatter_buganizer_test.py | 23 +++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 27d72d84f..d45bc27bd 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -20,6 +20,10 @@ - Adjust list splitting to avoid splitting before a dictionary element, because those are likely to be split anyway. If we do split, it leads to horrible looking code. +- Dictionary arguments were broken in a recent version. It resulted in + unreadable formatting, where the remaining arguments were indented far more + than the dictionary. Fixed so that if the dictionary is the first argument in + a function call and doesn't fit on a single line, then it forces a split. ## [0.26.0] 2019-02-08 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index cba880e58..a322d38c4 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -416,6 +416,24 @@ def SurroundedByParens(token): return True pprevious = previous.previous_token + + # A function call with a dictionary as its first argument may result in + # unreadable formatting if the dictionary spans multiple lines. The + # dictionary itself is formatted just fine, but the remaning arguments are + # indented too far: + # + # function_call({ + # KEY_1: 'value one', + # KEY_2: 'value two', + # }, + # default=False) + if (current.value == '{' and previous.value == '(' and pprevious and + pprevious.is_name): + dict_end = current.matching_bracket + next_token = dict_end.next_token + if next_token.value == ',' and not self._FitsOnLine(current, dict_end): + return True + if (current.is_name and pprevious and pprevious.is_name and previous.value == '('): diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 4d555e35b..768b6bf3f 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,29 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB124415889(self): + code = """\ +class _(): + + def run_queue_scanners(): + return xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( + { + components.NAME.FNOR: True, + components.NAME.DEVO: True, + }, + default=False) + + def modules_to_install(): + modules = DeepCopy(GetDef({})) + modules.update({ + 'xxxxxxxxxxxxxxxxxxxx': + GetDef('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz', None), + }) + return modules +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB73166511(self): code = """\ def _(): From 190df35267b1421c510a4cd3782ee9d064264f24 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 7 Apr 2019 02:48:45 -0700 Subject: [PATCH 376/719] Increase penalty for splitting items in a list This prevents bad formatting when it could be better to split at a more gross level. Closes #701 --- CHANGELOG | 2 ++ yapf/yapflib/split_penalty.py | 3 ++- yapftests/reformatter_basic_test.py | 22 +++++++++++----------- yapftests/reformatter_buganizer_test.py | 4 ++-- yapftests/reformatter_pep8_test.py | 14 ++++++++++++++ 5 files changed, 31 insertions(+), 14 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d45bc27bd..0aa6412f8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -24,6 +24,8 @@ unreadable formatting, where the remaining arguments were indented far more than the dictionary. Fixed so that if the dictionary is the first argument in a function call and doesn't fit on a single line, then it forces a split. +- Improve the connectiveness between items in a list. This prevents random + splitting when it's not 100% necessary. ## [0.26.0] 2019-02-08 ### Added diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 3df8f2ec4..6c6a79fcb 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -31,6 +31,7 @@ VERY_STRONGLY_CONNECTED = 3500 STRONGLY_CONNECTED = 3000 CONNECTED = 500 +TOGETHER = 100 OR_TEST = 1000 AND_TEST = 1100 @@ -481,7 +482,7 @@ def Visit_testlist_gexp(self, node): # pylint: disable=invalid-name prev_was_comma = True else: if prev_was_comma: - _SetSplitPenalty(pytree_utils.FirstLeafNode(child), 0) + _SetSplitPenalty(pytree_utils.FirstLeafNode(child), TOGETHER) prev_was_comma = False ############################################################################ diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index c1e9ae644..60d7cb673 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1346,7 +1346,7 @@ def _(): return True """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) def testDictSetGenerator(self): code = textwrap.dedent("""\ @@ -1896,8 +1896,8 @@ def _(): if True: if True: if True: - boxes[id_] = np.concatenate((points.min(axis=0), - qoints.max(axis=0))) + boxes[id_] = np.concatenate( + (points.min(axis=0), qoints.max(axis=0))) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2202,7 +2202,7 @@ def testNotInParams(self): not True) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) def testNamedAssignNotAtEndOfLine(self): unformatted_code = textwrap.dedent("""\ @@ -2220,7 +2220,7 @@ def _(): pass """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) def testBlankLineBeforeClassDocstring(self): unformatted_code = textwrap.dedent('''\ @@ -2245,7 +2245,7 @@ def __init__(self): pass ''') uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) try: style.SetGlobalStyle( @@ -2301,7 +2301,7 @@ def foobar(): pass ''') uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) try: style.SetGlobalStyle( @@ -2346,7 +2346,7 @@ def f(): ('a string that may be too long %s' % 'M15')) """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) def testSubscriptExpression(self): code = textwrap.dedent("""\ @@ -2380,7 +2380,7 @@ def foo(): ] """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) def testEllipses(self): unformatted_code = textwrap.dedent("""\ @@ -2392,7 +2392,7 @@ def testEllipses(self): Y = X if ... else X """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) def testPseudoParens(self): unformatted_code = """\ @@ -2410,7 +2410,7 @@ def testPseudoParens(self): } """ uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) def testSplittingBeforeFirstArgumentOnFunctionCall(self): """Tests split_before_first_argument on a function call.""" diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 768b6bf3f..3a6ef3c71 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -1172,8 +1172,8 @@ def testB29908765(self): class _(): def __repr__(self): - return '' % (self._id, - self._stub._stub.rpc_channel().target()) # pylint:disable=protected-access + return '' % ( + self._id, self._stub._stub.rpc_channel().target()) # pylint:disable=protected-access """) uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 05d2cf090..1b79a7220 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -477,6 +477,20 @@ def _(): finally: style.SetGlobalStyle(style.CreatePEP8Style()) + def testListSplitting(self): + unformatted_code = """\ +foo([(1,1), (1,1), (1,1), (1,1), (1,1), (1,1), (1,1), + (1,1), (1,1), (1,1), (1,1), (1,1), (1,1), (1,1), + (1,10), (1,11), (1, 10), (1,11), (10,11)]) +""" + expected_code = """\ +foo([(1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), + (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 10), (1, 11), (1, 10), + (1, 11), (10, 11)]) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From 0c84a27f90b82e74074aed7cd993f4238942846b Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 7 Apr 2019 03:41:17 -0700 Subject: [PATCH 377/719] Keep comments attached to prev objects. A comment may be in the "prefix" of a pytree node, but is actually attached to the object before the node. E.g., if the node is a function or class, we don't want to comment to appear to be attached to it instead of the original object. --- CHANGELOG | 2 ++ yapf/yapflib/comment_splicer.py | 10 ++++++++++ yapftests/reformatter_buganizer_test.py | 13 +++++++++++++ yapftests/yapf_test.py | 16 ++++++++-------- 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0aa6412f8..f2cb4d73b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -26,6 +26,8 @@ a function call and doesn't fit on a single line, then it forces a split. - Improve the connectiveness between items in a list. This prevents random splitting when it's not 100% necessary. +- Don't remove a comment attached to a previous object just because it's part + of the "prefix" of a function/class node. ## [0.26.0] 2019-02-08 ### Added diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index 8717394f0..028d68a4f 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -152,6 +152,16 @@ def _VisitNodeRec(node): # parent to insert into. See comments above # _STANDALONE_LINE_NODES for more details. node_with_line_parent = _FindNodeWithStandaloneLineParent(child) + + if pytree_utils.NodeName( + node_with_line_parent.parent) in {'funcdef', 'classdef'}: + # Keep a comment that's not attached to a function or class + # next to the object it is attached to. + comment_end = ( + comment_lineno + comment_prefix.rstrip('\n').count('\n')) + if comment_end < node_with_line_parent.lineno - 1: + node_with_line_parent = node_with_line_parent.parent + pytree_utils.InsertNodesBefore( _CreateCommentsFromPrefix( comment_prefix, comment_lineno, 0, standalone=True), diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 3a6ef3c71..a4c0b457e 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,19 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB122541552(self): + code = """\ +# pylint: disable=g-explicit-bool-comparison,singleton-comparison +_QUERY = account.Account.query(account.Account.enabled == True) +# pylint: enable=g-explicit-bool-comparison,singleton-comparison + + +def _(): + pass +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB124415889(self): code = """\ class _(): diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 3313a3f9b..784f2d7a2 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -31,6 +31,7 @@ from yapf.yapflib import yapf_api from yapftests import utils +from yapftests import yapf_test_helper ROOT_DIR = os.path.dirname(os.path.abspath(os.path.dirname(__file__))) @@ -38,12 +39,12 @@ YAPF_BINARY = [sys.executable, '-m', 'yapf', '--verify', '--no-local-style'] -class FormatCodeTest(unittest.TestCase): +class FormatCodeTest(yapf_test_helper.YAPFTest): def _Check(self, unformatted_code, expected_formatted_code): formatted_code, _ = yapf_api.FormatCode( unformatted_code, style_config='chromium') - self.assertEqual(expected_formatted_code, formatted_code) + self.assertCodeEqual(expected_formatted_code, formatted_code) def testSimple(self): unformatted_code = textwrap.dedent("""\ @@ -1461,7 +1462,7 @@ def testSimple(self): self._Check(unformatted_code, expected_formatted_code) -class HorizontallyAlignedTrailingCommentsTest(unittest.TestCase): +class HorizontallyAlignedTrailingCommentsTest(yapf_test_helper.YAPFTest): @staticmethod def _OwnStyle(): @@ -1476,7 +1477,7 @@ def _OwnStyle(): def _Check(self, unformatted_code, expected_formatted_code): formatted_code, _ = yapf_api.FormatCode( unformatted_code, style_config=style.SetGlobalStyle(self._OwnStyle())) - self.assertEqual(expected_formatted_code, formatted_code) + self.assertCodeEqual(expected_formatted_code, formatted_code) def testSimple(self): unformatted_code = textwrap.dedent("""\ @@ -1543,7 +1544,7 @@ def testBlockFuncSuffix(self): func(2) # Line 2 # Line 3 func(3) # Line 4 - # Line 5 - SpliceComments makes this a new block + # Line 5 # Line 6 def Func(): @@ -1554,9 +1555,8 @@ def Func(): func(2) # Line 2 # Line 3 func(3) # Line 4 - - # Line 5 - SpliceComments makes this a new block - # Line 6 + # Line 5 + # Line 6 def Func(): From cc0492917387a9010b45f6da31f4f8e301b48a36 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 7 Apr 2019 03:44:52 -0700 Subject: [PATCH 378/719] Bump version to 0.27.0 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f2cb4d73b..480203fb4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.27.0] UNRELEASED +## [0.27.0] 2019-04-07 ### Added - `SPLIT_BEFORE_ARITHMETIC_OPERATOR` splits before an arithmetic operator when set. `SPLIT_PENALTY_ARITHMETIC_OPERATOR` allows you to set the split penalty diff --git a/yapf/__init__.py b/yapf/__init__.py index a7e7fc613..a9e17c60e 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -40,7 +40,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.26.0' +__version__ = '0.27.0' def main(argv): From c4fc441724dd3f473910429d3233c169c2320e1d Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Mon, 8 Apr 2019 11:17:09 -0700 Subject: [PATCH 379/719] Correctly follow Google style for dict indentation http://google.github.io/styleguide/pyguide.html#34-indentation --- yapf/yapflib/style.py | 1 + 1 file changed, 1 insertion(+) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 359246e4a..7954c34fb 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -396,6 +396,7 @@ def CreateGoogleStyle(): style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False style['BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'] = True style['COLUMN_LIMIT'] = 80 + style['INDENT_DICTIONARY_VALUE'] = True style['INDENT_WIDTH'] = 4 style['I18N_COMMENT'] = r'#\..*' style['I18N_FUNCTION_CALL'] = ['N_', '_'] From 36dceb5b73b13dc2398925c24f342089fd752c7c Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Mon, 8 Apr 2019 14:06:53 -0700 Subject: [PATCH 380/719] Update CHANGELOG --- CHANGELOG | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 480203fb4..46b908258 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.28.0] UNRELEASED +### Changed +- Set `INDENT_DICTIONARY_VALUE` for Google style. + ## [0.27.0] 2019-04-07 ### Added - `SPLIT_BEFORE_ARITHMETIC_OPERATOR` splits before an arithmetic operator when From ab12ccdf33b2d45c424995c37b42df4345213eb4 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 9 Apr 2019 03:00:56 -0700 Subject: [PATCH 381/719] Adjust newlines if nested class/func Closes #645 --- CHANGELOG | 5 +++- yapf/__init__.py | 6 ++--- yapf/yapflib/reformatter.py | 15 +++++++---- yapftests/reformatter_pep8_test.py | 41 ++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 9 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 46b908258..1821eab35 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,9 +2,12 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.28.0] UNRELEASED +## [0.27.1] UNRELEASED ### Changed - Set `INDENT_DICTIONARY_VALUE` for Google style. +### Fixed +- `BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=False` wasn't honored because the + number of newlines was erroneously calculated beforehand. ## [0.27.0] 2019-04-07 ### Added diff --git a/yapf/__init__.py b/yapf/__init__.py index a9e17c60e..fa9c60ed9 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -121,16 +121,16 @@ def main(argv): '-p', '--parallel', action='store_true', - help=('Run yapf in parallel when formatting multiple files. Requires ' + help=('run yapf in parallel when formatting multiple files. Requires ' 'concurrent.futures in Python 2.X')) parser.add_argument( '-vv', '--verbose', action='store_true', - help='Print out file names while processing') + help='print out file names while processing') parser.add_argument( - 'files', nargs='*', help='Reads from stdin when no files are specified.') + 'files', nargs='*', help='reads from stdin when no files are specified.') args = parser.parse_args(argv[1:]) if args.version: diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 38de3cbb4..6638cc700 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -587,11 +587,11 @@ def _FormatFirstToken(first_token, indent_depth, prev_uwline, final_lines): TWO_BLANK_LINES = 3 -def _IsClassOrDef(uwline): - if uwline.first.value in {'class', 'def'}: +def _IsClassOrDef(tok): + if tok.value in {'class', 'def', '@'}: return True - - return [t.value for t in uwline.tokens[:2]] == ['async', 'def'] + return (tok.next_token and tok.value == 'async' and + tok.next_token.value == 'def') def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, @@ -638,6 +638,11 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, # Separate a class or function from the module-level docstring with # appropriate number of blank lines. return 1 + style.Get('BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION') + if (not style.Get('BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF') and + _IsClassOrDef(first_token)): + pytree_utils.SetNodeAnnotation(first_token.node, + pytree_utils.Annotation.NEWLINES, None) + return NO_BLANK_LINES if _NoBlankLinesBeforeCurrentToken(prev_last_token.value, first_token, prev_last_token): return NO_BLANK_LINES @@ -672,7 +677,7 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, pytree_utils.Annotation.NEWLINES, None) return NO_BLANK_LINES - elif _IsClassOrDef(prev_uwline): + elif _IsClassOrDef(prev_uwline.first): if not style.Get('BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'): pytree_utils.SetNodeAnnotation(first_token.node, pytree_utils.Annotation.NEWLINES, None) diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 1b79a7220..92c2a2913 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -491,6 +491,47 @@ def testListSplitting(self): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) + def testNoBlankLineBeforeNestedFuncOrClass(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: pep8, ' + 'blank_line_before_nested_class_or_def: false}')) + + unformatted_code = '''\ +def normal_function(): + """Return the nested function.""" + + def nested_function(): + """Do nothing just nest within.""" + + @nested(klass) + class nested_class(): + pass + + pass + + return nested_function +''' + expected_formatted_code = '''\ +def normal_function(): + """Return the nested function.""" + def nested_function(): + """Do nothing just nest within.""" + @nested(klass) + class nested_class(): + pass + + pass + + return nested_function +''' + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreatePEP8Style()) + if __name__ == '__main__': unittest.main() From bde38af4080c6dd33f7ad28fed60faf6fed9398a Mon Sep 17 00:00:00 2001 From: Sergio Giro Date: Wed, 17 Apr 2019 08:51:56 +0100 Subject: [PATCH 382/719] Add knob SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES (#1) Add knob SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES The existing knob SPLIT_ALL_COMMA_SEPARATED_VALUES is overly aggresive in that, if an argument list (or, more generally, a container) needs splitting, then all subexpressions will be split as well. For instance, in ``` abcdef(aReallyLongThing, b=(c,d)) ``` if the line needs splitting because of `aReallyLongThing`, then it will produce ``` abcdef( aReallyLongThing, b=(c, d)) ``` I've seen terrible things like ``` argument: [Int, Int] ``` in function definitions with many arguments (even if the second `Int` fits in the line). The new knob checks if a container (argument list, list literal, etc) fits in a line and avoids breaking if so, producing ``` abcdef( aReallyLongThing, b=(c, d)) ``` which makes more sense (to me at least). See https://github.com/prodo-ai/plz/pull/248 for an example of a codebase reformatted with the new knob (plus `split_before_first_argument`). Nice, isn't it? --- yapf/yapflib/format_decision_state.py | 28 ++++++-- yapf/yapflib/style.py | 5 ++ yapftests/reformatter_basic_test.py | 100 ++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 4 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index a322d38c4..4965d60e9 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -176,6 +176,20 @@ def MustSplit(self): if style.Get('SPLIT_ALL_COMMA_SEPARATED_VALUES') and previous.value == ',': return True + if style.Get( + 'SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES') and previous.value == ',': + # Avoid breaking in a container that fits in the current line if possible + opening = _GetOpeningBracket(current) + + # Can't find opening bracket, behave the same way as + # SPLIT_ALL_COMMA_SEPARATED_VALUES + if not opening: + return True + + matching_bracket = opening.matching_bracket + # If the container doesn't fit in the current line, must split + return not self._ContainerFitsOnStartLine(opening) + if (self.stack[-1].split_before_closing_bracket and current.value in '}]' and style.Get('SPLIT_BEFORE_CLOSING_BRACKET')): # Split before the closing bracket if we can. @@ -370,10 +384,7 @@ def SurroundedByParens(token): opening = _GetOpeningBracket(current) if opening: - arglist_length = ( - opening.matching_bracket.total_length - opening.total_length + - self.stack[-1].indent) - return arglist_length > self.column_limit + return not self._ContainerFitsOnStartLine(opening) if (current.value not in '{)' and previous.value == '(' and self._ArgumentListHasDictionaryEntry(current)): @@ -935,6 +946,15 @@ def _ArgumentListHasDictionaryEntry(self, token): token = token.next_token return False + def _ContainerFitsOnStartLine(self, opening): + """Check if the container can fit on its starting line. + + Arguments: + opening: (FormatToken) The unwrapped line we're currently processing. + """ + return (opening.matching_bracket.total_length - opening.total_length + + self.stack[-1].indent) <= self.column_limit + _COMPOUND_STMTS = frozenset( {'for', 'while', 'if', 'elif', 'with', 'except', 'def', 'class'}) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 7954c34fb..48b3984c0 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -239,6 +239,9 @@ def method(): comma."""), SPLIT_ALL_COMMA_SEPARATED_VALUES=textwrap.dedent("""\ Split before arguments"""), + SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=textwrap.dedent("""\ + Split before arguments, but do not split all subexpressions recursively + (unless needed)."""), SPLIT_BEFORE_ARITHMETIC_OPERATOR=textwrap.dedent("""\ Set to True to prefer splitting before '+', '-', '*', '/', '//', or '@' rather than after."""), @@ -367,6 +370,7 @@ def CreatePEP8Style(): SPACES_BEFORE_COMMENT=2, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False, SPLIT_ALL_COMMA_SEPARATED_VALUES=False, + SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=False, SPLIT_BEFORE_ARITHMETIC_OPERATOR=False, SPLIT_BEFORE_BITWISE_OPERATOR=True, SPLIT_BEFORE_CLOSING_BRACKET=True, @@ -543,6 +547,7 @@ def _IntOrIntListConverter(s): SPACES_BEFORE_COMMENT=_IntOrIntListConverter, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter, SPLIT_ALL_COMMA_SEPARATED_VALUES=_BoolConverter, + SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=_BoolConverter, SPLIT_BEFORE_ARITHMETIC_OPERATOR=_BoolConverter, SPLIT_BEFORE_BITWISE_OPERATOR=_BoolConverter, SPLIT_BEFORE_CLOSING_BRACKET=_BoolConverter, diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 60d7cb673..a7d5af13d 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -43,6 +43,8 @@ def testSplittingAllArgs(self): "whatever": 120 } """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) unformatted_code = textwrap.dedent("""\ def foo(long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args): pass @@ -77,6 +79,104 @@ def foo(long_arg, """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + # There is a test for split_all_top_level_comma_separated_values, with + # different expected value + unformatted_code = textwrap.dedent("""\ + someLongFunction(this_is_a_very_long_parameter, + abc=(a, this_will_just_fit_xxxxxxx)) + """) + expected_formatted_code = textwrap.dedent("""\ + someLongFunction( + this_is_a_very_long_parameter, + abc=(a, + this_will_just_fit_xxxxxxx)) + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testSplittingTopLevelAllArgs(self): + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{split_all_top_level_comma_separated_values: true, column_limit: 40}' + )) + # Works the same way as split_all_comma_separated_values + unformatted_code = textwrap.dedent("""\ + responseDict = {"timestamp": timestamp, "someValue": value, "whatever": 120} + """) + expected_formatted_code = textwrap.dedent("""\ + responseDict = { + "timestamp": timestamp, + "someValue": value, + "whatever": 120 + } + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + # Works the same way as split_all_comma_separated_values + unformatted_code = textwrap.dedent("""\ + def foo(long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def foo(long_arg, + really_long_arg, + really_really_long_arg, + cant_keep_all_these_args): + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + # Works the same way as split_all_comma_separated_values + unformatted_code = textwrap.dedent("""\ + foo_tuple = [long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args] + """) + expected_formatted_code = textwrap.dedent("""\ + foo_tuple = [ + long_arg, + really_long_arg, + really_really_long_arg, + cant_keep_all_these_args + ] + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + # Works the same way as split_all_comma_separated_values + unformatted_code = textwrap.dedent("""\ + foo_tuple = [short, arg] + """) + expected_formatted_code = textwrap.dedent("""\ + foo_tuple = [short, arg] + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + # There is a test for split_all_comma_separated_values, with different + # expected value + unformatted_code = textwrap.dedent("""\ + someLongFunction(this_is_a_very_long_parameter, + abc=(a, this_will_just_fit_xxxxxxx)) + """) + expected_formatted_code = textwrap.dedent("""\ + someLongFunction( + this_is_a_very_long_parameter, + abc=(a, this_will_just_fit_xxxxxxx)) + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + actual_formatted_code = reformatter.Reformat(uwlines) + self.assertEqual(40, len(actual_formatted_code.splitlines()[-1])) + self.assertCodeEqual(expected_formatted_code, actual_formatted_code) + + unformatted_code = textwrap.dedent("""\ + someLongFunction(this_is_a_very_long_parameter, + abc=(a, this_will_not_fit_xxxxxxxxx)) + """) + expected_formatted_code = textwrap.dedent("""\ + someLongFunction( + this_is_a_very_long_parameter, + abc=(a, + this_will_not_fit_xxxxxxxxx)) + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSimpleFunctionsWithTrailingComments(self): unformatted_code = textwrap.dedent("""\ From 718191c9a87a445315c943e387bf38ddb9fe7ccf Mon Sep 17 00:00:00 2001 From: Sergio Giro Date: Wed, 17 Apr 2019 11:07:58 +0100 Subject: [PATCH 383/719] Tests: exercise the case where there is no opening bracket --- yapf/yapflib/format_decision_state.py | 1 - yapftests/reformatter_basic_test.py | 12 ++++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 4965d60e9..74adbaa11 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -186,7 +186,6 @@ def MustSplit(self): if not opening: return True - matching_bracket = opening.matching_bracket # If the container doesn't fit in the current line, must split return not self._ContainerFitsOnStartLine(opening) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index a7d5af13d..be3fbbcc9 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -178,6 +178,18 @@ def foo(long_arg, uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + # Exercise the case where there's no opening bracket (for a, b) + unformatted_code = textwrap.dedent("""\ + a, b = f( + a_very_long_parameter, yet_another_one, and_another) + """) + expected_formatted_code = textwrap.dedent("""\ + a, b = f( + a_very_long_parameter, yet_another_one, and_another) + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testSimpleFunctionsWithTrailingComments(self): unformatted_code = textwrap.dedent("""\ def g(): # Trailing comment From 4d878975b976408578b02f8bf279a301bff69747 Mon Sep 17 00:00:00 2001 From: Sergio Giro Date: Wed, 24 Apr 2019 09:49:49 +0100 Subject: [PATCH 384/719] Knob SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES. Update README and CHANGELOG --- CHANGELOG | 5 +++++ README.rst | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 1821eab35..48dd45fac 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,11 @@ # This project adheres to [Semantic Versioning](http://semver.org/). ## [0.27.1] UNRELEASED +### Added +- New knob `SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES` is a variation on + `SPLIT_ALL_COMMA_SEPARATED_VALUES` in which, if a subexpression with comma + fits in its starting line, then the subexpression is not split (thus avoiding + unnecessary splits). ### Changed - Set `INDENT_DICTIONARY_VALUE` for Google style. ### Fixed diff --git a/README.rst b/README.rst index ead684331..8dcb0087e 100644 --- a/README.rst +++ b/README.rst @@ -564,6 +564,26 @@ Knobs If a comma separated list (dict, list, tuple, or function def) is on a line that is too long, split such that all elements are on a single line. +``SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES`` + Variation on ``SPLIT_ALL_COMMA_SEPARATED_VALUES`` in which, if a + subexpression with comma fits in its starting line, then the subexpression + is not split. This avoids splits like the one for ``b`` in this code: + + .. code-block:: python + + abcdef( + aReallyLongThing: int, + b: [Int, + Int]) + + With the new knob this is split as: + + .. code-block:: python + + abcdef( + aReallyLongThing: int, + b: [Int, Int]) + ``SPLIT_BEFORE_BITWISE_OPERATOR`` Set to True to prefer splitting before '&', '|' or '^' rather than after. From bc2a2d16f8d26c78b325c06805b5846e34343dae Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 24 Apr 2019 02:00:50 -0700 Subject: [PATCH 385/719] Update README.rst --- README.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 8dcb0087e..10def1df9 100644 --- a/README.rst +++ b/README.rst @@ -566,8 +566,9 @@ Knobs ``SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES`` Variation on ``SPLIT_ALL_COMMA_SEPARATED_VALUES`` in which, if a - subexpression with comma fits in its starting line, then the subexpression - is not split. This avoids splits like the one for ``b`` in this code: + subexpression with a comma fits in its starting line, then the + subexpression is not split. This avoids splits like the one for + ``b`` in this code: .. code-block:: python From b61bde71722670ce3d49042409bb593c2cb97b79 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 24 Apr 2019 02:01:17 -0700 Subject: [PATCH 386/719] Update CHANGELOG --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 48dd45fac..9ca199c63 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,7 +5,7 @@ ## [0.27.1] UNRELEASED ### Added - New knob `SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES` is a variation on - `SPLIT_ALL_COMMA_SEPARATED_VALUES` in which, if a subexpression with comma + `SPLIT_ALL_COMMA_SEPARATED_VALUES` in which, if a subexpression with a comma fits in its starting line, then the subexpression is not split (thus avoiding unnecessary splits). ### Changed From fa7ae496cbeb62d6c58251cb0ee02a7a5d17daea Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 24 Apr 2019 02:07:14 -0700 Subject: [PATCH 387/719] Update format_decision_state.py --- yapf/yapflib/format_decision_state.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 74adbaa11..24ebdff0d 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -176,8 +176,8 @@ def MustSplit(self): if style.Get('SPLIT_ALL_COMMA_SEPARATED_VALUES') and previous.value == ',': return True - if style.Get( - 'SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES') and previous.value == ',': + if (style.Get('SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES') and + previous.value == ','): # Avoid breaking in a container that fits in the current line if possible opening = _GetOpeningBracket(current) @@ -948,8 +948,11 @@ def _ArgumentListHasDictionaryEntry(self, token): def _ContainerFitsOnStartLine(self, opening): """Check if the container can fit on its starting line. - Arguments: - opening: (FormatToken) The unwrapped line we're currently processing. + Arguments: + opening: (FormatToken) The unwrapped line we're currently processing. + + Returns: + True if the container fits on the start line. """ return (opening.matching_bracket.total_length - opening.total_length + self.stack[-1].indent) <= self.column_limit From e876f12dc05014772d3cfbf6e710319b347e08cc Mon Sep 17 00:00:00 2001 From: Oleg Butuzov Date: Fri, 10 May 2019 14:11:55 +0300 Subject: [PATCH 388/719] `spaces_before_comment` parsing for `--style-help` #723 --- CONTRIBUTORS | 1 + yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 62e2a5f21..284b13f3c 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -13,3 +13,4 @@ Bill Wendling Eli Bendersky Sam Clegg Ɓukasz Langa +Oleg Butuzov diff --git a/yapf/__init__.py b/yapf/__init__.py index fa9c60ed9..d88d15cee 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -149,7 +149,7 @@ def main(argv): print('#', line and ' ' or '', line, sep='') option_value = style.Get(option) if isinstance(option_value, set) or isinstance(option_value, list): - option_value = ', '.join(option_value) + option_value = ', '.join(map(str, option_value)) print(option.lower(), '=', option_value, sep='') print() return 0 From 1256ac85a5017da91916d3af6fb3539a9b4d07dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9rome=20Perrin?= Date: Fri, 31 May 2019 15:51:09 +0900 Subject: [PATCH 389/719] README: fix restructured text syntax --- README.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index b139e5d7b..995b3324a 100644 --- a/README.rst +++ b/README.rst @@ -575,19 +575,19 @@ Knobs ``b`` in this code: .. code-block:: python - - abcdef( - aReallyLongThing: int, - b: [Int, - Int]) + + abcdef( + aReallyLongThing: int, + b: [Int, + Int]) With the new knob this is split as: .. code-block:: python - - abcdef( - aReallyLongThing: int, - b: [Int, Int]) + + abcdef( + aReallyLongThing: int, + b: [Int, Int]) ``SPLIT_BEFORE_BITWISE_OPERATOR`` Set to ``True`` to prefer splitting before ``&``, ``|`` or ``^`` rather From 73b92fe0c63e56ba912a4cfa871e769df91f89aa Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 21 Jun 2019 11:44:32 -0700 Subject: [PATCH 390/719] Don't increase split penalty on 'lambda' keyword If a lambda expression is an argument to a function (common), then we should be able to split before it without hinderance. --- CHANGELOG | 3 +++ yapf/yapflib/format_decision_state.py | 2 +- yapf/yapflib/split_penalty.py | 4 ++-- yapftests/reformatter_buganizer_test.py | 11 +++++++++++ yapftests/split_penalty_test.py | 4 ++-- yapftests/subtype_assigner_test.py | 6 +++--- 6 files changed, 22 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9ca199c63..61be588dd 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,9 @@ ### Fixed - `BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=False` wasn't honored because the number of newlines was erroneously calculated beforehand. +- Lambda expressions shouldn't have an increased split penalty applied to the + 'lambda' keyword. This prevents them from being properly formatted when they're + arguments to functions. ## [0.27.0] 2019-04-07 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 24ebdff0d..ab7a40b20 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -950,7 +950,7 @@ def _ContainerFitsOnStartLine(self, opening): Arguments: opening: (FormatToken) The unwrapped line we're currently processing. - + Returns: True if the container fits on the start line. """ diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 6c6a79fcb..7f86d96b3 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -129,9 +129,9 @@ def Visit_lambdef(self, node): # pylint: disable=invalid-name break if allow_multiline_lambdas: - _SetStronglyConnected(node) + _SetExpressionPenalty(node, STRONGLY_CONNECTED) else: - _SetVeryStronglyConnected(node) + _SetExpressionPenalty(node, VERY_STRONGLY_CONNECTED) def Visit_parameters(self, node): # pylint: disable=invalid-name # parameters ::= '(' [typedargslist] ')' diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index f1280733f..935f98e29 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,17 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB26521719(self): + code = """\ +class _(): + + def _(self): + self.stubs.Set(some_type_of_arg, 'ThisIsAStringArgument', + lambda *unused_args, **unused_kwargs: fake_resolver) +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB122541552(self): code = """\ # pylint: disable=g-explicit-bool-comparison,singleton-comparison diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index efcebfb22..895445cfc 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -139,7 +139,7 @@ class B(A): """) tree = self._ParseAndComputePenalties(code) self._CheckPenalties(tree, [ - ('lambda', VERY_STRONGLY_CONNECTED), + ('lambda', None), ('a', VERY_STRONGLY_CONNECTED), (',', VERY_STRONGLY_CONNECTED), ('b', VERY_STRONGLY_CONNECTED), @@ -180,7 +180,7 @@ def testStronglyConnected(self): (',', None), ('y', None), ('(', UNBREAKABLE), - ('lambda', VERY_STRONGLY_CONNECTED), + ('lambda', STRONGLY_CONNECTED), ('a', VERY_STRONGLY_CONNECTED), (':', VERY_STRONGLY_CONNECTED), ('23', VERY_STRONGLY_CONNECTED), diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index 8132c6894..ef864f83a 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -159,7 +159,7 @@ def testBitwiseOperators(self): ('3', [format_token.Subtype.NONE]), (')', [format_token.Subtype.NONE]), ('>>', {format_token.Subtype.BINARY_OPERATOR}), - ('1', [format_token.Subtype.NONE]), ], + ('1', [format_token.Subtype.NONE]),], ]) # yapf: disable def testArithmeticOperators(self): @@ -201,7 +201,7 @@ def testArithmeticOperators(self): (')', [format_token.Subtype.NONE]), ('//', {format_token.Subtype.BINARY_OPERATOR, format_token.Subtype.M_EXPR_OPERATOR}), - ('1', [format_token.Subtype.NONE]), ], + ('1', [format_token.Subtype.NONE]),], ]) # yapf: disable def testSubscriptColon(self): @@ -234,7 +234,7 @@ def testFunctionCallWithStarExpression(self): ('*', {format_token.Subtype.UNARY_OPERATOR, format_token.Subtype.VARARGS_STAR}), ('b', [format_token.Subtype.NONE]), - (']', [format_token.Subtype.NONE]), ], + (']', [format_token.Subtype.NONE]),], ]) # yapf: disable From a586d2c34338882a5f6aba332cfa3ffd464a7ca7 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 21 Jun 2019 12:56:22 -0700 Subject: [PATCH 391/719] A disabled comment with continuation markers shouldn't adjust the line numbering --- CHANGELOG | 1 + yapf/yapflib/reformatter.py | 3 ++- yapftests/yapf_test.py | 23 +++++++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 61be588dd..d39f07990 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,7 @@ - Lambda expressions shouldn't have an increased split penalty applied to the 'lambda' keyword. This prevents them from being properly formatted when they're arguments to functions. +- A comment with continuation markers (??) shouldn't mess with the lineno count. ## [0.27.0] 2019-04-07 ### Added diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 6638cc700..91304f584 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -122,6 +122,7 @@ def _RetainRequiredVerticalSpacing(cur_uwline, prev_uwline, lines): prev_tok = None if prev_uwline is not None: prev_tok = prev_uwline.last + for cur_tok in cur_uwline.tokens: _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines) @@ -152,7 +153,7 @@ def _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines): else: cur_lineno = cur_tok.lineno - if prev_tok.value.endswith('\\'): + if not prev_tok.is_comment and prev_tok.value.endswith('\\'): prev_lineno += prev_tok.value.count('\n') required_newlines = cur_lineno - prev_lineno diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 784f2d7a2..8181d7104 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -840,6 +840,29 @@ def g(): self.assertYapfReformats( unformatted_code, unformatted_code, extra_options=['--lines', '2-2']) + def testVerticalSpacingWithCommentWithContinuationMarkers(self): + unformatted_code = """\ +# \\ +# \\ +# \\ + +x = { +} +""" + expected_formatted_code = """\ +# \\ +# \\ +# \\ + +x = { +} +""" + self.assertYapfReformats( + unformatted_code, + expected_formatted_code, + extra_options=['--lines', '1-1']) + + def testRetainingSemicolonsWhenSpecifyingLines(self): unformatted_code = textwrap.dedent("""\ a = line_to_format From 902bde39be72f51eafc24e449a261da88316eff5 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 21 Jun 2019 13:07:43 -0700 Subject: [PATCH 392/719] reformat --- yapftests/yapf_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 8181d7104..a257200f6 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -862,7 +862,6 @@ def testVerticalSpacingWithCommentWithContinuationMarkers(self): expected_formatted_code, extra_options=['--lines', '1-1']) - def testRetainingSemicolonsWhenSpecifyingLines(self): unformatted_code = textwrap.dedent("""\ a = line_to_format From 6301a8717da792d3f589b44598577a70b4e19007 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 27 Jun 2019 10:31:34 -0700 Subject: [PATCH 393/719] Emit unformatted only if "pylint: disable" is at the end of the line --- CHANGELOG | 3 +++ yapf/yapflib/reformatter.py | 5 +---- yapftests/reformatter_buganizer_test.py | 13 +++++++++++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d39f07990..9b4965112 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -17,6 +17,9 @@ 'lambda' keyword. This prevents them from being properly formatted when they're arguments to functions. - A comment with continuation markers (??) shouldn't mess with the lineno count. +- Only emit unformatted if the "disable long line" is at the end of the line. + Otherwise we could mess up formatting for containers which have them + interspersed with code. ## [0.27.0] 2019-04-07 ### Added diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 91304f584..73165b0b7 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -240,10 +240,7 @@ def _LineContainsI18n(uwline): def _LineContainsPylintDisableLineTooLong(uwline): """Return true if there is a "pylint: disable=line-too-long" comment.""" - return any( - re.search(r'\bpylint:\s+disable=line-too-long\b', tok.value) - for tok in uwline.tokens - if tok.is_comment) + return re.search(r'\bpylint:\s+disable=line-too-long\b', uwline.last.value) def _LineHasContinuationMarkers(uwline): diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 935f98e29..4c30f72c5 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,19 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB132886019(self): + code = """\ +X = { + 'some_dict_key': + frozenset([ + # pylint: disable=line-too-long + '//this/path/is/really/too/long/for/this/line/and/probably/should/be/split', + ]), +} +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB26521719(self): code = """\ class _(): From dd53451fa0c2feb70b9954260e189866b8d69325 Mon Sep 17 00:00:00 2001 From: "O. Libre" Date: Sun, 30 Jun 2019 01:40:36 +0200 Subject: [PATCH 394/719] Provide the four predefined styles The based_on_style setting currently supports four predefined styles: - pep8 (default) - chromium - google - facebook See: https://github.com/google/yapf/blob/master/yapf/yapflib/style.py#L445 --- README.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 995b3324a..6ab3132f5 100644 --- a/README.rst +++ b/README.rst @@ -168,7 +168,11 @@ with a ``[yapf]`` heading. For example: split_before_logical_operator = true The ``based_on_style`` setting determines which of the predefined styles this -custom style is based on (think of it like subclassing). +custom style is based on (think of it like subclassing). Four +styles are predefined: ``pep8`` (default), ``chromium``, ``google`` and +``facebook`` (see ``_STYLE_NAME_TO_FACTORY`` in style.py_). + +.. _style.py: https://github.com/google/yapf/blob/master/yapf/yapflib/style.py#L445 It's also possible to do the same on the command line with a dictionary. For example: From 4a8323718d74de98e9691eb7bff7c50d47db2fb3 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 1 Jul 2019 15:16:05 -0700 Subject: [PATCH 395/719] Open files safely Using a try-catch-else prevents potential race conditions. Closes #731 --- CHANGELOG | 4 +++- yapf/yapflib/file_resources.py | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9b4965112..95ce3fbb7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.27.1] UNRELEASED +## [0.28.0] UNRELEASED ### Added - New knob `SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES` is a variation on `SPLIT_ALL_COMMA_SEPARATED_VALUES` in which, if a subexpression with a comma @@ -20,6 +20,8 @@ - Only emit unformatted if the "disable long line" is at the end of the line. Otherwise we could mess up formatting for containers which have them interspersed with code. +- Fix a potential race condition by using the correct style for opening a file + which may not exist. ## [0.27.0] 2019-04-07 ### Added diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 6de0b292d..3b1b3f0b9 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -86,8 +86,12 @@ def GetDefaultStyleForDir(dirname, default_style=style.DEFAULT_STYLE): # See if we have a setup.cfg file with a '[yapf]' section. config_file = os.path.join(dirname, style.SETUP_CONFIG) - if os.path.exists(config_file): - with open(config_file) as fd: + try: + fd = open(config_file) + except IOError: + pass # It's okay if it's not there. + else: + with fd: config = py3compat.ConfigParser() config.read_file(fd) if config.has_section('yapf'): From 7389bd54179a9e2c9af4f35715db5656df515895 Mon Sep 17 00:00:00 2001 From: Samuel Ainsworth Date: Mon, 1 Jul 2019 15:50:18 -0700 Subject: [PATCH 396/719] Catch/report `UnicodeDecodeError`s in `ReadFile` --- yapf/yapflib/yapf_api.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 282dea3eb..618e85d0c 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -202,6 +202,12 @@ def ReadFile(filename, logger=None): if logger: logger(err) raise + except UnicodeDecodeError as err: # pragma: no cover + if logger: + logger("Could not parse {}! Consider excluding this file with --exclude." + .format(filename)) + logger(err) + raise def _SplitSemicolons(uwlines): From de5c96ee161a21eefd868ea62d05bc36d83bd43f Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 11 Jul 2019 22:07:39 -0700 Subject: [PATCH 397/719] Bump version to 0.28.0 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 95ce3fbb7..ecdff4cb5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.28.0] UNRELEASED +## [0.28.0] 2019-07-11 ### Added - New knob `SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES` is a variation on `SPLIT_ALL_COMMA_SEPARATED_VALUES` in which, if a subexpression with a comma diff --git a/yapf/__init__.py b/yapf/__init__.py index d88d15cee..73665f66e 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -40,7 +40,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.27.0' +__version__ = '0.28.0' def main(argv): From e410178df392d98d56dd97c20a3c77284d7fce7a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 11 Jul 2019 22:25:51 -0700 Subject: [PATCH 398/719] Use a parameter list state object A parameter list state object allows us to keep better track of how a function's parameter list is formatted. --- CHANGELOG | 6 + yapf/yapflib/format_decision_state.py | 119 ++++++++- yapf/yapflib/format_token.py | 47 ++-- yapf/yapflib/object_state.py | 122 ++++++++- yapf/yapflib/pytree_unwrapper.py | 36 +++ yapf/yapflib/subtype_assigner.py | 46 +++- yapf/yapflib/unwrapped_line.py | 8 +- yapftests/reformatter_buganizer_test.py | 17 +- yapftests/reformatter_python3_test.py | 56 +++-- yapftests/subtype_assigner_test.py | 312 ++++++++++++++---------- yapftests/yapf_test.py | 12 +- 11 files changed, 597 insertions(+), 184 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ecdff4cb5..6f5ac38ab 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,12 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.28.1] UNRELEASED +### Changed +- Collect a parameter list into a single object. This allows us to track how a + parameter list is formatted, keeping state along the way. This helps when + supporting Python 3 type annotations. + ## [0.28.0] 2019-07-11 ### Added - New knob `SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES` is a variation on diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index ab7a40b20..71d57bd72 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -48,6 +48,8 @@ class FormatDecisionState(object): parenthesis levels. comp_stack: A stack (of ComprehensionState) keeping track of properties applying to comprehensions. + param_list_stack: A stack (of ParameterListState) keeping track of + properties applying to function parameter lists. ignore_stack_for_comparison: Ignore the stack of _ParenState for state comparison. """ @@ -70,6 +72,7 @@ def __init__(self, line, first_indent): self.ignore_stack_for_comparison = False self.stack = [_ParenState(first_indent, first_indent)] self.comp_stack = [] + self.param_list_stack = [] self.first_indent = first_indent self.column_limit = style.Get('COLUMN_LIMIT') @@ -86,6 +89,7 @@ def Clone(self): new.first_indent = self.first_indent new.stack = [state.Clone() for state in self.stack] new.comp_stack = [state.Clone() for state in self.comp_stack] + new.param_list_stack = [state.Clone() for state in self.param_list_stack] return new def __eq__(self, other): @@ -98,8 +102,9 @@ def __eq__(self, other): self.line.depth == other.line.depth and self.lowest_level_on_line == other.lowest_level_on_line and (self.ignore_stack_for_comparison or - other.ignore_stack_for_comparison or - self.stack == other.stack and self.comp_stack == other.comp_stack)) + other.ignore_stack_for_comparison or self.stack == other.stack and + self.comp_stack == other.comp_stack and + self.param_list_stack == other.param_list_stack)) def __ne__(self, other): return not self == other @@ -559,6 +564,8 @@ def AddTokenToState(self, newline, dry_run, must_split=False): Returns: The penalty of splitting after the current token. """ + self._PushParameterListState(newline) + penalty = 0 if newline: penalty = self._AddTokenOnNewline(dry_run, must_split) @@ -566,6 +573,7 @@ def AddTokenToState(self, newline, dry_run, must_split=False): self._AddTokenOnCurrentLine(dry_run) penalty += self._CalculateComprehensionState(newline) + penalty += self._CalculateParameterListState(newline) return self.MoveStateToNextToken() + penalty @@ -801,6 +809,100 @@ def _CalculateComprehensionState(self, newline): return penalty + def _PushParameterListState(self, newline): + """Push a new parameter list state for a function definition. + + Args: + newline: Whether the current token is to be added on a newline. + """ + current = self.next_token + previous = current.previous_token + + if _IsFunctionDefinition(previous): + first_param_column = previous.total_length + self.stack[-2].indent + self.param_list_stack.append( + object_state.ParameterListState(previous, newline, + first_param_column)) + + def _CalculateParameterListState(self, newline): + """Makes required changes to parameter list state. + + Args: + newline: Whether the current token is to be added on a newline. + + Returns: + The penalty for the token-newline combination given the current + parameter state. + """ + current = self.next_token + previous = current.previous_token + penalty = 0 + + if _IsFunctionDefinition(previous): + first_param_column = previous.total_length + self.stack[-2].indent + if not newline: + param_list = self.param_list_stack[-1] + if param_list.parameters and param_list.has_typed_return: + last_param = param_list.parameters[-1].first_token + last_token = _LastTokenInLine(previous.matching_bracket) + total_length = last_token.total_length + total_length -= last_param.total_length - len(last_param.value) + if total_length + self.column > self.column_limit: + # If we need to split before the trailing code of a function + # definition with return types, then also split before the opening + # parameter so that the trailing bit isn't indented on a line by + # itself: + # + # def rrrrrrrrrrrrrrrrrrrrrr(ccccccccccccccccccccccc: Tuple[Text] + # ) -> List[Tuple[Text, Text]]: + # pass + penalty += split_penalty.VERY_STRONGLY_CONNECTED + return penalty + + if first_param_column <= self.column: + # Make sure we don't split after the opening bracket if the + # continuation indent is greater than the opening bracket: + # + # a( + # b=1, + # c=2) + penalty += split_penalty.VERY_STRONGLY_CONNECTED + return penalty + + if not self.param_list_stack: + return penalty + + param_list = self.param_list_stack[-1] + if current == self.param_list_stack[-1].closing_bracket: + self.param_list_stack.pop() # We're done with this state. + if newline and param_list.has_typed_return: + if param_list.split_before_closing_bracket: + penalty -= split_penalty.STRONGLY_CONNECTED + elif param_list.LastParamFitsOnLine(self.column): + penalty += split_penalty.STRONGLY_CONNECTED + + if (not newline and param_list.has_typed_return and + param_list.has_split_before_first_param): + # Prefer splitting before the closing bracket if there's a return type + # and we've already split before the first parameter. + penalty += split_penalty.STRONGLY_CONNECTED + + if newline: + if self._FitsOnLine(param_list.parameters[0].first_token, + _LastTokenInLine(param_list.closing_bracket)): + penalty += split_penalty.STRONGLY_CONNECTED + + if (not newline and style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and + param_list.has_default_values and + current != param_list.parameters[0].first_token and + current != param_list.closing_bracket and + format_token.Subtype.PARAMETER_START in current.subtypes): + # If we want to split before parameters when there are named assigns, + # then add a penalty for not splitting. + penalty += split_penalty.STRONGLY_CONNECTED + + return penalty + def _GetNewlineColumn(self): """Return the new column on the newline.""" current = self.next_token @@ -841,7 +943,18 @@ def _GetNewlineColumn(self): len(self.line.first.whitespace_prefix.split('\n')[-1]) + style.Get('INDENT_WIDTH')) if token_indent == top_of_stack.indent: - return top_of_stack.indent + style.Get('CONTINUATION_INDENT_WIDTH') + if self.param_list_stack and _IsFunctionDef(self.line.first): + last_param = self.param_list_stack[-1] + if (last_param.LastParamFitsOnLine(token_indent) and + not last_param.LastParamFitsOnLine( + token_indent + style.Get('CONTINUATION_INDENT_WIDTH'))): + self.param_list_stack[-1].split_before_closing_bracket = True + return token_indent + + if not last_param.LastParamFitsOnLine(token_indent): + self.param_list_stack[-1].split_before_closing_bracket = True + return token_indent + return token_indent + style.Get('CONTINUATION_INDENT_WIDTH') return top_of_stack.indent diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 9bd2f7027..79b2b5c92 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -36,28 +36,30 @@ class Subtype(object): NONE = 0 UNARY_OPERATOR = 1 BINARY_OPERATOR = 2 - A_EXPR_OPERATOR = 22 - M_EXPR_OPERATOR = 23 - SUBSCRIPT_COLON = 3 - SUBSCRIPT_BRACKET = 4 - DEFAULT_OR_NAMED_ASSIGN = 5 - DEFAULT_OR_NAMED_ASSIGN_ARG_LIST = 6 - VARARGS_LIST = 7 - VARARGS_STAR = 8 - KWARGS_STAR_STAR = 9 - ASSIGN_OPERATOR = 10 - DICTIONARY_KEY = 11 - DICTIONARY_KEY_PART = 12 - DICTIONARY_VALUE = 13 - DICT_SET_GENERATOR = 14 - COMP_EXPR = 21 - COMP_FOR = 15 - COMP_IF = 16 - FUNC_DEF = 17 - DECORATOR = 18 - TYPED_NAME = 19 - TYPED_NAME_ARG_LIST = 20 + A_EXPR_OPERATOR = 3 + M_EXPR_OPERATOR = 4 + SUBSCRIPT_COLON = 5 + SUBSCRIPT_BRACKET = 6 + DEFAULT_OR_NAMED_ASSIGN = 7 + DEFAULT_OR_NAMED_ASSIGN_ARG_LIST = 8 + VARARGS_LIST = 9 + VARARGS_STAR = 10 + KWARGS_STAR_STAR = 11 + ASSIGN_OPERATOR = 12 + DICTIONARY_KEY = 13 + DICTIONARY_KEY_PART = 14 + DICTIONARY_VALUE = 15 + DICT_SET_GENERATOR = 16 + COMP_EXPR = 17 + COMP_FOR = 18 + COMP_IF = 19 + FUNC_DEF = 20 + DECORATOR = 21 + TYPED_NAME = 22 + TYPED_NAME_ARG_LIST = 23 SIMPLE_EXPRESSION = 24 + PARAMETER_START = 25 + PARAMETER_STOP = 26 def _TabbedContinuationAlignPadding(spaces, align_style, tab_width, @@ -96,6 +98,8 @@ class FormatToken(object): this is the first token in the unwrapped line. matching_bracket: If a bracket token ('[', '{', or '(') the matching bracket. + parameters: If this and its following tokens make up a parameter list, then + this is a list of those parameters. container_opening: If the object is in a container, this points to its opening bracket. container_elements: If this is the start of a container, a list of the @@ -125,6 +129,7 @@ def __init__(self, node): self.next_token = None self.previous_token = None self.matching_bracket = None + self.parameters = [] self.container_opening = None self.container_elements = [] self.whitespace_prefix = '' diff --git a/yapf/yapflib/object_state.py b/yapf/yapflib/object_state.py index dded7c423..41b58aeff 100644 --- a/yapf/yapflib/object_state.py +++ b/yapf/yapflib/object_state.py @@ -22,6 +22,11 @@ from __future__ import division from __future__ import print_function +from yapf.yapflib import format_token +from yapf.yapflib import py3compat +from yapf.yapflib import pytree_utils +from yapf.yapflib import style + class ComprehensionState(object): """Maintains the state of list comprehension formatting decisions. @@ -33,9 +38,9 @@ class ComprehensionState(object): expr_token: The first token in the comprehension. for_token: The first 'for' token of the comprehension. has_split_at_for: Whether there is a newline immediately before the - for_token. + for_token. has_interior_split: Whether there is a newline within the comprehension. - That is, a split somewhere after expr_token or before closing_bracket. + That is, a split somewhere after expr_token or before closing_bracket. """ def __init__(self, expr_token): @@ -78,3 +83,116 @@ def __ne__(self, other): def __hash__(self, *args, **kwargs): return hash((self.expr_token, self.for_token, self.has_split_at_for, self.has_interior_split)) + + +class ParameterListState(object): + """Maintains the state of function parameter list formatting decisions. + + Attributes: + opening_bracket: The opening bracket of the parameter list. + has_split_before_first_param: Whether there is a newline before the first + parameter. + opening_column: The position of the opening parameter before a newline. + parameters: A list of parameter objects (Parameter). + split_before_closing_bracket: Split before the closing bracket. Sometimes + needed if the indentation would collide. + """ + + def __init__(self, opening_bracket, newline, opening_column): + self.opening_bracket = opening_bracket + self.has_split_before_first_param = newline + self.opening_column = opening_column + self.parameters = opening_bracket.parameters + self.split_before_closing_bracket = False + + @property + def closing_bracket(self): + return self.opening_bracket.matching_bracket + + @property + def has_typed_return(self): + return self.closing_bracket.next_token.value == '->' + + @property + @py3compat.lru_cache() + def has_default_values(self): + return any(param.has_default_value for param in self.parameters) + + @py3compat.lru_cache() + def LastParamFitsOnLine(self, indent): + if not self.has_typed_return: + return False + last_param = self.parameters[-1].first_token + last_token = self.opening_bracket.matching_bracket + while not last_token.is_comment and last_token.next_token: + last_token = last_token.next_token + total_length = last_token.total_length + total_length -= last_param.total_length - len(last_param.value) + return total_length + indent <= style.Get('COLUMN_LIMIT') + + def Clone(self): + clone = ParameterListState(self.opening_bracket, + self.has_split_before_first_param, + self.opening_column) + clone.split_before_closing_bracket = self.split_before_closing_bracket + clone.parameters = [param.Clone() for param in self.parameters] + return clone + + def __repr__(self): + return ('[opening_bracket::%s, has_split_before_first_param::%s, ' + 'opening_column::%d]' % + (self.opening_bracket, self.has_split_before_first_param, + self.opening_column)) + + def __eq__(self, other): + return hash(self) == hash(other) + + def __ne__(self, other): + return not self == other + + def __hash__(self, *args, **kwargs): + return hash( + (self.opening_bracket, self.has_split_before_first_param, + self.opening_column, (hash(param) for param in self.parameters))) + + +class Parameter(object): + """A parameter in a parameter list. + + Attributes: + first_token: (format_token.FormatToken) First token of parameter. + last_token: (format_token.FormatToken) Last token of parameter. + """ + + def __init__(self, first_token, last_token): + self.first_token = first_token + self.last_token = last_token + + @property + @py3compat.lru_cache() + def has_default_value(self): + tok = self.first_token + while tok != self.last_token: + if format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in tok.subtypes: + return True + if tok.OpensScope(): + tok = tok.matching_bracket + else: + tok = tok.next_token + return False + + def Clone(self): + return Parameter(self.first_token, self.last_token) + + def __repr__(self): + return '[first_token::%s, last_token:%s]' % (self.first_token, + self.last_token) + + def __eq__(self, other): + return hash(self) == hash(other) + + def __ne__(self, other): + return not self == other + + def __hash__(self, *args, **kwargs): + return hash((self.first_token, self.last_token)) diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index 0d371ae19..ca6784dbb 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -31,8 +31,10 @@ from lib2to3 import pytree from lib2to3.pgen2 import token as grammar_token +from yapf.yapflib import format_token from yapf.yapflib import pytree_utils from yapf.yapflib import pytree_visitor +from yapf.yapflib import object_state from yapf.yapflib import split_penalty from yapf.yapflib import style from yapf.yapflib import unwrapped_line @@ -108,6 +110,7 @@ def _StartNewLine(self): if self._cur_unwrapped_line.tokens: self._unwrapped_lines.append(self._cur_unwrapped_line) _MatchBrackets(self._cur_unwrapped_line) + _IdentifyParameterLists(self._cur_unwrapped_line) _AdjustSplitPenalty(self._cur_unwrapped_line) self._cur_unwrapped_line = unwrapped_line.UnwrappedLine(self._cur_depth) @@ -320,6 +323,39 @@ def _MatchBrackets(uwline): token.container_opening = bracket +def _IdentifyParameterLists(uwline): + """Visit the node to create a state for parameter lists. + + For instance, a parameter is considered an "object" with its first and last + token uniquely identifying the object. + + Arguments: + uwline: (UnwrappedLine) An unwrapped line. + """ + func_stack = [] + param_stack = [] + for tok in uwline.tokens: + # Identify parameter list objects. + if format_token.Subtype.FUNC_DEF in tok.subtypes: + assert tok.next_token.value == '(' + func_stack.append(tok.next_token) + continue + + if func_stack and tok.value == ')': + if tok == func_stack[-1].matching_bracket: + func_stack.pop() + continue + + # Identify parameter objects. + if format_token.Subtype.PARAMETER_START in tok.subtypes: + param_stack.append(tok) + + # Not "elif", a parameter could be a single token. + if param_stack and format_token.Subtype.PARAMETER_STOP in tok.subtypes: + start = param_stack.pop() + func_stack[-1].parameters.append(object_state.Parameter(start, tok)) + + def _AdjustSplitPenalty(uwline): """Visit the node and adjust the split penalties if needed. diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index dc36bbb64..585f265f2 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -280,6 +280,15 @@ def Visit_funcdef(self, node): # pylint: disable=invalid-name for child in node.children: self.Visit(child) + def Visit_parameters(self, node): # pylint: disable=invalid-name + # parameters ::= '(' [typedargslist] ')' + self._ProcessArgLists(node) + if len(node.children) > 2: + _AppendFirstLeafTokenSubtype(node.children[1], + format_token.Subtype.PARAMETER_START) + _AppendLastLeafTokenSubtype(node.children[-2], + format_token.Subtype.PARAMETER_STOP) + def Visit_typedargslist(self, node): # pylint: disable=invalid-name # typedargslist ::= # ((tfpdef ['=' test] ',')* @@ -290,16 +299,35 @@ def Visit_typedargslist(self, node): # pylint: disable=invalid-name _SetArgListSubtype(node, format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN, format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) tname = False - for child in node.children: + if not len(node.children): + return + + _AppendFirstLeafTokenSubtype(node.children[0], + format_token.Subtype.PARAMETER_START) + _AppendLastLeafTokenSubtype(node.children[-1], + format_token.Subtype.PARAMETER_STOP) + + i = 1 + tname = pytree_utils.NodeName(node.children[0]) == 'tname' + while i < len(node.children): + prev_child = node.children[i - 1] + child = node.children[i] + i += 1 + + if pytree_utils.NodeName(prev_child) == 'COMMA': + _AppendFirstLeafTokenSubtype(child, + format_token.Subtype.PARAMETER_START) + elif pytree_utils.NodeName(child) == 'COMMA': + _AppendLastLeafTokenSubtype(prev_child, + format_token.Subtype.PARAMETER_STOP) + if pytree_utils.NodeName(child) == 'tname': tname = True _SetArgListSubtype(child, format_token.Subtype.TYPED_NAME, format_token.Subtype.TYPED_NAME_ARG_LIST) - if not isinstance(child, pytree.Leaf): - continue - if child.value == ',': + elif pytree_utils.NodeName(child) == 'COMMA': tname = False - elif child.value == '=' and tname: + elif pytree_utils.NodeName(child) == 'EQUAL' and tname: _AppendTokenSubtype(child, subtype=format_token.Subtype.TYPED_NAME) tname = False @@ -390,6 +418,14 @@ def _AppendFirstLeafTokenSubtype(node, subtype): _AppendFirstLeafTokenSubtype(node.children[0], subtype) +def _AppendLastLeafTokenSubtype(node, subtype): + """Append the last leaf token's subtypes.""" + if isinstance(node, pytree.Leaf): + _AppendTokenSubtype(node, subtype) + return + _AppendLastLeafTokenSubtype(node.children[-1], subtype) + + def _AppendSubtypeRec(node, subtype, force=True): """Append the leafs in the node to the given subtype.""" if isinstance(node, pytree.Leaf): diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index fb1275583..10e1609d8 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -358,8 +358,12 @@ def _SpaceRequiredBetween(left, right): # The previous token was a unary op. No space is desired between it and # the current token. return False - if (format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in left.subtypes or - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in right.subtypes): + if (format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in left.subtypes and + format_token.Subtype.TYPED_NAME not in right.subtypes): + # A named argument or default parameter shouldn't have spaces around it. + return style.Get('SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN') + if (format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in right.subtypes and + format_token.Subtype.TYPED_NAME not in left.subtypes): # A named argument or default parameter shouldn't have spaces around it. return style.Get('SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN') if (format_token.Subtype.VARARGS_LIST in left.subtypes or diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 4c30f72c5..b43191583 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,17 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB119300344(self): + code = """\ +def _GenerateStatsEntries( + process_id: Text, + timestamp: Optional[rdfvalue.RDFDatetime] = None +) -> Sequence[stats_values.StatsStoreEntry]: + pass +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB132886019(self): code = """\ X = { @@ -175,7 +186,8 @@ def xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( eeeeeeeeeeee: AnyStr = cst.DEFAULT_CONTROL_NAME, ffffffffffffffffffff: Optional[ Callable[[pd.DataFrame], pd.DataFrame]] = None, - gggggggggggggg: ooooooooooooo = ooooooooooooo()) -> pd.DataFrame: + gggggggggggggg: ooooooooooooo = ooooooooooooo() +) -> pd.DataFrame: pass """ uwlines = yapf_test_helper.ParseAndUnwrap(code) @@ -1110,7 +1122,8 @@ def aaaaa(self, bbbbb, cccccccccccccc=None): # TODO(who): pylint: disable=unuse return 1 def xxxxx( - self, yyyyy, + self, + yyyyy, zzzzzzzzzzzzzz=None): # A normal comment that runs over the column limit. return 1 """) diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index 9be6528d5..ff7bf749b 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -238,7 +238,7 @@ def _ReduceAbstractContainers( """) expected_formatted_code = textwrap.dedent("""\ def _ReduceAbstractContainers( - self, *args: Optional[automation_converter.PyiCollectionAbc] + self, *args: Optional[automation_converter.PyiCollectionAbc] ) -> List[automation_converter.PyiCollectionAbc]: pass """) @@ -290,33 +290,33 @@ def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): """ expected_formatted_code = """\ async def open_file( - file, - mode='r', - buffering=-1, - encoding=None, - errors=None, - newline=None, - closefd=True, - opener=None + file, + mode='r', + buffering=-1, + encoding=None, + errors=None, + newline=None, + closefd=True, + opener=None ): pass async def run_sync_in_worker_thread( - sync_fn, *args, cancellable=False, limiter=None + sync_fn, *args, cancellable=False, limiter=None ): pass def open_file( - file, - mode='r', - buffering=-1, - encoding=None, - errors=None, - newline=None, - closefd=True, - opener=None + file, + mode='r', + buffering=-1, + encoding=None, + errors=None, + newline=None, + closefd=True, + opener=None ): pass @@ -378,6 +378,26 @@ def dirichlet(x12345678901234567890123456789012345678901234567890=...) -> None: uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testFunctionTypedReturnNextLine(self): + code = """\ +def _GenerateStatsEntries( + process_id: Text, + timestamp: Optional[ffffffff.FFFFFFFFFFF] = None +) -> Sequence[ssssssssssss.SSSSSSSSSSSSSSS]: + pass +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testFunctionTypedReturnSameLine(self): + code = """\ +def rrrrrrrrrrrrrrrrrrrrrr( + ccccccccccccccccccccccc: Tuple[Text, Text]) -> List[Tuple[Text, Text]]: + pass +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index ef864f83a..2a74a83ec 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -43,41 +43,66 @@ def _CheckFormatTokenSubtypes(self, uwlines, list_of_expected): self.assertEqual(list_of_expected, actual) def testFuncDefDefaultAssign(self): + self.maxDiff = None code = textwrap.dedent(r""" def foo(a=37, *b, **c): return -x[:42] """) uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ - [('def', [format_token.Subtype.NONE]), - ('foo', {format_token.Subtype.FUNC_DEF}), - ('(', [format_token.Subtype.NONE]), - ('a', {format_token.Subtype.NONE, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST}), - ('=', {format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST}), - ('37', {format_token.Subtype.NONE, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST}), - (',', {format_token.Subtype.NONE}), - ('*', {format_token.Subtype.VARARGS_STAR, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST}), - ('b', {format_token.Subtype.NONE, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST}), - (',', {format_token.Subtype.NONE}), - ('**', {format_token.Subtype.KWARGS_STAR_STAR, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST}), - ('c', {format_token.Subtype.NONE, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST}), - (')', [format_token.Subtype.NONE]), - (':', [format_token.Subtype.NONE])], - [('return', [format_token.Subtype.NONE]), - ('-', {format_token.Subtype.UNARY_OPERATOR}), - ('x', [format_token.Subtype.NONE]), - ('[', {format_token.Subtype.SUBSCRIPT_BRACKET}), - (':', {format_token.Subtype.SUBSCRIPT_COLON}), - ('42', [format_token.Subtype.NONE]), - (']', {format_token.Subtype.SUBSCRIPT_BRACKET})], - ]) # yapf: disable + [ + ('def', [format_token.Subtype.NONE]), + ('foo', {format_token.Subtype.FUNC_DEF}), + ('(', {format_token.Subtype.NONE}), + ('a', { + format_token.Subtype.NONE, + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + format_token.Subtype.PARAMETER_START, + }), + ('=', { + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN, + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + ('37', { + format_token.Subtype.NONE, + format_token.Subtype.PARAMETER_STOP, + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + (',', {format_token.Subtype.NONE}), + ('*', { + format_token.Subtype.PARAMETER_START, + format_token.Subtype.VARARGS_STAR, + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + ('b', { + format_token.Subtype.NONE, + format_token.Subtype.PARAMETER_STOP, + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + (',', {format_token.Subtype.NONE}), + ('**', { + format_token.Subtype.PARAMETER_START, + format_token.Subtype.KWARGS_STAR_STAR, + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + ('c', { + format_token.Subtype.NONE, + format_token.Subtype.PARAMETER_STOP, + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + (')', {format_token.Subtype.NONE}), + (':', [format_token.Subtype.NONE]), + ], + [ + ('return', [format_token.Subtype.NONE]), + ('-', {format_token.Subtype.UNARY_OPERATOR}), + ('x', [format_token.Subtype.NONE]), + ('[', {format_token.Subtype.SUBSCRIPT_BRACKET}), + (':', {format_token.Subtype.SUBSCRIPT_COLON}), + ('42', [format_token.Subtype.NONE]), + (']', {format_token.Subtype.SUBSCRIPT_BRACKET}), + ], + ]) def testFuncCallWithDefaultAssign(self): code = textwrap.dedent(r""" @@ -85,17 +110,23 @@ def testFuncCallWithDefaultAssign(self): """) uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ - [('foo', [format_token.Subtype.NONE]), - ('(', [format_token.Subtype.NONE]), - ('x', {format_token.Subtype.NONE, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST}), - (',', {format_token.Subtype.NONE}), - ('a', {format_token.Subtype.NONE, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST}), - ('=', {format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN}), - ("'hello world'", {format_token.Subtype.NONE}), - (')', [format_token.Subtype.NONE])], - ]) # yapf: disable + [ + ('foo', [format_token.Subtype.NONE]), + ('(', [format_token.Subtype.NONE]), + ('x', { + format_token.Subtype.NONE, + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + (',', {format_token.Subtype.NONE}), + ('a', { + format_token.Subtype.NONE, + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + ('=', {format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN}), + ("'hello world'", {format_token.Subtype.NONE}), + (')', [format_token.Subtype.NONE]), + ], + ]) def testSetComprehension(self): code = textwrap.dedent("""\ @@ -104,36 +135,45 @@ def foo(strs): """) uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ - [('def', [format_token.Subtype.NONE]), - ('foo', {format_token.Subtype.FUNC_DEF}), - ('(', [format_token.Subtype.NONE]), - ('strs', [format_token.Subtype.NONE]), - (')', [format_token.Subtype.NONE]), - (':', [format_token.Subtype.NONE])], - [('return', [format_token.Subtype.NONE]), - ('{', [format_token.Subtype.NONE]), - ('s', {format_token.Subtype.COMP_EXPR}), - ('.', {format_token.Subtype.COMP_EXPR}), - ('lower', {format_token.Subtype.COMP_EXPR}), - ('(', {format_token.Subtype.COMP_EXPR}), - (')', {format_token.Subtype.COMP_EXPR}), - ('for', {format_token.Subtype.DICT_SET_GENERATOR, - format_token.Subtype.COMP_FOR}), - ('s', {format_token.Subtype.COMP_FOR}), - ('in', {format_token.Subtype.COMP_FOR}), - ('strs', {format_token.Subtype.COMP_FOR}), - ('}', [format_token.Subtype.NONE])] - ]) # yapf: disable + [ + ('def', [format_token.Subtype.NONE]), + ('foo', {format_token.Subtype.FUNC_DEF}), + ('(', {format_token.Subtype.NONE}), + ('strs', { + format_token.Subtype.NONE, + format_token.Subtype.PARAMETER_START, + format_token.Subtype.PARAMETER_STOP, + }), + (')', {format_token.Subtype.NONE}), + (':', [format_token.Subtype.NONE]), + ], + [ + ('return', [format_token.Subtype.NONE]), + ('{', [format_token.Subtype.NONE]), + ('s', {format_token.Subtype.COMP_EXPR}), + ('.', {format_token.Subtype.COMP_EXPR}), + ('lower', {format_token.Subtype.COMP_EXPR}), + ('(', {format_token.Subtype.COMP_EXPR}), + (')', {format_token.Subtype.COMP_EXPR}), + ('for', { + format_token.Subtype.DICT_SET_GENERATOR, + format_token.Subtype.COMP_FOR, + }), + ('s', {format_token.Subtype.COMP_FOR}), + ('in', {format_token.Subtype.COMP_FOR}), + ('strs', {format_token.Subtype.COMP_FOR}), + ('}', [format_token.Subtype.NONE]), + ], + ]) def testUnaryNotOperator(self): code = textwrap.dedent("""\ not a """) uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes(uwlines, [ - [('not', {format_token.Subtype.UNARY_OPERATOR}), - ('a', [format_token.Subtype.NONE])] - ]) # yapf: disable + self._CheckFormatTokenSubtypes( + uwlines, [[('not', {format_token.Subtype.UNARY_OPERATOR}), + ('a', [format_token.Subtype.NONE])]]) def testBitwiseOperators(self): code = textwrap.dedent("""\ @@ -141,26 +181,28 @@ def testBitwiseOperators(self): """) uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ - [('x', [format_token.Subtype.NONE]), - ('=', {format_token.Subtype.ASSIGN_OPERATOR}), - ('(', [format_token.Subtype.NONE]), - ('(', [format_token.Subtype.NONE]), - ('a', [format_token.Subtype.NONE]), - ('|', {format_token.Subtype.BINARY_OPERATOR}), - ('(', [format_token.Subtype.NONE]), - ('b', [format_token.Subtype.NONE]), - ('^', {format_token.Subtype.BINARY_OPERATOR}), - ('3', [format_token.Subtype.NONE]), - (')', [format_token.Subtype.NONE]), - ('&', {format_token.Subtype.BINARY_OPERATOR}), - ('c', [format_token.Subtype.NONE]), - (')', [format_token.Subtype.NONE]), - ('<<', {format_token.Subtype.BINARY_OPERATOR}), - ('3', [format_token.Subtype.NONE]), - (')', [format_token.Subtype.NONE]), - ('>>', {format_token.Subtype.BINARY_OPERATOR}), - ('1', [format_token.Subtype.NONE]),], - ]) # yapf: disable + [ + ('x', [format_token.Subtype.NONE]), + ('=', {format_token.Subtype.ASSIGN_OPERATOR}), + ('(', [format_token.Subtype.NONE]), + ('(', [format_token.Subtype.NONE]), + ('a', [format_token.Subtype.NONE]), + ('|', {format_token.Subtype.BINARY_OPERATOR}), + ('(', [format_token.Subtype.NONE]), + ('b', [format_token.Subtype.NONE]), + ('^', {format_token.Subtype.BINARY_OPERATOR}), + ('3', [format_token.Subtype.NONE]), + (')', [format_token.Subtype.NONE]), + ('&', {format_token.Subtype.BINARY_OPERATOR}), + ('c', [format_token.Subtype.NONE]), + (')', [format_token.Subtype.NONE]), + ('<<', {format_token.Subtype.BINARY_OPERATOR}), + ('3', [format_token.Subtype.NONE]), + (')', [format_token.Subtype.NONE]), + ('>>', {format_token.Subtype.BINARY_OPERATOR}), + ('1', [format_token.Subtype.NONE]), + ], + ]) def testArithmeticOperators(self): code = textwrap.dedent("""\ @@ -168,41 +210,57 @@ def testArithmeticOperators(self): """) uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ - [('x', [format_token.Subtype.NONE]), - ('=', {format_token.Subtype.ASSIGN_OPERATOR}), - ('(', [format_token.Subtype.NONE]), - ('(', [format_token.Subtype.NONE]), - ('a', [format_token.Subtype.NONE]), - ('+', {format_token.Subtype.BINARY_OPERATOR, - format_token.Subtype.A_EXPR_OPERATOR}), - ('(', [format_token.Subtype.NONE]), - ('b', [format_token.Subtype.NONE]), - ('-', {format_token.Subtype.BINARY_OPERATOR, + [ + ('x', [format_token.Subtype.NONE]), + ('=', {format_token.Subtype.ASSIGN_OPERATOR}), + ('(', [format_token.Subtype.NONE]), + ('(', [format_token.Subtype.NONE]), + ('a', [format_token.Subtype.NONE]), + ('+', { + format_token.Subtype.BINARY_OPERATOR, + format_token.Subtype.A_EXPR_OPERATOR, + }), + ('(', [format_token.Subtype.NONE]), + ('b', [format_token.Subtype.NONE]), + ('-', { + format_token.Subtype.BINARY_OPERATOR, format_token.Subtype.A_EXPR_OPERATOR, - format_token.Subtype.SIMPLE_EXPRESSION}), - ('3', [format_token.Subtype.NONE]), - (')', [format_token.Subtype.NONE]), - ('*', {format_token.Subtype.BINARY_OPERATOR, - format_token.Subtype.M_EXPR_OPERATOR}), - ('(', [format_token.Subtype.NONE]), - ('1', [format_token.Subtype.NONE]), - ('%', {format_token.Subtype.BINARY_OPERATOR, + format_token.Subtype.SIMPLE_EXPRESSION, + }), + ('3', [format_token.Subtype.NONE]), + (')', [format_token.Subtype.NONE]), + ('*', { + format_token.Subtype.BINARY_OPERATOR, + format_token.Subtype.M_EXPR_OPERATOR, + }), + ('(', [format_token.Subtype.NONE]), + ('1', [format_token.Subtype.NONE]), + ('%', { + format_token.Subtype.BINARY_OPERATOR, format_token.Subtype.M_EXPR_OPERATOR, - format_token.Subtype.SIMPLE_EXPRESSION}), - ('c', [format_token.Subtype.NONE]), - (')', [format_token.Subtype.NONE]), - ('@', {format_token.Subtype.BINARY_OPERATOR, - format_token.Subtype.M_EXPR_OPERATOR}), - ('d', [format_token.Subtype.NONE]), - (')', [format_token.Subtype.NONE]), - ('/', {format_token.Subtype.BINARY_OPERATOR, - format_token.Subtype.M_EXPR_OPERATOR}), - ('3', [format_token.Subtype.NONE]), - (')', [format_token.Subtype.NONE]), - ('//', {format_token.Subtype.BINARY_OPERATOR, - format_token.Subtype.M_EXPR_OPERATOR}), - ('1', [format_token.Subtype.NONE]),], - ]) # yapf: disable + format_token.Subtype.SIMPLE_EXPRESSION, + }), + ('c', [format_token.Subtype.NONE]), + (')', [format_token.Subtype.NONE]), + ('@', { + format_token.Subtype.BINARY_OPERATOR, + format_token.Subtype.M_EXPR_OPERATOR, + }), + ('d', [format_token.Subtype.NONE]), + (')', [format_token.Subtype.NONE]), + ('/', { + format_token.Subtype.BINARY_OPERATOR, + format_token.Subtype.M_EXPR_OPERATOR, + }), + ('3', [format_token.Subtype.NONE]), + (')', [format_token.Subtype.NONE]), + ('//', { + format_token.Subtype.BINARY_OPERATOR, + format_token.Subtype.M_EXPR_OPERATOR, + }), + ('1', [format_token.Subtype.NONE]), + ], + ]) def testSubscriptColon(self): code = textwrap.dedent("""\ @@ -228,14 +286,18 @@ def testFunctionCallWithStarExpression(self): """) uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ - [('[', [format_token.Subtype.NONE]), - ('a', [format_token.Subtype.NONE]), - (',', [format_token.Subtype.NONE]), - ('*', {format_token.Subtype.UNARY_OPERATOR, - format_token.Subtype.VARARGS_STAR}), - ('b', [format_token.Subtype.NONE]), - (']', [format_token.Subtype.NONE]),], - ]) # yapf: disable + [ + ('[', [format_token.Subtype.NONE]), + ('a', [format_token.Subtype.NONE]), + (',', [format_token.Subtype.NONE]), + ('*', { + format_token.Subtype.UNARY_OPERATOR, + format_token.Subtype.VARARGS_STAR, + }), + ('b', [format_token.Subtype.NONE]), + (']', [format_token.Subtype.NONE]), + ], + ]) if __name__ == '__main__': diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index a257200f6..e13955fde 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1710,12 +1710,12 @@ def MyFunc( """) expected_formatted_code = textwrap.dedent("""\ def MyFunc( - arg1, # Desc 1 - arg2, # Desc 2 - a_longer_var_name, # Desc 3 - arg4, - arg5, # Desc 5 - arg6, + arg1, # Desc 1 + arg2, # Desc 2 + a_longer_var_name, # Desc 3 + arg4, + arg5, # Desc 5 + arg6, ): pass """) From 37ac648c03fad6a82c85ee2d98fe7d71beec59db Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 11 Jul 2019 23:46:15 -0700 Subject: [PATCH 399/719] Format subscript lists A subscript list can be treated like a normal arg list. Splitting after a comma should be essentially free. --- CHANGELOG | 2 ++ yapf/yapflib/split_penalty.py | 15 +++++++++++---- yapftests/reformatter_buganizer_test.py | 25 +++++++++++++++++++------ 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6f5ac38ab..4bb00e1a8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,8 @@ - Collect a parameter list into a single object. This allows us to track how a parameter list is formatted, keeping state along the way. This helps when supporting Python 3 type annotations. +### Fixed +- Format subscript lists so that splits are essentially free after a comma. ## [0.28.0] 2019-07-11 ### Added diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 7f86d96b3..3d56f0363 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -250,10 +250,7 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name # Bump up the split penalty for the first part of a subscript. We # would rather not split there. - first_leaf = pytree_utils.FirstLeafNode(node.children[1]) - penalty = pytree_utils.GetNodeAnnotation( - first_leaf, pytree_utils.Annotation.SPLIT_PENALTY, default=0) - _SetSplitPenalty(first_leaf, penalty + CONNECTED) + _IncreasePenalty(node.children[1], CONNECTED) else: _SetStronglyConnected(node.children[1], node.children[2]) @@ -331,6 +328,16 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring # split the two. _SetStronglyConnected(trailer.children[-1]) + def Visit_subscriptlist(self, node): # pylint: disable=invalid-name + # subscriptlist ::= subscript (',' subscript)* [','] + self.DefaultNodeVisit(node) + _SetSplitPenalty(pytree_utils.FirstLeafNode(node), 0) + prev_child = None + for child in node.children: + if prev_child and pytree_utils.NodeName(prev_child) == 'COMMA': + _SetSplitPenalty(pytree_utils.FirstLeafNode(child), 0) + prev_child = child + def Visit_subscript(self, node): # pylint: disable=invalid-name # subscript ::= test | [test] ':' [test] [sliceop] _SetStronglyConnected(*node.children) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index b43191583..f0d24274d 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,19 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB122455211(self): + unformatted_code = """\ +_zzzzzzzzzzzzzzzzzzzz = Union[sssssssssssssssssssss.pppppppppppppppp, + sssssssssssssssssssss.pppppppppppppppppppppppppppp] +""" + expected_formatted_code = """\ +_zzzzzzzzzzzzzzzzzzzz = Union[ + sssssssssssssssssssss.pppppppppppppppp, + sssssssssssssssssssss.pppppppppppppppppppppppppppp] +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB119300344(self): code = """\ def _GenerateStatsEntries( @@ -168,10 +181,10 @@ def testNoAlertForShortPeriod(self, rutabaga): class Foo(object): def testNoAlertForShortPeriod(self, rutabaga): - self.targets[:][streamz_path, - self._fillInOtherFields( - streamz_path, {streamz_field_of_interest: True} - )] = series.Counter('1s', '+ 500x10000') + self.targets[:][ + streamz_path, + self._fillInOtherFields(streamz_path, {streamz_field_of_interest: True} + )] = series.Counter('1s', '+ 500x10000') """ uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -184,8 +197,8 @@ def xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( cccccccccc: AnyStr = cst.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD, dddddddddd: Sequence[SliceDimension] = (), eeeeeeeeeeee: AnyStr = cst.DEFAULT_CONTROL_NAME, - ffffffffffffffffffff: Optional[ - Callable[[pd.DataFrame], pd.DataFrame]] = None, + ffffffffffffffffffff: Optional[Callable[[pd.DataFrame], + pd.DataFrame]] = None, gggggggggggggg: ooooooooooooo = ooooooooooooo() ) -> pd.DataFrame: pass From 99f5d3f50484c067a5bde64951d5e1b545a6433d Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 12 Jul 2019 00:34:31 -0700 Subject: [PATCH 400/719] Fix linter warnings. --- yapf/yapflib/object_state.py | 7 ++++++- yapf/yapflib/pytree_unwrapper.py | 2 +- yapf/yapflib/subtype_assigner.py | 2 +- yapftests/subtype_assigner_test.py | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/yapf/yapflib/object_state.py b/yapf/yapflib/object_state.py index 41b58aeff..124ae6566 100644 --- a/yapf/yapflib/object_state.py +++ b/yapf/yapflib/object_state.py @@ -24,7 +24,6 @@ from yapf.yapflib import format_token from yapf.yapflib import py3compat -from yapf.yapflib import pytree_utils from yapf.yapflib import style @@ -90,6 +89,9 @@ class ParameterListState(object): Attributes: opening_bracket: The opening bracket of the parameter list. + closing_bracket: The closing bracket of the parameter list. + has_typed_return: True if the function definition has a typed return. + has_default_values: True if the parameters have default values. has_split_before_first_param: Whether there is a newline before the first parameter. opening_column: The position of the opening parameter before a newline. @@ -120,6 +122,7 @@ def has_default_values(self): @py3compat.lru_cache() def LastParamFitsOnLine(self, indent): + """Return true if the last parameter fits on a single line.""" if not self.has_typed_return: return False last_param = self.parameters[-1].first_token @@ -162,6 +165,7 @@ class Parameter(object): Attributes: first_token: (format_token.FormatToken) First token of parameter. last_token: (format_token.FormatToken) Last token of parameter. + has_default_value: (boolean) True if the parameter has a default value """ def __init__(self, first_token, last_token): @@ -171,6 +175,7 @@ def __init__(self, first_token, last_token): @property @py3compat.lru_cache() def has_default_value(self): + """Returns true if the parameter has a default value.""" tok = self.first_token while tok != self.last_token: if format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in tok.subtypes: diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index ca6784dbb..f4d9cbafc 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -32,9 +32,9 @@ from lib2to3.pgen2 import token as grammar_token from yapf.yapflib import format_token +from yapf.yapflib import object_state from yapf.yapflib import pytree_utils from yapf.yapflib import pytree_visitor -from yapf.yapflib import object_state from yapf.yapflib import split_penalty from yapf.yapflib import style from yapf.yapflib import unwrapped_line diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 585f265f2..0fa2d9663 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -299,7 +299,7 @@ def Visit_typedargslist(self, node): # pylint: disable=invalid-name _SetArgListSubtype(node, format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN, format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) tname = False - if not len(node.children): + if not node.children: return _AppendFirstLeafTokenSubtype(node.children[0], diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index 2a74a83ec..b42b8cfab 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -43,7 +43,7 @@ def _CheckFormatTokenSubtypes(self, uwlines, list_of_expected): self.assertEqual(list_of_expected, actual) def testFuncDefDefaultAssign(self): - self.maxDiff = None + self.maxDiff = None # pylint: disable=invalid-name code = textwrap.dedent(r""" def foo(a=37, *b, **c): return -x[:42] From 9e210ce72c3f06c1568f1806889bf02bfc2c4f8a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 16 Jul 2019 01:28:38 -0700 Subject: [PATCH 401/719] Don't add a space between a string and its subscript --- CHANGELOG | 1 + yapf/yapflib/split_penalty.py | 6 ++++++ yapf/yapflib/unwrapped_line.py | 3 +++ yapftests/reformatter_buganizer_test.py | 14 ++++++++++++++ 4 files changed, 24 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 4bb00e1a8..bec7de177 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,7 @@ supporting Python 3 type annotations. ### Fixed - Format subscript lists so that splits are essentially free after a comma. +- Don't add a space between a string and its subscript. ## [0.28.0] 2019-07-11 ### Added diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 3d56f0363..e15ea2e67 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -144,6 +144,12 @@ def Visit_parameters(self, node): # pylint: disable=invalid-name def Visit_arglist(self, node): # pylint: disable=invalid-name # arglist ::= argument (',' argument)* [','] + if pytree_utils.NodeName(node.children[0]) == 'STAR': + # Python 3 treats a star expression as a specific expression type. + # Process it in that method. + self.Visit_star_expr(node) + return + self.DefaultNodeVisit(node) for index in py3compat.range(1, len(node.children)): diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 10e1609d8..ff51db504 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -329,6 +329,9 @@ def _SpaceRequiredBetween(left, right): # A string followed by something other than a subscript, closing bracket, # dot, or a binary op should have a space after it. return True + if format_token.Subtype.SUBSCRIPT_BRACKET in right.subtypes: + # It's legal to do this in Python: 'hello'[a] + return False if left.is_binary_op and lval != '**' and _IsUnaryOperator(right): # Space between the binary operator and the unary operator. return True diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index f0d24274d..e4218b13d 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,20 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB73279849(self): + unformatted_code = """\ +class A: + def _(a): + return 'hello' [ a ] +""" + expected_formatted_code = """\ +class A: + def _(a): + return 'hello'[a] +""" + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testB122455211(self): unformatted_code = """\ _zzzzzzzzzzzzzzzzzzzz = Union[sssssssssssssssssssss.pppppppppppppppp, From 8244b5f4360a31941acdf8de82f0c7e3dbba3673 Mon Sep 17 00:00:00 2001 From: Gary Miguel Date: Wed, 10 Jul 2019 15:12:07 -0700 Subject: [PATCH 402/719] Set JOIN_MULTIPLE_LINES = False in google style IIUC, this is more likely to make the output compliant with the google style guide[1], though in some cases it is stricter than that document requires. Specifically this example from the "No" section would be fixed only after this change: ``` if foo: bar(foo) else: baz(foo) ``` But this example from the "Yes" section will also be modified: ``` if foo: bar(foo) ``` I think eliminating one way in which the formatter produes style-guide-violating code is an improvement. [1] https://github.com/google/styleguide/blob/gh-pages/pyguide.md#314-statements --- CHANGELOG | 1 + yapf/yapflib/style.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 95ce3fbb7..941a8a9b9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,7 @@ unnecessary splits). ### Changed - Set `INDENT_DICTIONARY_VALUE` for Google style. +- Set `JOIN_MULTIPLE_LINES = False` for Google style. ### Fixed - `BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=False` wasn't honored because the number of newlines was erroneously calculated beforehand. diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 48b3984c0..e614e6252 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -404,6 +404,7 @@ def CreateGoogleStyle(): style['INDENT_WIDTH'] = 4 style['I18N_COMMENT'] = r'#\..*' style['I18N_FUNCTION_CALL'] = ['N_', '_'] + style['JOIN_MULTIPLE_LINES'] = False style['SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET'] = False style['SPLIT_BEFORE_BITWISE_OPERATOR'] = False style['SPLIT_BEFORE_DICT_SET_GENERATOR'] = False @@ -419,7 +420,6 @@ def CreateChromiumStyle(): style['ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS'] = False style['INDENT_DICTIONARY_VALUE'] = True style['INDENT_WIDTH'] = 2 - style['JOIN_MULTIPLE_LINES'] = False style['SPLIT_BEFORE_BITWISE_OPERATOR'] = True style['SPLIT_BEFORE_DOT'] = True style['SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN'] = True From eef522123a359a41787e65491b7f51812a479d01 Mon Sep 17 00:00:00 2001 From: Eric An Date: Thu, 18 Jul 2019 20:10:51 -0700 Subject: [PATCH 403/719] Look for style/config at root, add tests - We encountered a weird phenonemon when building containers with setup.cfg placed at the container root, and the yapf command fired on a subdirectory of root. - Appears as though the traversal to root breaks one step too early in the current implementation. Tiny fix; adds a test. - Also adds a few tests to test discovery of styles via setup.cfg - Thanks to sendittovignesh@gmail.com and matthewwillian@gmail.com for the discovery & diagnosis of the issue! --- yapf/yapflib/file_resources.py | 2 +- yapftests/file_resources_test.py | 44 ++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 3b1b3f0b9..59c3df54c 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -97,10 +97,10 @@ def GetDefaultStyleForDir(dirname, default_style=style.DEFAULT_STYLE): if config.has_section('yapf'): return config_file - dirname = os.path.dirname(dirname) if (not dirname or not os.path.basename(dirname) or dirname == os.path.abspath(os.path.sep)): break + dirname = os.path.dirname(dirname) global_file = os.path.expanduser(style.GLOBAL_STYLE) if os.path.exists(global_file): diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index eaf4b8be3..b88afd881 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -35,6 +35,15 @@ def _restore_working_dir(): finally: os.chdir(curdir) +@contextlib.contextmanager +def _exists_mocked_in_module(module, mock_implementation): + unmocked_exists = getattr(module, 'exists') + setattr(module, 'exists', mock_implementation) + try: + yield + finally: + setattr(module, 'exists', unmocked_exists) + class GetExcludePatternsForDir(unittest.TestCase): @@ -92,6 +101,41 @@ def test_with_local_style(self): self.assertEqual(style_file, file_resources.GetDefaultStyleForDir(test_filename)) + def test_setup_config(self): + # An empty setup.cfg file should not be used + setup_config = os.path.join(self.test_tmpdir, 'setup.cfg') + open(setup_config, 'w').close() + + test_dir = os.path.join(self.test_tmpdir, 'dir1') + style_name = file_resources.GetDefaultStyleForDir(test_dir) + self.assertEqual(style_name, 'pep8') + + # One with a '[yapf]' section should be used + with open(setup_config, 'w') as f: + f.write('[yapf]\n') + self.assertEqual(setup_config, + file_resources.GetDefaultStyleForDir(test_dir)) + + def test_local_style_at_root(self): + # Test behavior of files located on the root, and under root. + rootdir = os.path.abspath(os.path.sep) + test_dir_at_root = os.path.join(rootdir, 'dir1') + test_dir_under_root = os.path.join(rootdir, 'dir1', 'dir2') + + # Fake placing only a style file at the root by mocking `os.path.exists`. + style_file = os.path.join(rootdir, '.style.yapf') + def mock_exists_implementation(path): + return path == style_file + with _exists_mocked_in_module(file_resources.os.path, + mock_exists_implementation): + # Both files should find the style file at the root. + default_style_at_root = file_resources.GetDefaultStyleForDir( + test_dir_at_root) + self.assertEqual(style_file, default_style_at_root) + default_style_under_root = file_resources.GetDefaultStyleForDir( + test_dir_under_root) + self.assertEqual(style_file, default_style_under_root) + def _touch_files(filenames): for name in filenames: From b1123fdfc6a1b74d624f6bb3c4fdf2c2657d189f Mon Sep 17 00:00:00 2001 From: Eric An Date: Thu, 18 Jul 2019 20:24:24 -0700 Subject: [PATCH 404/719] heard you like yapf... --- yapftests/file_resources_test.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index b88afd881..c728bfc68 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -37,12 +37,12 @@ def _restore_working_dir(): @contextlib.contextmanager def _exists_mocked_in_module(module, mock_implementation): - unmocked_exists = getattr(module, 'exists') - setattr(module, 'exists', mock_implementation) - try: - yield - finally: - setattr(module, 'exists', unmocked_exists) + unmocked_exists = getattr(module, 'exists') + setattr(module, 'exists', mock_implementation) + try: + yield + finally: + setattr(module, 'exists', unmocked_exists) class GetExcludePatternsForDir(unittest.TestCase): @@ -124,8 +124,10 @@ def test_local_style_at_root(self): # Fake placing only a style file at the root by mocking `os.path.exists`. style_file = os.path.join(rootdir, '.style.yapf') + def mock_exists_implementation(path): return path == style_file + with _exists_mocked_in_module(file_resources.os.path, mock_exists_implementation): # Both files should find the style file at the root. From 11ec20dedc284d219962d5298e80d6b5bb6547ed Mon Sep 17 00:00:00 2001 From: Eric An Date: Thu, 18 Jul 2019 20:26:51 -0700 Subject: [PATCH 405/719] ... so we yapfed your yapf --- yapftests/file_resources_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index c728bfc68..07e31342e 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -35,6 +35,7 @@ def _restore_working_dir(): finally: os.chdir(curdir) + @contextlib.contextmanager def _exists_mocked_in_module(module, mock_implementation): unmocked_exists = getattr(module, 'exists') From 1909d2e408ebf474fb48d715092c07d4d1383aa1 Mon Sep 17 00:00:00 2001 From: Eric An Date: Fri, 19 Jul 2019 08:41:25 -0700 Subject: [PATCH 406/719] updating CHANGELOG --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index a655589c8..4385ee3d6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,8 @@ ### Fixed - Format subscript lists so that splits are essentially free after a comma. - Don't add a space between a string and its subscript. +- Extend discovery of '.style.yapf' & 'setup.cfg' files to search the root + directory as well. ## [0.28.0] 2019-07-11 ### Added From d394d8045f67ffc96bc36ce3d88ac9c33ebd5383 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 20 Jul 2019 14:22:20 -0700 Subject: [PATCH 407/719] Ensure params exist when calculating their penalties --- CHANGELOG | 2 ++ yapf/yapflib/format_decision_state.py | 5 +++++ yapftests/reformatter_buganizer_test.py | 10 ++++++++++ 3 files changed, 17 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 4385ee3d6..4996e6b25 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,8 @@ - Don't add a space between a string and its subscript. - Extend discovery of '.style.yapf' & 'setup.cfg' files to search the root directory as well. +- Make sure we have parameters before we start calculating penalties for + splitting them. ## [0.28.0] 2019-07-11 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 71d57bd72..3fac458c2 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -887,6 +887,11 @@ def _CalculateParameterListState(self, newline): # and we've already split before the first parameter. penalty += split_penalty.STRONGLY_CONNECTED + return penalty + + if not param_list.parameters: + return penalty + if newline: if self._FitsOnLine(param_list.parameters[0].first_token, _LastTokenInLine(param_list.closing_bracket)): diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index e4218b13d..eb0cc8ace 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -28,6 +28,16 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): def setUpClass(cls): style.SetGlobalStyle(style.CreateChromiumStyle()) + def testB137580392(self): + code = """\ +def _create_testing_simulator_and_sink( +) -> Tuple[_batch_simulator:_batch_simulator.BatchSimulator, + _batch_simulator.SimulationSink]: + pass +""" + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testB73279849(self): unformatted_code = """\ class A: From 016ce60cead84a6db2605a8cff2f2b6582d7e85c Mon Sep 17 00:00:00 2001 From: Steven Lee Date: Mon, 29 Jul 2019 15:04:12 +1000 Subject: [PATCH 408/719] Add ignore rule for PyCharm (.idea) --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 3fd6b2b3b..960818e0f 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,6 @@ /dist /.tox /yapf.egg-info + +/.idea + From 7c44b5903e57bd6a194d02f98acd9761129ad3bd Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 6 Aug 2019 00:34:55 -0700 Subject: [PATCH 409/719] Use single quotes and don't format the string --- yapf/yapflib/yapf_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 618e85d0c..f5240abce 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -204,8 +204,8 @@ def ReadFile(filename, logger=None): raise except UnicodeDecodeError as err: # pragma: no cover if logger: - logger("Could not parse {}! Consider excluding this file with --exclude." - .format(filename)) + logger('Could not parse %s! Consider excluding this file with --exclude.', + filename) logger(err) raise From 052b9dccf07381b0ae210bf860ae41dac0c4c929 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 6 Aug 2019 00:41:29 -0700 Subject: [PATCH 410/719] Update the CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 95ce3fbb7..aff99bc8c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,7 @@ unnecessary splits). ### Changed - Set `INDENT_DICTIONARY_VALUE` for Google style. +- Catch and report `UnicodeDecodeError` exceptions. ### Fixed - `BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=False` wasn't honored because the number of newlines was erroneously calculated beforehand. From 28f86f14854780d6ff8d31e9add92b21ba66308c Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 6 Aug 2019 01:01:14 -0700 Subject: [PATCH 411/719] Don't print information if quiet is enabled --- yapf/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 62d9faa73..50f8328e9 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -290,7 +290,7 @@ def _FormatFile(filename, quiet=False, verbose=False): """Format an individual file.""" - if verbose: + if verbose and not quiet: print('Reformatting %s' % filename) if style_config is None and not no_local_style: style_config = file_resources.GetDefaultStyleForDir( From 1d1eb3058f8d45f703f9f5ef7fe68c8f4dfbe2cd Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 6 Aug 2019 01:04:46 -0700 Subject: [PATCH 412/719] Update CHANGELOG --- CHANGELOG | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c7bdc762e..da7ce1b2d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,11 +2,15 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.28.1] UNRELEASED +## [0.29.0] UNRELEASED +### Added +- Add the `--quiet` flag to suppress output. The return code is 1 if there are + changes, similarly to the `--diff` flag. ### Changed - Collect a parameter list into a single object. This allows us to track how a parameter list is formatted, keeping state along the way. This helps when supporting Python 3 type annotations. +- Catch and report `UnicodeDecodeError` exceptions. ### Fixed - Format subscript lists so that splits are essentially free after a comma. - Don't add a space between a string and its subscript. @@ -24,7 +28,6 @@ ### Changed - Set `INDENT_DICTIONARY_VALUE` for Google style. - Set `JOIN_MULTIPLE_LINES = False` for Google style. -- Catch and report `UnicodeDecodeError` exceptions. ### Fixed - `BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=False` wasn't honored because the number of newlines was erroneously calculated beforehand. From 3d6e039be929f030bab1391a0ca547f05dde9f7a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 6 Aug 2019 01:08:05 -0700 Subject: [PATCH 413/719] Reformat __init__.py --- yapf/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 50f8328e9..ef7e77f07 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -267,9 +267,8 @@ def FormatFiles(filenames, with concurrent.futures.ProcessPoolExecutor(workers) as executor: future_formats = [ executor.submit(_FormatFile, filename, lines, style_config, - no_local_style, in_place, print_diff, verify, - quiet, verbose) - for filename in filenames + no_local_style, in_place, print_diff, verify, quiet, + verbose) for filename in filenames ] for future in concurrent.futures.as_completed(future_formats): changed |= future.result() From c22ce76f1f019aa362c879a42aff2655efb9a967 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 13 Aug 2019 14:28:22 -0700 Subject: [PATCH 414/719] Indicate if this is a nested class/function Closes #742 --- CHANGELOG | 1 + yapf/yapflib/reformatter.py | 27 +++++++++++++++++++++++---- yapftests/reformatter_pep8_test.py | 24 ++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index da7ce1b2d..2195884e7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -18,6 +18,7 @@ directory as well. - Make sure we have parameters before we start calculating penalties for splitting them. +- Indicate if a class/function is nested to ensure blank lines when needed. ## [0.28.0] 2019-07-11 ### Added diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 73165b0b7..2968a581f 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -559,6 +559,10 @@ def _ReconstructPath(initial_state, current): initial_state.AddTokenToState(newline=node.newline, dry_run=False) +_ClassDepth = [] +_FuncDepth = [] + + def _FormatFirstToken(first_token, indent_depth, prev_uwline, final_lines): """Format the first token in the unwrapped line. @@ -574,9 +578,23 @@ def _FormatFirstToken(first_token, indent_depth, prev_uwline, final_lines): final_lines: (list of unwrapped_line.UnwrappedLine) The unwrapped lines that have already been processed. """ + if _FuncDepth and _FuncDepth[-1] == indent_depth: + _FuncDepth.pop() + if _ClassDepth and _ClassDepth[-1] == indent_depth: + _ClassDepth.pop() + + nested = False + if _IsClassOrDef(first_token): + if first_token.value == 'class': + nested = len(_ClassDepth) > 1 or len(_FuncDepth) > 1 + _ClassDepth.append(indent_depth) + else: + nested = len(_FuncDepth) > 1 + _FuncDepth.append(indent_depth) + first_token.AddWhitespacePrefix( _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, - final_lines), + final_lines, nested), indent_level=indent_depth) @@ -593,7 +611,7 @@ def _IsClassOrDef(tok): def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, - final_lines): + final_lines, nested): """Calculate the number of newlines we need to add. Arguments: @@ -604,6 +622,7 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, previous to this line. final_lines: (list of unwrapped_line.UnwrappedLine) The unwrapped lines that have already been processed. + nested: (boolean) Whether this is a nested class or function. Returns: The number of newlines needed before the first token. @@ -636,7 +655,7 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, # Separate a class or function from the module-level docstring with # appropriate number of blank lines. return 1 + style.Get('BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION') - if (not style.Get('BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF') and + if (nested and not style.Get('BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF') and _IsClassOrDef(first_token)): pytree_utils.SetNodeAnnotation(first_token.node, pytree_utils.Annotation.NEWLINES, None) @@ -647,7 +666,7 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, else: return ONE_BLANK_LINE - if first_token.value in {'class', 'def', 'async', '@'}: + if _IsClassOrDef(first_token): # TODO(morbo): This can go once the blank line calculator is more # sophisticated. if not indent_depth: diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 92c2a2913..6454a7527 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -64,6 +64,30 @@ def joe(): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testNoBlankBetweenDefsInClass(self): + unformatted_code = textwrap.dedent('''\ + class TestClass: + def __init__(self): + self.running = False + def run(self): + """Override in subclass""" + def is_running(self): + return self.running + ''') + expected_formatted_code = textwrap.dedent('''\ + class TestClass: + def __init__(self): + self.running = False + + def run(self): + """Override in subclass""" + + def is_running(self): + return self.running + ''') + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testSingleWhiteBeforeTrailingComment(self): unformatted_code = textwrap.dedent("""\ if a+b: # comment From 214ca41ae46acd10943afae474849bd9c1c0a825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A4in=C3=B6=20J=C3=A4rvel=C3=A4?= Date: Wed, 13 Nov 2019 09:50:01 +0200 Subject: [PATCH 415/719] Fix async for else indentation Previously: async def fn(): async for message in websocket: pass else: pass was indented as: async def fn(): async for message in websocket: pass else: pass which breaks the code and crashes any further runs of yapf on that codebase because of parse errors. --- yapf/yapflib/pytree_unwrapper.py | 2 ++ yapftests/reformatter_python3_test.py | 29 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index f4d9cbafc..06ff07bb4 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -224,6 +224,8 @@ def Visit_async_stmt(self, node): # pylint: disable=invalid-name if pytree_utils.NodeName(child) == 'ASYNC': break for child in node.children[index].children: + if (child.type == grammar_token.NAME and child.value == 'else'): + self._StartNewLine() self.Visit(child) def Visit_decorator(self, node): # pylint: disable=invalid-name diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index ff7bf749b..83f6a70ed 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -398,6 +398,35 @@ def rrrrrrrrrrrrrrrrrrrrrr( uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testAsyncForElseNotIndentedInsideBody(self): + if sys.version_info[1] < 5: + return + code = textwrap.dedent("""\ + async def fn(): + async for message in websocket: + for i in range(10): + pass + else: + pass + else: + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testForElseInAsyncNotMixedWithAsyncFor(self): + if sys.version_info[1] < 5: + return + code = textwrap.dedent("""\ + async def fn(): + for i in range(10): + pass + else: + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From 719a981a9e5dc35366ed859b91235e923d018816 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A4in=C3=B6=20J=C3=A4rvel=C3=A4?= Date: Thu, 14 Nov 2019 06:39:52 +0200 Subject: [PATCH 416/719] Update CHANGELOG for async-for else fix --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 2195884e7..1f3002d95 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,6 +19,7 @@ - Make sure we have parameters before we start calculating penalties for splitting them. - Indicate if a class/function is nested to ensure blank lines when needed. +- Fix extra indentation in async-for else statement. ## [0.28.0] 2019-07-11 ### Added From a850e52d18897a9300fb3ac57c12096c4a412c80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A4in=C3=B6=20J=C3=A4rvel=C3=A4?= Date: Thu, 14 Nov 2019 06:40:56 +0200 Subject: [PATCH 417/719] Use pytree_utils instead of direct field access --- yapf/yapflib/pytree_unwrapper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index 06ff07bb4..4858563e0 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -224,7 +224,7 @@ def Visit_async_stmt(self, node): # pylint: disable=invalid-name if pytree_utils.NodeName(child) == 'ASYNC': break for child in node.children[index].children: - if (child.type == grammar_token.NAME and child.value == 'else'): + if (pytree_utils.NodeName(child) == 'NAME' and child.value == 'else'): self._StartNewLine() self.Visit(child) From 24a15a55f4d653c7da1fe13ce535d07d0118100b Mon Sep 17 00:00:00 2001 From: Bill Wendling <5993918+gwelymernans@users.noreply.github.com> Date: Wed, 13 Nov 2019 23:20:59 -0800 Subject: [PATCH 418/719] Update pytree_unwrapper.py --- yapf/yapflib/pytree_unwrapper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index 4858563e0..c7e32a3e5 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -224,7 +224,7 @@ def Visit_async_stmt(self, node): # pylint: disable=invalid-name if pytree_utils.NodeName(child) == 'ASYNC': break for child in node.children[index].children: - if (pytree_utils.NodeName(child) == 'NAME' and child.value == 'else'): + if pytree_utils.NodeName(child) == 'NAME' and child.value == 'else': self._StartNewLine() self.Visit(child) From c35fae17637b0d79ca1750f66106a5a7bb08c6df Mon Sep 17 00:00:00 2001 From: Ethan Furman Date: Thu, 14 Nov 2019 10:32:42 -0800 Subject: [PATCH 419/719] add INDENT_CLOSING_BRACKETS option unlike CLOSING_INDENT_BRACKETS, this option leaves the final bracket aligned with the previous line's first column --- yapf/yapflib/format_decision_state.py | 14 ++++++++------ yapf/yapflib/split_penalty.py | 4 ++-- yapf/yapflib/style.py | 20 ++++++++++++++++++++ 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 3fac458c2..2c2c2829e 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -195,7 +195,8 @@ def MustSplit(self): return not self._ContainerFitsOnStartLine(opening) if (self.stack[-1].split_before_closing_bracket and - current.value in '}]' and style.Get('SPLIT_BEFORE_CLOSING_BRACKET')): + (current.value in '}]' and style.Get('SPLIT_BEFORE_CLOSING_BRACKET') or + current.value in '}])' and style.Get('INDENT_CLOSING_BRACKETS'))): # Split before the closing bracket if we can. if format_token.Subtype.SUBSCRIPT_BRACKET not in current.subtypes: return current.node_split_penalty != split_penalty.UNBREAKABLE @@ -214,6 +215,7 @@ def MustSplit(self): ########################################################################### # List Splitting if (style.Get('DEDENT_CLOSING_BRACKETS') or + style.Get('INDENT_CLOSING_BRACKETS') or style.Get('SPLIT_BEFORE_FIRST_ARGUMENT')): bracket = current if current.ClosesScope() else previous if format_token.Subtype.SUBSCRIPT_BRACKET not in bracket.subtypes: @@ -235,7 +237,8 @@ def MustSplit(self): self.stack[-1].split_before_closing_bracket = True return True - elif style.Get('DEDENT_CLOSING_BRACKETS') and current.ClosesScope(): + elif (style.Get('DEDENT_CLOSING_BRACKETS') or + style.Get('INDENT_CLOSING_BRACKETS')) and current.ClosesScope(): # Split before and dedent the closing bracket. return self.stack[-1].split_before_closing_bracket @@ -649,9 +652,8 @@ def _AddTokenOnNewline(self, dry_run, must_split): if (previous.OpensScope() or (previous.is_comment and previous.previous_token is not None and previous.previous_token.OpensScope())): - self.stack[-1].closing_scope_indent = max( - 0, self.stack[-1].indent - style.Get('CONTINUATION_INDENT_WIDTH')) - + dedent = (style.Get('CONTINUATION_INDENT_WIDTH'), 0)[style.Get('INDENT_CLOSING_BRACKETS')] + self.stack[-1].closing_scope_indent = max(0, self.stack[-1].indent - dedent) self.stack[-1].split_before_closing_bracket = True # Calculate the split penalty. @@ -942,7 +944,7 @@ def _GetNewlineColumn(self): return top_of_stack.indent if (_IsCompoundStatement(self.line.first) and - (not style.Get('DEDENT_CLOSING_BRACKETS') or + (not (style.Get('DEDENT_CLOSING_BRACKETS') or style.Get('INDENT_CLOSING_BRACKETS')) or style.Get('SPLIT_BEFORE_FIRST_ARGUMENT'))): token_indent = ( len(self.line.first.whitespace_prefix.split('\n')[-1]) + diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index e15ea2e67..a5a648753 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -139,7 +139,7 @@ def Visit_parameters(self, node): # pylint: disable=invalid-name # Can't break before the opening paren of a parameter list. _SetUnbreakable(node.children[0]) - if not style.Get('DEDENT_CLOSING_BRACKETS'): + if not (style.Get('INDENT_CLOSING_BRACKETS') or style.Get('DEDENT_CLOSING_BRACKETS')): _SetStronglyConnected(node.children[-1]) def Visit_arglist(self, node): # pylint: disable=invalid-name @@ -321,7 +321,7 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring last_child_node = pytree_utils.LastLeafNode(trailer) if last_child_node.value.strip().startswith('#'): last_child_node = last_child_node.prev_sibling - if not style.Get('DEDENT_CLOSING_BRACKETS'): + if not (style.Get('INDENT_CLOSING_BRACKETS') or style.Get('DEDENT_CLOSING_BRACKETS')): last = pytree_utils.LastLeafNode(last_child_node.prev_sibling) if last.value != ',': if last_child_node.value == ']': diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index e614e6252..77c91723b 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -150,6 +150,23 @@ def method(): start_ts=now()-timedelta(days=3), end_ts=now(), ) # <--- this bracket is dedented and on a separate line"""), + INDENT_CLOSING_BRACKETS=textwrap.dedent("""\ + Put closing brackets on a separate line, indented, if the bracketed + expression can't fit in a single line. Applies to all kinds of brackets, + including function definitions and calls. For example: + + config = { + 'key1': 'value1', + 'key2': 'value2', + } # <--- this bracket is indented and on a separate line + + time_series = self.remote_client.query_entity_counters( + entity='dev3246.region1', + key='dns.query_latency_tcp', + transform=Transformation.AVERAGE(window=timedelta(seconds=60)), + start_ts=now()-timedelta(days=3), + end_ts=now(), + ) # <--- this bracket is indented and on a separate line"""), DISABLE_ENDING_COMMA_HEURISTIC=textwrap.dedent("""\ Disable the heuristic which places each list element on a separate line if the list is comma-terminated."""), @@ -355,6 +372,7 @@ def CreatePEP8Style(): CONTINUATION_ALIGN_STYLE='SPACE', CONTINUATION_INDENT_WIDTH=4, DEDENT_CLOSING_BRACKETS=False, + INDENT_CLOSING_BRACKETS=False, DISABLE_ENDING_COMMA_HEURISTIC=False, EACH_DICT_ENTRY_ON_SEPARATE_LINE=True, I18N_COMMENT='', @@ -431,6 +449,7 @@ def CreateFacebookStyle(): style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False style['COLUMN_LIMIT'] = 80 style['DEDENT_CLOSING_BRACKETS'] = True + style['INDENT_CLOSING_BRACKETS'] = False style['INDENT_DICTIONARY_VALUE'] = True style['JOIN_MULTIPLE_LINES'] = False style['SPACES_BEFORE_COMMENT'] = 2 @@ -532,6 +551,7 @@ def _IntOrIntListConverter(s): CONTINUATION_ALIGN_STYLE=_ContinuationAlignStyleStringConverter, CONTINUATION_INDENT_WIDTH=int, DEDENT_CLOSING_BRACKETS=_BoolConverter, + INDENT_CLOSING_BRACKETS=_BoolConverter, DISABLE_ENDING_COMMA_HEURISTIC=_BoolConverter, EACH_DICT_ENTRY_ON_SEPARATE_LINE=_BoolConverter, I18N_COMMENT=str, From b09e65958b8ddbbfe27489d503463959deed1f7d Mon Sep 17 00:00:00 2001 From: Ethan Furman Date: Thu, 14 Nov 2019 10:51:32 -0800 Subject: [PATCH 420/719] fix formatting --- yapf/yapflib/format_decision_state.py | 9 ++++++--- yapf/yapflib/split_penalty.py | 6 ++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 2c2c2829e..04ed9112c 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -652,8 +652,10 @@ def _AddTokenOnNewline(self, dry_run, must_split): if (previous.OpensScope() or (previous.is_comment and previous.previous_token is not None and previous.previous_token.OpensScope())): - dedent = (style.Get('CONTINUATION_INDENT_WIDTH'), 0)[style.Get('INDENT_CLOSING_BRACKETS')] - self.stack[-1].closing_scope_indent = max(0, self.stack[-1].indent - dedent) + dedent = (style.Get('CONTINUATION_INDENT_WIDTH'), + 0)[style.Get('INDENT_CLOSING_BRACKETS')] + self.stack[-1].closing_scope_indent = max(0, + self.stack[-1].indent - dedent) self.stack[-1].split_before_closing_bracket = True # Calculate the split penalty. @@ -944,7 +946,8 @@ def _GetNewlineColumn(self): return top_of_stack.indent if (_IsCompoundStatement(self.line.first) and - (not (style.Get('DEDENT_CLOSING_BRACKETS') or style.Get('INDENT_CLOSING_BRACKETS')) or + (not (style.Get('DEDENT_CLOSING_BRACKETS') or + style.Get('INDENT_CLOSING_BRACKETS')) or style.Get('SPLIT_BEFORE_FIRST_ARGUMENT'))): token_indent = ( len(self.line.first.whitespace_prefix.split('\n')[-1]) + diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index a5a648753..958c76eaf 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -139,7 +139,8 @@ def Visit_parameters(self, node): # pylint: disable=invalid-name # Can't break before the opening paren of a parameter list. _SetUnbreakable(node.children[0]) - if not (style.Get('INDENT_CLOSING_BRACKETS') or style.Get('DEDENT_CLOSING_BRACKETS')): + if not (style.Get('INDENT_CLOSING_BRACKETS') or + style.Get('DEDENT_CLOSING_BRACKETS')): _SetStronglyConnected(node.children[-1]) def Visit_arglist(self, node): # pylint: disable=invalid-name @@ -321,7 +322,8 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring last_child_node = pytree_utils.LastLeafNode(trailer) if last_child_node.value.strip().startswith('#'): last_child_node = last_child_node.prev_sibling - if not (style.Get('INDENT_CLOSING_BRACKETS') or style.Get('DEDENT_CLOSING_BRACKETS')): + if not (style.Get('INDENT_CLOSING_BRACKETS') or + style.Get('DEDENT_CLOSING_BRACKETS')): last = pytree_utils.LastLeafNode(last_child_node.prev_sibling) if last.value != ',': if last_child_node.value == ']': From b5085620314e5b10863096649f16eb7d4961dba7 Mon Sep 17 00:00:00 2001 From: Ethan Furman Date: Thu, 14 Nov 2019 13:45:12 -0800 Subject: [PATCH 421/719] update README.rst and CHANGELOG --- CHANGELOG | 3 +++ README.rst | 23 ++++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 1f3002d95..49ad9955a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,9 @@ ### Added - Add the `--quiet` flag to suppress output. The return code is 1 if there are changes, similarly to the `--diff` flag. +- Add the `indent_closing_brackets` option. This is the same as the + `dedent_closing_brackets` option except the brackets are indented the same + as the previous line. ### Changed - Collect a parameter list into a single object. This allows us to track how a parameter list is formatted, keeping state along the way. This helps when diff --git a/README.rst b/README.rst index 6ab3132f5..0d86e3de2 100644 --- a/README.rst +++ b/README.rst @@ -394,7 +394,8 @@ Knobs ``COALESCE_BRACKETS`` Do not split consecutive brackets. Only relevant when - ``DEDENT_CLOSING_BRACKETS`` is set. For example: + ``DEDENT_CLOSING_BRACKETS`` or ``INDENT_CLOSING_BRACKETS`` + is set. For example: .. code-block:: python @@ -492,6 +493,26 @@ Knobs ``INDENT_BLANK_LINES`` Set to ``True`` to prefer indented blank lines rather than empty +``INDENT_CLOSING_BRACKETS`` + Put closing brackets on a separate line, indented, if the bracketed + expression can't fit in a single line. Applies to all kinds of brackets, + including function definitions and calls. For example: + + .. code-block:: python + + config = { + 'key1': 'value1', + 'key2': 'value2', + } # <--- this bracket is indented and on a separate line + + time_series = self.remote_client.query_entity_counters( + entity='dev3246.region1', + key='dns.query_latency_tcp', + transform=Transformation.AVERAGE(window=timedelta(seconds=60)), + start_ts=now()-timedelta(days=3), + end_ts=now(), + ) # <--- this bracket is indented and on a separate line + ``JOIN_MULTIPLE_LINES`` Join short lines into one line. E.g., single line ``if`` statements. From 63edb7f1b4b6d2a150932ae91b5f094f459a5283 Mon Sep 17 00:00:00 2001 From: Ethan Furman Date: Thu, 14 Nov 2019 16:33:49 -0800 Subject: [PATCH 422/719] add tests covering function call, tuple, list, and dict --- yapftests/reformatter_basic_test.py | 169 ++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index be3fbbcc9..bbceb21b7 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2710,6 +2710,175 @@ def function( finally: style.SetGlobalStyle(style.CreateChromiumStyle()) + def testIndentClosingBracketsWithTypeAnnotationExceedingLineLength(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{based_on_style: chromium,' + ' indent_closing_brackets: True}')) + unformatted_code = textwrap.dedent("""\ + def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: + pass + + + def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def function( + first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None + ) -> None: + pass + + + def function( + first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None + ) -> None: + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + + def testIndentClosingBracketsInFunctionCall(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{based_on_style: chromium,' + ' indent_closing_brackets: True}')) + unformatted_code = textwrap.dedent("""\ + def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None, third_and_final_argument=True): + pass + + + def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_and_last_argument=None): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def function( + first_argument_xxxxxxxxxxxxxxxx=(0,), + second_argument=None, + third_and_final_argument=True + ): + pass + + + def function( + first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_and_last_argument=None + ): + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + + def testIndentClosingBracketsInTuple(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{based_on_style: chromium,' + ' indent_closing_brackets: True}')) + unformatted_code = textwrap.dedent("""\ + def function(): + some_var = ('a long element', 'another long element', 'short element', 'really really long element') + return True + + def function(): + some_var = ('a couple', 'small', 'elemens') + return False + """) + expected_formatted_code = textwrap.dedent("""\ + def function(): + some_var = ( + 'a long element', 'another long element', 'short element', + 'really really long element' + ) + return True + + + def function(): + some_var = ('a couple', 'small', 'elemens') + return False + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + + def testIndentClosingBracketsInList(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{based_on_style: chromium,' + ' indent_closing_brackets: True}')) + unformatted_code = textwrap.dedent("""\ + def function(): + some_var = ['a long element', 'another long element', 'short element', 'really really long element'] + return True + + def function(): + some_var = ['a couple', 'small', 'elemens'] + return False + """) + expected_formatted_code = textwrap.dedent("""\ + def function(): + some_var = [ + 'a long element', 'another long element', 'short element', + 'really really long element' + ] + return True + + + def function(): + some_var = ['a couple', 'small', 'elemens'] + return False + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + + def testIndentClosingBracketsInDict(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{based_on_style: chromium,' + ' indent_closing_brackets: True}')) + unformatted_code = textwrap.dedent("""\ + def function(): + some_var = {1: ('a long element', 'and another really really long element that is really really amazingly long'), 2: 'another long element', 3: 'short element', 4: 'really really long element'} + return True + + def function(): + some_var = {1: 'a couple', 2: 'small', 3: 'elemens'} + return False + """) + expected_formatted_code = textwrap.dedent("""\ + def function(): + some_var = { + 1: + ( + 'a long element', + 'and another really really long element that is really really amazingly long' + ), + 2: 'another long element', + 3: 'short element', + 4: 'really really long element' + } + return True + + + def function(): + some_var = {1: 'a couple', 2: 'small', 3: 'elemens'} + return False + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + def testMultipleDictionariesInList(self): unformatted_code = """\ class A: From ae3145ffa626327361b74986a5d294cb0ec0aba2 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 23 Nov 2019 15:18:12 -0800 Subject: [PATCH 423/719] An empty parameter list doesn't count as exceeding the clolumn limit --- CHANGELOG | 2 ++ yapf/yapflib/object_state.py | 2 ++ yapftests/reformatter_python3_test.py | 13 +++++++++++++ 3 files changed, 17 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 49ad9955a..9c5b67b38 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -23,6 +23,8 @@ splitting them. - Indicate if a class/function is nested to ensure blank lines when needed. - Fix extra indentation in async-for else statement. +- A parameter list with no elements shouldn't count as exceeding the column + limit. ## [0.28.0] 2019-07-11 ### Added diff --git a/yapf/yapflib/object_state.py b/yapf/yapflib/object_state.py index 124ae6566..246476938 100644 --- a/yapf/yapflib/object_state.py +++ b/yapf/yapflib/object_state.py @@ -125,6 +125,8 @@ def LastParamFitsOnLine(self, indent): """Return true if the last parameter fits on a single line.""" if not self.has_typed_return: return False + if not self.parameters: + return True last_param = self.parameters[-1].first_token last_token = self.opening_bracket.matching_bracket while not last_token.is_comment and last_token.next_token: diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index 83f6a70ed..7e55fcba3 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -47,6 +47,19 @@ def x(aaaaaaaaaaaaaaa: int, uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testTypedNameWithLongNamedArg(self): + unformatted_code = textwrap.dedent("""\ + def func(arg=long_function_call_that_pushes_the_line_over_eighty_characters()) -> ReturnType: + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def func(arg=long_function_call_that_pushes_the_line_over_eighty_characters() + ) -> ReturnType: + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testKeywordOnlyArgSpecifier(self): unformatted_code = textwrap.dedent("""\ def foo(a, *, kw): From 0c0ed952d3be48a54c0d205ad5958bcb7b135849 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 27 Nov 2019 16:00:42 -0800 Subject: [PATCH 424/719] Rename globals to satisfy the linter --- yapf/yapflib/reformatter.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 2968a581f..9b6bca2a9 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -559,8 +559,8 @@ def _ReconstructPath(initial_state, current): initial_state.AddTokenToState(newline=node.newline, dry_run=False) -_ClassDepth = [] -_FuncDepth = [] +_CLASS_DEPTH = [] +_FUNC_DEPTH = [] def _FormatFirstToken(first_token, indent_depth, prev_uwline, final_lines): @@ -578,19 +578,19 @@ def _FormatFirstToken(first_token, indent_depth, prev_uwline, final_lines): final_lines: (list of unwrapped_line.UnwrappedLine) The unwrapped lines that have already been processed. """ - if _FuncDepth and _FuncDepth[-1] == indent_depth: - _FuncDepth.pop() - if _ClassDepth and _ClassDepth[-1] == indent_depth: - _ClassDepth.pop() + if _FUNC_DEPTH and _FUNC_DEPTH[-1] == indent_depth: + _FUNC_DEPTH.pop() + if _CLASS_DEPTH and _CLASS_DEPTH[-1] == indent_depth: + _CLASS_DEPTH.pop() nested = False if _IsClassOrDef(first_token): if first_token.value == 'class': - nested = len(_ClassDepth) > 1 or len(_FuncDepth) > 1 - _ClassDepth.append(indent_depth) + nested = len(_CLASS_DEPTH) > 1 or len(_FUNC_DEPTH) > 1 + _CLASS_DEPTH.append(indent_depth) else: - nested = len(_FuncDepth) > 1 - _FuncDepth.append(indent_depth) + nested = len(_FUNC_DEPTH) > 1 + _FUNC_DEPTH.append(indent_depth) first_token.AddWhitespacePrefix( _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, From f05ca12601dc3deeebfd4084e240235ed8993c1a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 27 Nov 2019 16:25:40 -0800 Subject: [PATCH 425/719] Treat the closing bracket like normal when splitting everything Closes #771 --- CHANGELOG | 2 ++ yapf/yapflib/format_decision_state.py | 6 ++++-- yapftests/reformatter_basic_test.py | 12 ++++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9c5b67b38..e2ac6c1fb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -25,6 +25,8 @@ - Fix extra indentation in async-for else statement. - A parameter list with no elements shouldn't count as exceeding the column limit. +- When splitting all comma separated values, don't treat the ending bracket as + special. ## [0.28.0] 2019-07-11 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 04ed9112c..17ade12ac 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -191,8 +191,10 @@ def MustSplit(self): if not opening: return True - # If the container doesn't fit in the current line, must split - return not self._ContainerFitsOnStartLine(opening) + # Allow the fallthrough code to handle the closing bracket. + if current != opening.matching_bracket: + # If the container doesn't fit in the current line, must split + return not self._ContainerFitsOnStartLine(opening) if (self.stack[-1].split_before_closing_bracket and (current.value in '}]' and style.Get('SPLIT_BEFORE_CLOSING_BRACKET') or diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index bbceb21b7..7e5cf287a 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -45,6 +45,18 @@ def testSplittingAllArgs(self): """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + unformatted_code = textwrap.dedent("""\ + yes = { 'yes': 'no', 'no': 'yes', } + """) + expected_formatted_code = textwrap.dedent("""\ + yes = { + 'yes': 'no', + 'no': 'yes', + } + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) unformatted_code = textwrap.dedent("""\ def foo(long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args): pass From 172508e90a73c5c26c421fd548ad0ba9d8b0bbd6 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 27 Nov 2019 16:56:38 -0800 Subject: [PATCH 426/719] Only the blank line only between the first nested class or function Closes #770 --- CHANGELOG | 2 ++ yapf/yapflib/reformatter.py | 34 ++++++++++++++---------------- yapftests/reformatter_pep8_test.py | 33 +++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e2ac6c1fb..a2f18f1f9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -27,6 +27,8 @@ limit. - When splitting all comma separated values, don't treat the ending bracket as special. +- The "no blank lines between nested classes or functions" knob should only + apply to the first nested class or function, not all of them. ## [0.28.0] 2019-07-11 ### Added diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 9b6bca2a9..f690a79df 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -559,8 +559,7 @@ def _ReconstructPath(initial_state, current): initial_state.AddTokenToState(newline=node.newline, dry_run=False) -_CLASS_DEPTH = [] -_FUNC_DEPTH = [] +NESTED_DEPTH = [] def _FormatFirstToken(first_token, indent_depth, prev_uwline, final_lines): @@ -578,23 +577,21 @@ def _FormatFirstToken(first_token, indent_depth, prev_uwline, final_lines): final_lines: (list of unwrapped_line.UnwrappedLine) The unwrapped lines that have already been processed. """ - if _FUNC_DEPTH and _FUNC_DEPTH[-1] == indent_depth: - _FUNC_DEPTH.pop() - if _CLASS_DEPTH and _CLASS_DEPTH[-1] == indent_depth: - _CLASS_DEPTH.pop() + global NESTED_DEPTH + while NESTED_DEPTH and NESTED_DEPTH[-1] > indent_depth: + NESTED_DEPTH.pop() - nested = False + first_nested = False if _IsClassOrDef(first_token): - if first_token.value == 'class': - nested = len(_CLASS_DEPTH) > 1 or len(_FUNC_DEPTH) > 1 - _CLASS_DEPTH.append(indent_depth) - else: - nested = len(_FUNC_DEPTH) > 1 - _FUNC_DEPTH.append(indent_depth) + if not NESTED_DEPTH: + NESTED_DEPTH = [indent_depth] + elif NESTED_DEPTH[-1] < indent_depth: + first_nested = True + NESTED_DEPTH.append(indent_depth) first_token.AddWhitespacePrefix( _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, - final_lines, nested), + final_lines, first_nested), indent_level=indent_depth) @@ -611,7 +608,7 @@ def _IsClassOrDef(tok): def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, - final_lines, nested): + final_lines, first_nested): """Calculate the number of newlines we need to add. Arguments: @@ -622,7 +619,7 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, previous to this line. final_lines: (list of unwrapped_line.UnwrappedLine) The unwrapped lines that have already been processed. - nested: (boolean) Whether this is a nested class or function. + first_nested: (boolean) Whether this is the first nested class or function. Returns: The number of newlines needed before the first token. @@ -655,7 +652,8 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, # Separate a class or function from the module-level docstring with # appropriate number of blank lines. return 1 + style.Get('BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION') - if (nested and not style.Get('BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF') and + if (first_nested and + not style.Get('BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF') and _IsClassOrDef(first_token)): pytree_utils.SetNodeAnnotation(first_token.node, pytree_utils.Annotation.NEWLINES, None) @@ -695,7 +693,7 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, None) return NO_BLANK_LINES elif _IsClassOrDef(prev_uwline.first): - if not style.Get('BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'): + if first_nested and not style.Get('BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'): pytree_utils.SetNodeAnnotation(first_token.node, pytree_utils.Annotation.NEWLINES, None) return NO_BLANK_LINES diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 6454a7527..c620271e6 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -480,6 +480,39 @@ def _(): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + def testNoBlankLinesOnlyForFirstNestedObject(self): + unformatted_code = '''\ +class Demo: + """ + Demo docs + """ + def foo(self): + """ + foo docs + """ + def bar(self): + """ + bar docs + """ +''' + expected_code = '''\ +class Demo: + """ + Demo docs + """ + def foo(self): + """ + foo docs + """ + + def bar(self): + """ + bar docs + """ +''' + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + def testSplitBeforeArithmeticOperators(self): try: style.SetGlobalStyle( From 44d5e4db804b614038090dfd5a3744588d7bc08d Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 27 Nov 2019 18:05:28 -0800 Subject: [PATCH 427/719] Improve the description of .yapfignore's syntax Closes #754 --- CHANGELOG | 1 + README.rst | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index a2f18f1f9..0a404b9be 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,7 @@ parameter list is formatted, keeping state along the way. This helps when supporting Python 3 type annotations. - Catch and report `UnicodeDecodeError` exceptions. +- Improved description of .yapfignore syntax. ### Fixed - Format subscript lists so that splits are essentially free after a comma. - Don't add a space between a string and its subscript. diff --git a/README.rst b/README.rst index 0d86e3de2..31f6d288c 100644 --- a/README.rst +++ b/README.rst @@ -145,6 +145,15 @@ In addition to exclude patterns provided on commandline, YAPF looks for addition patterns specified in a file named ``.yapfignore`` located in the working directory from which YAPF is invoked. +``.yapfignore``'s syntax is similar to UNIX's filename pattern matching:: + + * matches everything + ? matches any single character + [seq] matches any character in seq + [!seq] matches any character not in seq + +Note that no entry should begin with `./`. + Formatting style ================ From 91f5ca1125755a5fb65b568a94e3524bccbb7697 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 27 Nov 2019 18:41:42 -0800 Subject: [PATCH 428/719] Reformat with YAPF --- yapf/yapflib/reformatter.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index f690a79df..720f7a260 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -693,7 +693,8 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, None) return NO_BLANK_LINES elif _IsClassOrDef(prev_uwline.first): - if first_nested and not style.Get('BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'): + if first_nested and not style.Get( + 'BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'): pytree_utils.SetNodeAnnotation(first_token.node, pytree_utils.Annotation.NEWLINES, None) return NO_BLANK_LINES From a80800b81b9aa6acc1e48ec3859e834a833822a3 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 28 Nov 2019 01:56:01 -0800 Subject: [PATCH 429/719] Bump version to 0.29.0 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0a404b9be..9f2c8df3a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.29.0] UNRELEASED +## [0.29.0] 2019-11-28 ### Added - Add the `--quiet` flag to suppress output. The return code is 1 if there are changes, similarly to the `--diff` flag. diff --git a/yapf/__init__.py b/yapf/__init__.py index ef7e77f07..27ff527e2 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -40,7 +40,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.28.0' +__version__ = '0.29.0' def main(argv): From 0631ab54ac9c48ceddb78e97389d65742eb62334 Mon Sep 17 00:00:00 2001 From: Tim Gates Date: Sat, 30 Nov 2019 21:43:33 +1100 Subject: [PATCH 430/719] Fix simple typo: standaline -> standalone --- yapf/yapflib/comment_splicer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index 028d68a4f..a0f0499b0 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -260,7 +260,7 @@ def _CreateCommentsFromPrefix(comment_prefix, # When splicing a standalone comment (i.e. a comment that appears on its own # line, not on the same line with other code), it's important to insert it into # an appropriate parent of the node it's attached to. An appropriate parent -# is the first "standaline line node" in the parent chain of a node. +# is the first "standalone line node" in the parent chain of a node. _STANDALONE_LINE_NODES = frozenset([ 'suite', 'if_stmt', 'while_stmt', 'for_stmt', 'try_stmt', 'with_stmt', 'funcdef', 'classdef', 'decorated', 'file_input' From c8f05ee0be1c307a79534994c22f56f4599dd44c Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 14 Jan 2020 14:04:09 -0800 Subject: [PATCH 431/719] Honor the 'disable' directive at the end of a multiline comment Closes #799 --- CHANGELOG | 4 ++++ yapf/yapflib/style.py | 2 +- yapf/yapflib/yapf_api.py | 5 ++++- yapftests/yapf_test.py | 13 +++++++++++++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9f2c8df3a..fe6e020df 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.29.1] UNRELEASED +### Fixed +- Honor a disable directive at the end of a multiline comment. + ## [0.29.0] 2019-11-28 ### Added - Add the `--quiet` flag to suppress output. The return code is 1 if there are diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 77c91723b..ba528c0d0 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -129,7 +129,7 @@ def method(): characters. Slightly right (one more indent character) if cannot vertically align continuation lines with indent characters. - For options FIXED, and VALIGN-RIGHT are only available when USE_TABS is + Options FIXED and VALIGN-RIGHT are only available when USE_TABS is enabled."""), CONTINUATION_INDENT_WIDTH=textwrap.dedent("""\ Indent width used for line continuations."""), diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index f5240abce..3f7c94a9d 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -252,7 +252,10 @@ def _MarkLinesToFormat(uwlines, lines): while index < len(uwlines): uwline = uwlines[index] if uwline.is_comment and _EnableYAPF(uwline.first.value.strip()): - break + if not re.search(DISABLE_PATTERN, + uwline.first.value.strip().split('\n')[-1].strip(), + re.IGNORECASE): + break uwline.disable = True index += 1 elif re.search(DISABLE_PATTERN, uwline.last.value.strip(), re.IGNORECASE): diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index e13955fde..f1685a0f0 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -195,6 +195,19 @@ def foo_function(): formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(code, formatted_code) + def testEnabledDisabledSameComment(self): + code = textwrap.dedent(u"""\ + # yapf: disable + a(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, ccccccccccccccccccccccccccccccc, ddddddddddddddddddddddd, eeeeeeeeeeeeeeeeeeeeeeeeeee) + # yapf: enable + # yapf: disable + a(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, ccccccccccccccccccccccccccccccc, ddddddddddddddddddddddd, eeeeeeeeeeeeeeeeeeeeeeeeeee) + # yapf: enable + """) + with utils.TempFileContents(self.test_tmpdir, code) as filepath: + formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') + self.assertCodeEqual(code, formatted_code) + def testFormatFileLinesSelection(self): unformatted_code = textwrap.dedent(u"""\ if a: b From cbfda3cdc090f899aa458a614cea3a0b1551baa0 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 21 Jan 2020 11:35:43 -0800 Subject: [PATCH 432/719] Don't require splitting before comments The SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES knob is meant for values, not other things like comments. Don't require splits before those as it may conflict with other formatting decisions. Closes #802 --- CHANGELOG | 3 +++ yapf/yapflib/format_decision_state.py | 7 ++++++- yapftests/reformatter_basic_test.py | 22 ++++++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index fe6e020df..acf215328 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,9 @@ ## [0.29.1] UNRELEASED ### Fixed - Honor a disable directive at the end of a multiline comment. +- Don't require splitting before comments in a list when + `SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES` is set. The knob is meant for + values, not comments, which may be associated with the current line. ## [0.29.0] 2019-11-28 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 17ade12ac..ee4e80801 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -187,10 +187,15 @@ def MustSplit(self): opening = _GetOpeningBracket(current) # Can't find opening bracket, behave the same way as - # SPLIT_ALL_COMMA_SEPARATED_VALUES + # SPLIT_ALL_COMMA_SEPARATED_VALUES. if not opening: return True + if current.is_comment: + # Don't require splitting before a comment, since it may be related to + # the current line. + return False + # Allow the fallthrough code to handle the closing bracket. if current != opening.matching_bracket: # If the container doesn't fit in the current line, must split diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 7e5cf287a..891b4e89c 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -202,6 +202,28 @@ def foo(long_arg, uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + # Don't require splitting before comments. + unformatted_code = textwrap.dedent("""\ + KO = { + 'ABC': Abc, # abc + 'DEF': Def, # def + 'LOL': Lol, # wtf + 'GHI': Ghi, + 'JKL': Jkl, + } + """) + expected_formatted_code = textwrap.dedent("""\ + KO = { + 'ABC': Abc, # abc + 'DEF': Def, # def + 'LOL': Lol, # wtf + 'GHI': Ghi, + 'JKL': Jkl, + } + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testSimpleFunctionsWithTrailingComments(self): unformatted_code = textwrap.dedent("""\ def g(): # Trailing comment From a6d0bc74c5e72619ddfdaf8d928247c5279b1a8d Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 22 Jan 2020 03:50:25 -0800 Subject: [PATCH 433/719] Ensure that parameter lists don't collide with following code A parameter list shouldn't align with the code following it. Make sure that it's properly indented when this is the case. Closes #785 Closes #784 Closes #781 --- CHANGELOG | 2 + yapf/yapflib/format_decision_state.py | 26 ++++++------- yapf/yapflib/object_state.py | 33 ++++++++++++++-- yapftests/reformatter_pep8_test.py | 54 +++++++++++++++++++++++++++ yapftests/reformatter_python3_test.py | 19 ++++++++++ 5 files changed, 116 insertions(+), 18 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index acf215328..de2b9c855 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,8 @@ - Don't require splitting before comments in a list when `SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES` is set. The knob is meant for values, not comments, which may be associated with the current line. +- Don't over-indent a parameter list when not needed. But make sure it is + properly indented so that it doesn't collide with the lines afterwards. ## [0.29.0] 2019-11-28 ### Added diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index ee4e80801..e7200804d 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -661,8 +661,8 @@ def _AddTokenOnNewline(self, dry_run, must_split): previous.previous_token.OpensScope())): dedent = (style.Get('CONTINUATION_INDENT_WIDTH'), 0)[style.Get('INDENT_CLOSING_BRACKETS')] - self.stack[-1].closing_scope_indent = max(0, - self.stack[-1].indent - dedent) + self.stack[-1].closing_scope_indent = ( + max(0, self.stack[-1].indent - dedent)) self.stack[-1].split_before_closing_bracket = True # Calculate the split penalty. @@ -952,7 +952,7 @@ def _GetNewlineColumn(self): if format_token.Subtype.DICTIONARY_VALUE in current.subtypes: return top_of_stack.indent - if (_IsCompoundStatement(self.line.first) and + if (not self.param_list_stack and _IsCompoundStatement(self.line.first) and (not (style.Get('DEDENT_CLOSING_BRACKETS') or style.Get('INDENT_CLOSING_BRACKETS')) or style.Get('SPLIT_BEFORE_FIRST_ARGUMENT'))): @@ -960,19 +960,17 @@ def _GetNewlineColumn(self): len(self.line.first.whitespace_prefix.split('\n')[-1]) + style.Get('INDENT_WIDTH')) if token_indent == top_of_stack.indent: - if self.param_list_stack and _IsFunctionDef(self.line.first): - last_param = self.param_list_stack[-1] - if (last_param.LastParamFitsOnLine(token_indent) and - not last_param.LastParamFitsOnLine( - token_indent + style.Get('CONTINUATION_INDENT_WIDTH'))): - self.param_list_stack[-1].split_before_closing_bracket = True - return token_indent - - if not last_param.LastParamFitsOnLine(token_indent): - self.param_list_stack[-1].split_before_closing_bracket = True - return token_indent return token_indent + style.Get('CONTINUATION_INDENT_WIDTH') + if (self.param_list_stack and + not self.param_list_stack[-1].SplitBeforeClosingBracket( + top_of_stack.indent) and top_of_stack.indent == ( + (self.line.depth + 1) * style.Get('INDENT_WIDTH'))): + if (format_token.Subtype.PARAMETER_START in current.subtypes or + (previous.is_comment and + format_token.Subtype.PARAMETER_START in previous.subtypes)): + return top_of_stack.indent + style.Get('CONTINUATION_INDENT_WIDTH') + return top_of_stack.indent def _FitsOnLine(self, start, end): diff --git a/yapf/yapflib/object_state.py b/yapf/yapflib/object_state.py index 246476938..539dfe019 100644 --- a/yapf/yapflib/object_state.py +++ b/yapf/yapflib/object_state.py @@ -120,6 +120,21 @@ def has_typed_return(self): def has_default_values(self): return any(param.has_default_value for param in self.parameters) + @property + @py3compat.lru_cache() + def ends_in_comma(self): + if not self.parameters: + return False + return self.parameters[-1].last_token.next_token.value == ',' + + @property + @py3compat.lru_cache() + def last_token(self): + token = self.opening_bracket.matching_bracket + while not token.is_comment and token.next_token: + token = token.next_token + return token + @py3compat.lru_cache() def LastParamFitsOnLine(self, indent): """Return true if the last parameter fits on a single line.""" @@ -127,14 +142,24 @@ def LastParamFitsOnLine(self, indent): return False if not self.parameters: return True + total_length = self.last_token.total_length last_param = self.parameters[-1].first_token - last_token = self.opening_bracket.matching_bracket - while not last_token.is_comment and last_token.next_token: - last_token = last_token.next_token - total_length = last_token.total_length total_length -= last_param.total_length - len(last_param.value) return total_length + indent <= style.Get('COLUMN_LIMIT') + @py3compat.lru_cache() + def SplitBeforeClosingBracket(self, indent): + if style.Get('DEDENT_CLOSING_BRACKETS'): + return True + if self.ends_in_comma: + return True + if not self.parameters: + return False + total_length = self.last_token.total_length + last_param = self.parameters[-1].first_token + total_length -= last_param.total_length - len(last_param.value) + return total_length + indent > style.Get('COLUMN_LIMIT') + def Clone(self): clone = ParameterListState(self.opening_bracket, self.has_split_before_first_param, diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index c620271e6..ac90ab484 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -589,6 +589,60 @@ class nested_class(): finally: style.SetGlobalStyle(style.CreatePEP8Style()) + def testParamListIndentationCollision1(self): + unformatted_code = textwrap.dedent("""\ +class _(): + + def __init__(self, title: Optional[str], diffs: Collection[BinaryDiff] = (), charset: Union[Type[AsciiCharset], Type[LineCharset]] = AsciiCharset, preprocess: Callable[[str], str] = identity, + # TODO(somebody): Make this a Literal type. + justify: str = 'rjust'): + self._cs = charset + self._preprocess = preprocess + """) + expected_formatted_code = textwrap.dedent("""\ +class _(): + def __init__( + self, + title: Optional[str], + diffs: Collection[BinaryDiff] = (), + charset: Union[Type[AsciiCharset], + Type[LineCharset]] = AsciiCharset, + preprocess: Callable[[str], str] = identity, + # TODO(somebody): Make this a Literal type. + justify: str = 'rjust'): + self._cs = charset + self._preprocess = preprocess + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testParamListIndentationCollision2(self): + code = textwrap.dedent("""\ + def simple_pass_function_with_an_extremely_long_name_and_some_arguments( + argument0, argument1): + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + + def testParamListIndentationCollision3(self): + code = textwrap.dedent("""\ + def func1( + arg1, + arg2, + ) -> None: + pass + + + def func2( + arg1, + arg2, + ): + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index 7e55fcba3..63615fb8d 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -440,6 +440,25 @@ async def fn(): uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testParameterListIndentationConflicts(self): + unformatted_code = textwrap.dedent("""\ + def raw_message( # pylint: disable=too-many-arguments + self, text, user_id=1000, chat_type='private', forward_date=None, forward_from=None): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def raw_message( # pylint: disable=too-many-arguments + self, + text, + user_id=1000, + chat_type='private', + forward_date=None, + forward_from=None): + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From f1a04634dffe86eb5cd11c339f6fc4567731a6af Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 22 Jan 2020 16:46:02 -0800 Subject: [PATCH 434/719] Add comments to appease the lint gods. --- yapf/yapflib/object_state.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/yapf/yapflib/object_state.py b/yapf/yapflib/object_state.py index 539dfe019..6d3020da9 100644 --- a/yapf/yapflib/object_state.py +++ b/yapf/yapflib/object_state.py @@ -91,6 +91,8 @@ class ParameterListState(object): opening_bracket: The opening bracket of the parameter list. closing_bracket: The closing bracket of the parameter list. has_typed_return: True if the function definition has a typed return. + ends_in_comma: True if the parameter list ends in a comma. + last_token: Returns the last token of the function declaration. has_default_values: True if the parameters have default values. has_split_before_first_param: Whether there is a newline before the first parameter. @@ -149,6 +151,7 @@ def LastParamFitsOnLine(self, indent): @py3compat.lru_cache() def SplitBeforeClosingBracket(self, indent): + """Return true if there's a split before the closing bracket.""" if style.Get('DEDENT_CLOSING_BRACKETS'): return True if self.ends_in_comma: From 270c891055ebf76742eb2bf135e01379077a0f37 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 22 Jan 2020 17:10:59 -0800 Subject: [PATCH 435/719] Add docstrings and other things for the linter. --- yapf/__init__.py | 2 +- yapf/yapflib/comment_splicer.py | 1 + yapf/yapflib/format_decision_state.py | 4 ++++ yapf/yapflib/object_state.py | 2 ++ yapf/yapflib/reformatter.py | 1 + yapf/yapflib/style.py | 4 ++++ yapf/yapflib/yapf_api.py | 22 ++++++++++++++++++++-- yapftests/reformatter_basic_test.py | 2 +- yapftests/reformatter_pep8_test.py | 2 +- yapftests/reformatter_python3_test.py | 2 +- yapftests/yapf_test.py | 3 ++- 11 files changed, 38 insertions(+), 7 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 27ff527e2..a2ed4072d 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -334,7 +334,7 @@ def _GetLines(line_strings): if line[0] < 1: raise errors.YapfError('invalid start of line range: %r' % line) if line[0] > line[1]: - raise errors.YapfError('end comes before start in line range: %r', line) + raise errors.YapfError('end comes before start in line range: %r' % line) lines.append(tuple(line)) return lines diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index a0f0499b0..8d646849f 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -44,6 +44,7 @@ def SpliceComments(tree): _AnnotateIndents(tree) def _VisitNodeRec(node): + """Recursively visit each node to splice comments into the AST.""" # This loop may insert into node.children, so we'll iterate over a copy. for child in node.children[:]: if isinstance(child, pytree.Node): diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index e7200804d..fb91d3576 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -41,6 +41,7 @@ class FormatDecisionState(object): Attributes: first_indent: The indent of the first token. column: The number of used columns in the current line. + line: The unwrapped line we're currently processing. next_token: The next token to be formatted. paren_level: The level of nesting inside (), [], and {}. lowest_level_on_line: The lowest paren_level on the current line. @@ -52,6 +53,7 @@ class FormatDecisionState(object): properties applying to function parameter lists. ignore_stack_for_comparison: Ignore the stack of _ParenState for state comparison. + column_limit: The column limit specified by the style. """ def __init__(self, line, first_indent): @@ -999,6 +1001,7 @@ def ImplicitStringConcatenation(tok): return num_strings > 1 def DictValueIsContainer(opening, closing): + """Return true if the dictionary value is a container.""" if not opening or not closing: return False colon = opening.previous_token @@ -1205,6 +1208,7 @@ class _ParenState(object): indent: The column position to which a specified parenthesis level needs to be indented. last_space: The column position of the last space on each level. + closing_scope_indent: The column position of the closing indentation. split_before_closing_bracket: Whether a newline needs to be inserted before the closing bracket. We only want to insert a newline before the closing bracket if there also was a newline after the beginning left bracket. diff --git a/yapf/yapflib/object_state.py b/yapf/yapflib/object_state.py index 6d3020da9..4ae8eaeb6 100644 --- a/yapf/yapflib/object_state.py +++ b/yapf/yapflib/object_state.py @@ -36,6 +36,8 @@ class ComprehensionState(object): Attributes: expr_token: The first token in the comprehension. for_token: The first 'for' token of the comprehension. + opening_bracket: The opening bracket of the list comprehension. + closing_bracket: The closing bracket of the list comprehension. has_split_at_for: Whether there is a newline immediately before the for_token. has_interior_split: Whether there is a newline within the comprehension. diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 720f7a260..0faa91ff4 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -270,6 +270,7 @@ def _CanPlaceOnSingleLine(uwline): def _AlignTrailingComments(final_lines): + """Align trailing comments to the same column.""" final_lines_index = 0 while final_lines_index < len(final_lines): line = final_lines[final_lines_index] diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index ba528c0d0..87cab028b 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -356,6 +356,7 @@ def method(): def CreatePEP8Style(): + """Create the PEP8 formatting style.""" return dict( ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=True, ALLOW_MULTILINE_LAMBDAS=False, @@ -414,6 +415,7 @@ def CreatePEP8Style(): def CreateGoogleStyle(): + """Create the Google formatting style.""" style = CreatePEP8Style() style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False style['BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'] = True @@ -433,6 +435,7 @@ def CreateGoogleStyle(): def CreateChromiumStyle(): + """Create the Chromium formatting style.""" style = CreateGoogleStyle() style['ALLOW_MULTILINE_DICTIONARY_KEYS'] = True style['ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS'] = False @@ -445,6 +448,7 @@ def CreateChromiumStyle(): def CreateFacebookStyle(): + """Create the Facebook formatting style.""" style = CreatePEP8Style() style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False style['COLUMN_LIMIT'] = 80 diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 3f7c94a9d..dde1df931 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -63,9 +63,18 @@ def FormatFile(filename, Arguments: filename: (unicode) The file to reformat. + style_config: (string) Either a style name or a path to a file that contains + formatting style settings. If None is specified, use the default style + as set in style.DEFAULT_STYLE_FACTORY + lines: (list of tuples of integers) A list of tuples of lines, [start, end], + that we want to format. The lines are 1-based indexed. It can be used by + third-party code (e.g., IDEs) when reformatting a snippet of code rather + than a whole file. + print_diff: (bool) Instead of returning the reformatted source, return a + diff that turns the formatted source into reformatter source. + verify: (bool) True if reformatted code should be verified for syntax. in_place: (bool) If True, write the reformatted code back to the file. logger: (io streamer) A stream to output logging. - remaining arguments: see comment at the top of this module. Returns: Tuple of (reformatted_code, encoding, changed). reformatted_code is None if @@ -114,7 +123,16 @@ def FormatCode(unformatted_source, Arguments: unformatted_source: (unicode) The code to format. filename: (unicode) The name of the file being reformatted. - remaining arguments: see comment at the top of this module. + style_config: (string) Either a style name or a path to a file that contains + formatting style settings. If None is specified, use the default style + as set in style.DEFAULT_STYLE_FACTORY + lines: (list of tuples of integers) A list of tuples of lines, [start, end], + that we want to format. The lines are 1-based indexed. It can be used by + third-party code (e.g., IDEs) when reformatting a snippet of code rather + than a whole file. + print_diff: (bool) Instead of returning the reformatted source, return a + diff that turns the formatted source into reformatter source. + verify: (bool) True if reformatted code should be verified for syntax. Returns: Tuple of (reformatted_source, changed). reformatted_source conforms to the diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 891b4e89c..ce90fe5b9 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -26,7 +26,7 @@ class BasicReformatterTest(yapf_test_helper.YAPFTest): @classmethod - def setUpClass(cls): + def setUpClass(cls): # pylint: disable=g-missing-super-call style.SetGlobalStyle(style.CreateChromiumStyle()) def testSplittingAllArgs(self): diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index ac90ab484..8f59988aa 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -25,7 +25,7 @@ class TestsForPEP8Style(yapf_test_helper.YAPFTest): @classmethod - def setUpClass(cls): + def setUpClass(cls): # pylint: disable=g-missing-super-call style.SetGlobalStyle(style.CreatePEP8Style()) def testIndent4(self): diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index 63615fb8d..98ce5a654 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -29,7 +29,7 @@ class TestsForPython3Code(yapf_test_helper.YAPFTest): """Test a few constructs that are new Python 3 syntax.""" @classmethod - def setUpClass(cls): + def setUpClass(cls): # pylint: disable=g-missing-super-call style.SetGlobalStyle(style.CreatePEP8Style()) def testTypedNames(self): diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index f1685a0f0..25e4f9bd2 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -579,7 +579,8 @@ def f(): try: subprocess.check_call(YAPF_BINARY + ['--diff', filepath], stdout=out) except subprocess.CalledProcessError as e: - self.assertEqual(e.returncode, 1) # Indicates the text changed. + # Indicates the text changed. + self.assertEqual(e.returncode, 1) # pylint: disable=g-assert-in-except def testReformattingSpecificLines(self): unformatted_code = textwrap.dedent("""\ From a1d3405a2bec18f96919670668104b154bad75fd Mon Sep 17 00:00:00 2001 From: Brian Mego Date: Sat, 1 Feb 2020 21:49:06 -0600 Subject: [PATCH 436/719] Extracts print_help into its own function --- yapf/__init__.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index a2ed4072d..0890d8d86 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -145,18 +145,7 @@ def main(argv): style_config = args.style if args.style_help: - if style_config is None and not args.no_local_style: - style_config = file_resources.GetDefaultStyleForDir(os.getcwd()) - style.SetGlobalStyle(style.CreateStyleFromConfig(style_config)) - print('[style]') - for option, docstring in sorted(style.Help().items()): - for line in docstring.splitlines(): - print('#', line and ' ' or '', line, sep='') - option_value = style.Get(option) - if isinstance(option_value, set) or isinstance(option_value, list): - option_value = ', '.join(map(str, option_value)) - print(option.lower(), '=', option_value, sep='') - print() + print_help(args) return 0 if args.lines and len(args.files) > 1: @@ -226,6 +215,20 @@ def main(argv): verbose=args.verbose) return 1 if changed and (args.diff or args.quiet) else 0 +def print_help(args): + if args.style is None and not args.no_local_style: + args.style = file_resources.GetDefaultStyleForDir(os.getcwd()) + style.SetGlobalStyle(style.CreateStyleFromConfig(args.style)) + print('[style]') + for option, docstring in sorted(style.Help().items()): + for line in docstring.splitlines(): + print('#', line and ' ' or '', line, sep='') + option_value = style.Get(option) + if isinstance(option_value, set) or isinstance(option_value, list): + option_value = ', '.join(map(str, option_value)) + print(option.lower(), '=', option_value, sep='') + print() + def FormatFiles(filenames, lines, From ba94f83697cce168ab41eaf3a972585635c869ba Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 3 Feb 2020 15:09:56 -0800 Subject: [PATCH 437/719] Remove dead code. --- yapf/yapflib/format_decision_state.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index fb91d3576..18e29ac73 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -1124,14 +1124,6 @@ def _IsArgumentToFunction(token): return previous and previous.is_name -def _GetLengthOfSubtype(token, subtype, exclude=None): - current = token - while (current.next_token and subtype in current.subtypes and - (exclude is None or exclude not in current.subtypes)): - current = current.next_token - return current.total_length - token.total_length + 1 - - def _GetOpeningBracket(current): """Get the opening bracket containing the current token.""" if current.matching_bracket and not current.is_pseudo_paren: From e8a0f3173ebff8ddfdb326ec5315b8a18466c37d Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 3 Feb 2020 15:10:22 -0800 Subject: [PATCH 438/719] Move non-throwing code out of the 'try-except' block. --- yapf/__init__.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index a2ed4072d..36494aa44 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -291,9 +291,11 @@ def _FormatFile(filename, """Format an individual file.""" if verbose and not quiet: print('Reformatting %s' % filename) + if style_config is None and not no_local_style: style_config = file_resources.GetDefaultStyleForDir( os.path.dirname(filename)) + try: reformatted_code, encoding, has_change = yapf_api.FormatFile( filename, @@ -303,16 +305,17 @@ def _FormatFile(filename, print_diff=print_diff, verify=verify, logger=logging.warning) - if not in_place and not quiet and reformatted_code: - file_resources.WriteReformattedCode(filename, reformatted_code, encoding, - in_place) - return has_change except tokenize.TokenError as e: raise errors.YapfError('%s:%s:%s' % (filename, e.args[1][0], e.args[0])) except SyntaxError as e: e.filename = filename raise + if not in_place and not quiet and reformatted_code: + file_resources.WriteReformattedCode(filename, reformatted_code, encoding, + in_place) + return has_change + def _GetLines(line_strings): """Parses the start and end lines from a line string like 'start-end'. From 72e2b80069446846d4de1ef495c086508177f92f Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 3 Feb 2020 15:10:54 -0800 Subject: [PATCH 439/719] Reduce indentation with early exit --- yapf/yapflib/file_resources.py | 32 ++++++++++++++++---------------- yapf/yapflib/split_penalty.py | 24 ++++++++++++------------ 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 59c3df54c..50b4687f4 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -160,24 +160,24 @@ def _FindPythonFiles(filenames, recursive, exclude): if filename != '.' and exclude and IsIgnored(filename, exclude): continue if os.path.isdir(filename): - if recursive: - # TODO(morbo): Look into a version of os.walk that can handle recursion. - excluded_dirs = [] - for dirpath, _, filelist in os.walk(filename): - if dirpath != '.' and exclude and IsIgnored(dirpath, exclude): - excluded_dirs.append(dirpath) - continue - elif any(dirpath.startswith(e) for e in excluded_dirs): - continue - for f in filelist: - filepath = os.path.join(dirpath, f) - if exclude and IsIgnored(filepath, exclude): - continue - if IsPythonFile(filepath): - python_files.append(filepath) - else: + if not recursive: raise errors.YapfError( "directory specified without '--recursive' flag: %s" % filename) + + # TODO(morbo): Look into a version of os.walk that can handle recursion. + excluded_dirs = [] + for dirpath, _, filelist in os.walk(filename): + if dirpath != '.' and exclude and IsIgnored(dirpath, exclude): + excluded_dirs.append(dirpath) + continue + elif any(dirpath.startswith(e) for e in excluded_dirs): + continue + for f in filelist: + filepath = os.path.join(dirpath, f) + if exclude and IsIgnored(filepath, exclude): + continue + if IsPythonFile(filepath): + python_files.append(filepath) elif os.path.isfile(filename): python_files.append(filename) diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 958c76eaf..186f3e3be 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -290,20 +290,20 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring while prev_trailer_idx < len(node.children) - 1: cur_trailer_idx = prev_trailer_idx + 1 cur_trailer = node.children[cur_trailer_idx] - if pytree_utils.NodeName(cur_trailer) == 'trailer': - # Now we know we have two trailers one after the other - prev_trailer = node.children[prev_trailer_idx] - if prev_trailer.children[-1].value != ')': - # Set the previous node unbreakable if it's not a function call: - # atom tr1() tr2 - # It may be necessary (though undesirable) to split up a previous - # function call's parentheses to the next line. - _SetStronglyConnected(prev_trailer.children[-1]) - _SetStronglyConnected(cur_trailer.children[0]) - prev_trailer_idx = cur_trailer_idx - else: + if pytree_utils.NodeName(cur_trailer) != 'trailer': break + # Now we know we have two trailers one after the other + prev_trailer = node.children[prev_trailer_idx] + if prev_trailer.children[-1].value != ')': + # Set the previous node unbreakable if it's not a function call: + # atom tr1() tr2 + # It may be necessary (though undesirable) to split up a previous + # function call's parentheses to the next line. + _SetStronglyConnected(prev_trailer.children[-1]) + _SetStronglyConnected(cur_trailer.children[0]) + prev_trailer_idx = cur_trailer_idx + # We don't want to split before the last ')' of a function call. This also # takes care of the special case of: # atom tr1 tr2 ... trn From 00c5c057b9069621747406e2c64d78622168d128 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 3 Feb 2020 16:57:15 -0800 Subject: [PATCH 440/719] Don't split between two-word comparison operators. Closes #807 --- CHANGELOG | 1 + yapf/yapflib/split_penalty.py | 14 ++++++++------ yapftests/reformatter_basic_test.py | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index de2b9c855..d0c0b808d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,7 @@ values, not comments, which may be associated with the current line. - Don't over-indent a parameter list when not needed. But make sure it is properly indented so that it doesn't collide with the lines afterwards. +- Don't split between two-word comparison operators: "is not", "not in", etc. ## [0.29.0] 2019-11-28 ### Added diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 186f3e3be..819dbda0f 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -414,8 +414,7 @@ def Visit_comparison(self, node): # pylint: disable=invalid-name # comparison ::= expr (comp_op expr)* self.DefaultNodeVisit(node) if len(node.children) == 3 and _StronglyConnectedCompOp(node): - _SetSplitPenalty( - pytree_utils.FirstLeafNode(node.children[1]), STRONGLY_CONNECTED) + _IncreasePenalty(node.children[1], VERY_STRONGLY_CONNECTED) _SetSplitPenalty( pytree_utils.FirstLeafNode(node.children[2]), STRONGLY_CONNECTED) else: @@ -618,10 +617,13 @@ def _RecAnnotate(tree, annotate_name, annotate_value): def _StronglyConnectedCompOp(op): if (len(op.children[1].children) == 2 and - pytree_utils.NodeName(op.children[1]) == 'comp_op' and - pytree_utils.FirstLeafNode(op.children[1]).value == 'not' and - pytree_utils.LastLeafNode(op.children[1]).value == 'in'): - return True + pytree_utils.NodeName(op.children[1]) == 'comp_op'): + if (pytree_utils.FirstLeafNode(op.children[1]).value == 'not' and + pytree_utils.LastLeafNode(op.children[1]).value == 'in'): + return True + if (pytree_utils.FirstLeafNode(op.children[1]).value == 'is' and + pytree_utils.LastLeafNode(op.children[1]).value == 'not'): + return True if (isinstance(op.children[1], pytree.Leaf) and op.children[1].value in {'==', 'in'}): return True diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index ce90fe5b9..4add43ec1 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2966,6 +2966,25 @@ def b(): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testTwoWordComparisonOperators(self): + unformatted_code = textwrap.dedent("""\ + _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl is not ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj) + _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl not in {ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj}) + """) + expected_formatted_code = textwrap.dedent("""\ + _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl + is not ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj) + _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl + not in {ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj}) + """) + + try: + style.SetGlobalStyle(style.CreatePEP8Style()) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + if __name__ == '__main__': unittest.main() From f13d130e0d26a7c81babf96c1aa5aa835fed684a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 3 Feb 2020 17:19:15 -0800 Subject: [PATCH 441/719] Move code out of try-except blocks Other general cleanups. No functional change. --- yapftests/reformatter_basic_test.py | 875 ++++++++++++------------ yapftests/reformatter_buganizer_test.py | 58 +- yapftests/reformatter_pep8_test.py | 55 ++ yapftests/reformatter_python3_test.py | 53 +- 4 files changed, 539 insertions(+), 502 deletions(-) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 4add43ec1..8e93042e5 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -264,7 +264,7 @@ def foobar(): # foo expected_formatted_code = textwrap.dedent("""\ def foobar(): # foo pass - """) + """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -276,36 +276,38 @@ def foobar(): # foo """) expected_formatted_code = textwrap.dedent("""\ x = {'a': 37, 'b': 42, 'c': 927} - """) + """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testIndentBlankLines(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: chromium, indent_blank_lines: true}')) - unformatted_code = textwrap.dedent("""\ - class foo(object): + unformatted_code = textwrap.dedent("""\ + class foo(object): - def foobar(self): + def foobar(self): - pass + pass - def barfoo(self, x, y): # bar + def barfoo(self, x, y): # bar - if x: + if x: - return y + return y - def bar(): + def bar(): - return 0 - """) - expected_formatted_code = """\ + return 0 + """) + expected_formatted_code = """\ class foo(object):\n \n def foobar(self):\n \n pass\n \n def barfoo(self, x, y): # bar\n \n if x:\n \n return y\n\n\ndef bar():\n \n return 0 """ + + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: chromium, indent_blank_lines: true}')) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1821,33 +1823,34 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testMultilineLambdas(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: chromium, allow_multiline_lambdas: true}')) - unformatted_code = textwrap.dedent("""\ - class SomeClass(object): - do_something = True + unformatted_code = textwrap.dedent("""\ + class SomeClass(object): + do_something = True - def succeeded(self, dddddddddddddd): - d = defer.succeed(None) + def succeeded(self, dddddddddddddd): + d = defer.succeed(None) - if self.do_something: - d.addCallback(lambda _: self.aaaaaa.bbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccccccc(dddddddddddddd)) - return d - """) - expected_formatted_code = textwrap.dedent("""\ - class SomeClass(object): - do_something = True + if self.do_something: + d.addCallback(lambda _: self.aaaaaa.bbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccccccc(dddddddddddddd)) + return d + """) + expected_formatted_code = textwrap.dedent("""\ + class SomeClass(object): + do_something = True - def succeeded(self, dddddddddddddd): - d = defer.succeed(None) + def succeeded(self, dddddddddddddd): + d = defer.succeed(None) - if self.do_something: - d.addCallback(lambda _: self.aaaaaa.bbbbbbbbbbbbbbbb. - cccccccccccccccccccccccccccccccc(dddddddddddddd)) - return d - """) + if self.do_something: + d.addCallback(lambda _: self.aaaaaa.bbbbbbbbbbbbbbbb. + cccccccccccccccccccccccccccccccc(dddddddddddddd)) + return d + """) + + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: chromium, allow_multiline_lambdas: true}')) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1855,31 +1858,32 @@ def succeeded(self, dddddddddddddd): style.SetGlobalStyle(style.CreateChromiumStyle()) def testMultilineDictionaryKeys(self): + unformatted_code = textwrap.dedent("""\ + MAP_WITH_LONG_KEYS = { + ('lorem ipsum', 'dolor sit amet'): + 1, + ('consectetur adipiscing elit.', 'Vestibulum mauris justo, ornare eget dolor eget'): + 2, + ('vehicula convallis nulla. Vestibulum dictum nisl in malesuada finibus.',): + 3 + } + """) + expected_formatted_code = textwrap.dedent("""\ + MAP_WITH_LONG_KEYS = { + ('lorem ipsum', 'dolor sit amet'): + 1, + ('consectetur adipiscing elit.', + 'Vestibulum mauris justo, ornare eget dolor eget'): + 2, + ('vehicula convallis nulla. Vestibulum dictum nisl in malesuada finibus.',): + 3 + } + """) + try: style.SetGlobalStyle( style.CreateStyleFromConfig('{based_on_style: chromium, ' 'allow_multiline_dictionary_keys: true}')) - unformatted_code = textwrap.dedent("""\ - MAP_WITH_LONG_KEYS = { - ('lorem ipsum', 'dolor sit amet'): - 1, - ('consectetur adipiscing elit.', 'Vestibulum mauris justo, ornare eget dolor eget'): - 2, - ('vehicula convallis nulla. Vestibulum dictum nisl in malesuada finibus.',): - 3 - } - """) - expected_formatted_code = textwrap.dedent("""\ - MAP_WITH_LONG_KEYS = { - ('lorem ipsum', 'dolor sit amet'): - 1, - ('consectetur adipiscing elit.', - 'Vestibulum mauris justo, ornare eget dolor eget'): - 2, - ('vehicula convallis nulla. Vestibulum dictum nisl in malesuada finibus.',): - 3 - } - """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1887,24 +1891,26 @@ def testMultilineDictionaryKeys(self): style.SetGlobalStyle(style.CreateChromiumStyle()) def testStableDictionaryFormatting(self): + code = textwrap.dedent("""\ + class A(object): + def method(self): + filters = { + 'expressions': [{ + 'field': { + 'search_field': { + 'user_field': 'latest_party__number_of_guests' + }, + } + }] + } + """) + try: style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: pep8, indent_width: 2, ' 'continuation_indent_width: 4, indent_dictionary_value: True}')) - code = textwrap.dedent("""\ - class A(object): - def method(self): - filters = { - 'expressions': [{ - 'field': { - 'search_field': { - 'user_field': 'latest_party__number_of_guests' - }, - } - }] - } - """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) reformatted_code = reformatter.Reformat(uwlines) self.assertCodeEqual(code, reformatted_code) @@ -1915,33 +1921,6 @@ def method(self): finally: style.SetGlobalStyle(style.CreateChromiumStyle()) - def testStableInlinedDictionaryFormatting(self): - try: - style.SetGlobalStyle(style.CreatePEP8Style()) - unformatted_code = textwrap.dedent("""\ - def _(): - url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( - value, urllib.urlencode({'action': 'update', 'parameter': value})) - """) - expected_formatted_code = textwrap.dedent("""\ - def _(): - url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( - value, urllib.urlencode({ - 'action': 'update', - 'parameter': value - })) - """) - - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - reformatted_code = reformatter.Reformat(uwlines) - self.assertCodeEqual(expected_formatted_code, reformatted_code) - - uwlines = yapf_test_helper.ParseAndUnwrap(reformatted_code) - reformatted_code = reformatter.Reformat(uwlines) - self.assertCodeEqual(expected_formatted_code, reformatted_code) - finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) - def testDontSplitKeywordValueArguments(self): unformatted_code = textwrap.dedent("""\ def mark_game_scored(gid): @@ -1981,6 +1960,20 @@ def a(): self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testNoSplittingWhenBinPacking(self): + code = textwrap.dedent("""\ + a_very_long_function_name( + long_argument_name_1=1, + long_argument_name_2=2, + long_argument_name_3=3, + long_argument_name_4=4, + ) + + a_very_long_function_name( + long_argument_name_1=1, long_argument_name_2=2, long_argument_name_3=3, + long_argument_name_4=4 + ) + """) + try: style.SetGlobalStyle( style.CreateStyleFromConfig( @@ -1988,19 +1981,7 @@ def testNoSplittingWhenBinPacking(self): 'continuation_indent_width: 4, indent_dictionary_value: True, ' 'dedent_closing_brackets: True, ' 'split_before_named_assigns: False}')) - code = textwrap.dedent("""\ - a_very_long_function_name( - long_argument_name_1=1, - long_argument_name_2=2, - long_argument_name_3=3, - long_argument_name_4=4, - ) - a_very_long_function_name( - long_argument_name_1=1, long_argument_name_2=2, long_argument_name_3=3, - long_argument_name_4=4 - ) - """) uwlines = yapf_test_helper.ParseAndUnwrap(code) reformatted_code = reformatter.Reformat(uwlines) self.assertCodeEqual(code, reformatted_code) @@ -2078,50 +2059,52 @@ def _pack_results_for_constraint_or(cls, combination, constraints): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testSplittingArgumentsTerminatedByComma(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: chromium, ' - 'split_arguments_when_comma_terminated: True}')) - unformatted_code = textwrap.dedent("""\ - function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3) + unformatted_code = textwrap.dedent("""\ + function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3) - function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3,) + function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3,) - a_very_long_function_name(long_argument_name_1=1, long_argument_name_2=2, long_argument_name_3=3, long_argument_name_4=4) + a_very_long_function_name(long_argument_name_1=1, long_argument_name_2=2, long_argument_name_3=3, long_argument_name_4=4) - a_very_long_function_name(long_argument_name_1, long_argument_name_2, long_argument_name_3, long_argument_name_4,) + a_very_long_function_name(long_argument_name_1, long_argument_name_2, long_argument_name_3, long_argument_name_4,) - r =f0 (1, 2,3,) - """) - expected_formatted_code = textwrap.dedent("""\ - function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3) + r =f0 (1, 2,3,) + """) + expected_formatted_code = textwrap.dedent("""\ + function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3) - function_name( - argument_name_1=1, - argument_name_2=2, - argument_name_3=3, - ) + function_name( + argument_name_1=1, + argument_name_2=2, + argument_name_3=3, + ) - a_very_long_function_name( - long_argument_name_1=1, - long_argument_name_2=2, - long_argument_name_3=3, - long_argument_name_4=4) - - a_very_long_function_name( - long_argument_name_1, - long_argument_name_2, - long_argument_name_3, - long_argument_name_4, - ) + a_very_long_function_name( + long_argument_name_1=1, + long_argument_name_2=2, + long_argument_name_3=3, + long_argument_name_4=4) + + a_very_long_function_name( + long_argument_name_1, + long_argument_name_2, + long_argument_name_3, + long_argument_name_4, + ) + + r = f0( + 1, + 2, + 3, + ) + """) + + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: chromium, ' + 'split_arguments_when_comma_terminated: True}')) - r = f0( - 1, - 2, - 3, - ) - """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) reformatted_code = reformatter.Reformat(uwlines) self.assertCodeEqual(expected_formatted_code, reformatted_code) @@ -2393,33 +2376,35 @@ def __init__(self): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: chromium, ' - 'blank_line_before_class_docstring: True}')) - unformatted_code = textwrap.dedent('''\ - class A: + unformatted_code = textwrap.dedent('''\ + class A: - """Does something. + """Does something. - Also, here are some details. - """ + Also, here are some details. + """ - def __init__(self): - pass - ''') - expected_formatted_code = textwrap.dedent('''\ - class A: + def __init__(self): + pass + ''') + expected_formatted_code = textwrap.dedent('''\ + class A: - """Does something. + """Does something. - Also, here are some details. - """ + Also, here are some details. + """ + + def __init__(self): + pass + ''') + + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: chromium, ' + 'blank_line_before_class_docstring: True}')) - def __init__(self): - pass - ''') uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2449,12 +2434,7 @@ def foobar(): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: pep8, ' - 'blank_line_before_module_docstring: True}')) - unformatted_code = textwrap.dedent('''\ + unformatted_code = textwrap.dedent('''\ #!/usr/bin/env python # -*- coding: utf-8 name> -*- """Some module docstring.""" @@ -2462,8 +2442,8 @@ def foobar(): def foobar(): pass - ''') - expected_formatted_code = textwrap.dedent('''\ + ''') + expected_formatted_code = textwrap.dedent('''\ #!/usr/bin/env python # -*- coding: utf-8 name> -*- @@ -2472,7 +2452,14 @@ def foobar(): def foobar(): pass - ''') + ''') + + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: pep8, ' + 'blank_line_before_module_docstring: True}')) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2560,18 +2547,20 @@ def testPseudoParens(self): def testSplittingBeforeFirstArgumentOnFunctionCall(self): """Tests split_before_first_argument on a function call.""" + unformatted_code = textwrap.dedent("""\ + a_very_long_function_name("long string with formatting {0:s}".format( + "mystring")) + """) + expected_formatted_code = textwrap.dedent("""\ + a_very_long_function_name( + "long string with formatting {0:s}".format("mystring")) + """) + try: style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: chromium, split_before_first_argument: True}')) - unformatted_code = textwrap.dedent("""\ - a_very_long_function_name("long string with formatting {0:s}".format( - "mystring")) - """) - expected_formatted_code = textwrap.dedent("""\ - a_very_long_function_name( - "long string with formatting {0:s}".format("mystring")) - """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2580,20 +2569,22 @@ def testSplittingBeforeFirstArgumentOnFunctionCall(self): def testSplittingBeforeFirstArgumentOnFunctionDefinition(self): """Tests split_before_first_argument on a function definition.""" + unformatted_code = textwrap.dedent("""\ + def _GetNumberOfSecondsFromElements(year, month, day, hours, + minutes, seconds, microseconds): + return + """) + expected_formatted_code = textwrap.dedent("""\ + def _GetNumberOfSecondsFromElements( + year, month, day, hours, minutes, seconds, microseconds): + return + """) + try: style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: chromium, split_before_first_argument: True}')) - unformatted_code = textwrap.dedent("""\ - def _GetNumberOfSecondsFromElements(year, month, day, hours, - minutes, seconds, microseconds): - return - """) - expected_formatted_code = textwrap.dedent("""\ - def _GetNumberOfSecondsFromElements( - year, month, day, hours, minutes, seconds, microseconds): - return - """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2602,22 +2593,24 @@ def _GetNumberOfSecondsFromElements( def testSplittingBeforeFirstArgumentOnCompoundStatement(self): """Tests split_before_first_argument on a compound statement.""" + unformatted_code = textwrap.dedent("""\ + if (long_argument_name_1 == 1 or + long_argument_name_2 == 2 or + long_argument_name_3 == 3 or + long_argument_name_4 == 4): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + if (long_argument_name_1 == 1 or long_argument_name_2 == 2 or + long_argument_name_3 == 3 or long_argument_name_4 == 4): + pass + """) + try: style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: chromium, split_before_first_argument: True}')) - unformatted_code = textwrap.dedent("""\ - if (long_argument_name_1 == 1 or - long_argument_name_2 == 2 or - long_argument_name_3 == 3 or - long_argument_name_4 == 4): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - if (long_argument_name_1 == 1 or long_argument_name_2 == 2 or - long_argument_name_3 == 3 or long_argument_name_4 == 4): - pass - """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2626,32 +2619,34 @@ def testSplittingBeforeFirstArgumentOnCompoundStatement(self): def testCoalesceBracketsOnDict(self): """Tests coalesce_brackets on a dictionary.""" + unformatted_code = textwrap.dedent("""\ + date_time_values = ( + { + u'year': year, + u'month': month, + u'day_of_month': day_of_month, + u'hours': hours, + u'minutes': minutes, + u'seconds': seconds + } + ) + """) + expected_formatted_code = textwrap.dedent("""\ + date_time_values = ({ + u'year': year, + u'month': month, + u'day_of_month': day_of_month, + u'hours': hours, + u'minutes': minutes, + u'seconds': seconds + }) + """) + try: style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: chromium, coalesce_brackets: True}')) - unformatted_code = textwrap.dedent("""\ - date_time_values = ( - { - u'year': year, - u'month': month, - u'day_of_month': day_of_month, - u'hours': hours, - u'minutes': minutes, - u'seconds': seconds - } - ) - """) - expected_formatted_code = textwrap.dedent("""\ - date_time_values = ({ - u'year': year, - u'month': month, - u'day_of_month': day_of_month, - u'hours': hours, - u'minutes': minutes, - u'seconds': seconds - }) - """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2659,85 +2654,68 @@ def testCoalesceBracketsOnDict(self): style.SetGlobalStyle(style.CreateChromiumStyle()) def testSplitAfterComment(self): + code = textwrap.dedent("""\ + if __name__ == "__main__": + with another_resource: + account = { + "validUntil": + int(time() + (6 * 7 * 24 * 60 * 60)) # in 6 weeks time + } + """) + try: style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: chromium, coalesce_brackets: True, ' 'dedent_closing_brackets: true}')) - code = textwrap.dedent("""\ - if __name__ == "__main__": - with another_resource: - account = { - "validUntil": - int(time() + (6 * 7 * 24 * 60 * 60)) # in 6 weeks time - } - """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) - - @unittest.skipUnless(not py3compat.PY3, 'Requires Python 2.7') - def testAsyncAsNonKeyword(self): - try: - style.SetGlobalStyle(style.CreatePEP8Style()) - - # In Python 2, async may be used as a non-keyword identifier. - code = textwrap.dedent("""\ - from util import async - - - class A(object): - def foo(self): - async.run() - def bar(self): - pass - """) uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines, verify=False)) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) finally: style.SetGlobalStyle(style.CreateChromiumStyle()) def testDisableEndingCommaHeuristic(self): + code = textwrap.dedent("""\ + x = [1, 2, 3, 4, 5, 6, 7,] + """) + try: style.SetGlobalStyle( style.CreateStyleFromConfig('{based_on_style: chromium,' ' disable_ending_comma_heuristic: True}')) - code = """\ -x = [1, 2, 3, 4, 5, 6, 7,] -""" uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) finally: style.SetGlobalStyle(style.CreateChromiumStyle()) def testDedentClosingBracketsWithTypeAnnotationExceedingLineLength(self): + unformatted_code = textwrap.dedent("""\ + def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: + pass + + + def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def function( + first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None + ) -> None: + pass + + + def function( + first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None + ) -> None: + pass + """) + try: style.SetGlobalStyle( style.CreateStyleFromConfig('{based_on_style: chromium,' ' dedent_closing_brackets: True}')) - unformatted_code = textwrap.dedent("""\ - def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: - pass - - - def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: - pass - """) - expected_formatted_code = textwrap.dedent("""\ - def function( - first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None - ) -> None: - pass - - - def function( - first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None - ) -> None: - pass - """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2745,30 +2723,32 @@ def function( style.SetGlobalStyle(style.CreateChromiumStyle()) def testIndentClosingBracketsWithTypeAnnotationExceedingLineLength(self): + unformatted_code = textwrap.dedent("""\ + def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: + pass + + + def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def function( + first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None + ) -> None: + pass + + + def function( + first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None + ) -> None: + pass + """) + try: style.SetGlobalStyle( style.CreateStyleFromConfig('{based_on_style: chromium,' ' indent_closing_brackets: True}')) - unformatted_code = textwrap.dedent("""\ - def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: - pass - - - def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: - pass - """) - expected_formatted_code = textwrap.dedent("""\ - def function( - first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None - ) -> None: - pass - - - def function( - first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None - ) -> None: - pass - """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2776,32 +2756,34 @@ def function( style.SetGlobalStyle(style.CreateChromiumStyle()) def testIndentClosingBracketsInFunctionCall(self): + unformatted_code = textwrap.dedent("""\ + def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None, third_and_final_argument=True): + pass + + + def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_and_last_argument=None): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def function( + first_argument_xxxxxxxxxxxxxxxx=(0,), + second_argument=None, + third_and_final_argument=True + ): + pass + + + def function( + first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_and_last_argument=None + ): + pass + """) + try: style.SetGlobalStyle( style.CreateStyleFromConfig('{based_on_style: chromium,' ' indent_closing_brackets: True}')) - unformatted_code = textwrap.dedent("""\ - def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None, third_and_final_argument=True): - pass - - - def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_and_last_argument=None): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - def function( - first_argument_xxxxxxxxxxxxxxxx=(0,), - second_argument=None, - third_and_final_argument=True - ): - pass - - - def function( - first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_and_last_argument=None - ): - pass - """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2809,32 +2791,34 @@ def function( style.SetGlobalStyle(style.CreateChromiumStyle()) def testIndentClosingBracketsInTuple(self): + unformatted_code = textwrap.dedent("""\ + def function(): + some_var = ('a long element', 'another long element', 'short element', 'really really long element') + return True + + def function(): + some_var = ('a couple', 'small', 'elemens') + return False + """) + expected_formatted_code = textwrap.dedent("""\ + def function(): + some_var = ( + 'a long element', 'another long element', 'short element', + 'really really long element' + ) + return True + + + def function(): + some_var = ('a couple', 'small', 'elemens') + return False + """) + try: style.SetGlobalStyle( style.CreateStyleFromConfig('{based_on_style: chromium,' ' indent_closing_brackets: True}')) - unformatted_code = textwrap.dedent("""\ - def function(): - some_var = ('a long element', 'another long element', 'short element', 'really really long element') - return True - - def function(): - some_var = ('a couple', 'small', 'elemens') - return False - """) - expected_formatted_code = textwrap.dedent("""\ - def function(): - some_var = ( - 'a long element', 'another long element', 'short element', - 'really really long element' - ) - return True - - - def function(): - some_var = ('a couple', 'small', 'elemens') - return False - """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2842,32 +2826,34 @@ def function(): style.SetGlobalStyle(style.CreateChromiumStyle()) def testIndentClosingBracketsInList(self): + unformatted_code = textwrap.dedent("""\ + def function(): + some_var = ['a long element', 'another long element', 'short element', 'really really long element'] + return True + + def function(): + some_var = ['a couple', 'small', 'elemens'] + return False + """) + expected_formatted_code = textwrap.dedent("""\ + def function(): + some_var = [ + 'a long element', 'another long element', 'short element', + 'really really long element' + ] + return True + + + def function(): + some_var = ['a couple', 'small', 'elemens'] + return False + """) + try: style.SetGlobalStyle( style.CreateStyleFromConfig('{based_on_style: chromium,' ' indent_closing_brackets: True}')) - unformatted_code = textwrap.dedent("""\ - def function(): - some_var = ['a long element', 'another long element', 'short element', 'really really long element'] - return True - - def function(): - some_var = ['a couple', 'small', 'elemens'] - return False - """) - expected_formatted_code = textwrap.dedent("""\ - def function(): - some_var = [ - 'a long element', 'another long element', 'short element', - 'really really long element' - ] - return True - - - def function(): - some_var = ['a couple', 'small', 'elemens'] - return False - """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2875,38 +2861,40 @@ def function(): style.SetGlobalStyle(style.CreateChromiumStyle()) def testIndentClosingBracketsInDict(self): + unformatted_code = textwrap.dedent("""\ + def function(): + some_var = {1: ('a long element', 'and another really really long element that is really really amazingly long'), 2: 'another long element', 3: 'short element', 4: 'really really long element'} + return True + + def function(): + some_var = {1: 'a couple', 2: 'small', 3: 'elemens'} + return False + """) + expected_formatted_code = textwrap.dedent("""\ + def function(): + some_var = { + 1: + ( + 'a long element', + 'and another really really long element that is really really amazingly long' + ), + 2: 'another long element', + 3: 'short element', + 4: 'really really long element' + } + return True + + + def function(): + some_var = {1: 'a couple', 2: 'small', 3: 'elemens'} + return False + """) + try: style.SetGlobalStyle( style.CreateStyleFromConfig('{based_on_style: chromium,' ' indent_closing_brackets: True}')) - unformatted_code = textwrap.dedent("""\ - def function(): - some_var = {1: ('a long element', 'and another really really long element that is really really amazingly long'), 2: 'another long element', 3: 'short element', 4: 'really really long element'} - return True - - def function(): - some_var = {1: 'a couple', 2: 'small', 3: 'elemens'} - return False - """) - expected_formatted_code = textwrap.dedent("""\ - def function(): - some_var = { - 1: - ( - 'a long element', - 'and another really really long element that is really really amazingly long' - ), - 2: 'another long element', - 3: 'short element', - 4: 'really really long element' - } - return True - - - def function(): - some_var = {1: 'a couple', 2: 'small', 3: 'elemens'} - return False - """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2914,18 +2902,42 @@ def function(): style.SetGlobalStyle(style.CreateChromiumStyle()) def testMultipleDictionariesInList(self): - unformatted_code = """\ -class A: - def b(): - d = { - "123456": [ - { + unformatted_code = textwrap.dedent("""\ + class A: + def b(): + d = { + "123456": [ + { + "12": "aa" + }, + { + "12": "bb" + }, + { + "12": "cc", + "1234567890": { + "1234567": [{ + "12": "dd", + "12345": "text 1" + }, { + "12": "ee", + "12345": "text 2" + }] + } + } + ] + } + """) + expected_formatted_code = textwrap.dedent("""\ + class A: + + def b(): + d = { + "123456": [{ "12": "aa" - }, - { + }, { "12": "bb" - }, - { + }, { "12": "cc", "1234567890": { "1234567": [{ @@ -2936,55 +2948,12 @@ def b(): "12345": "text 2" }] } - } - ] - } -""" - expected_formatted_code = """\ -class A: - - def b(): - d = { - "123456": [{ - "12": "aa" - }, { - "12": "bb" - }, { - "12": "cc", - "1234567890": { - "1234567": [{ - "12": "dd", - "12345": "text 1" - }, { - "12": "ee", - "12345": "text 2" }] } - }] - } -""" + """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - def testTwoWordComparisonOperators(self): - unformatted_code = textwrap.dedent("""\ - _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl is not ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj) - _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl not in {ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj}) - """) - expected_formatted_code = textwrap.dedent("""\ - _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl - is not ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj) - _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl - not in {ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj}) - """) - - try: - style.SetGlobalStyle(style.CreatePEP8Style()) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) - if __name__ == '__main__': unittest.main() diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index eb0cc8ace..b09445513 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -1680,45 +1680,49 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testB20016122(self): + unformatted_code = textwrap.dedent("""\ + from a_very_long_or_indented_module_name_yada_yada import (long_argument_1, + long_argument_2) + """) + expected_formatted_code = textwrap.dedent("""\ + from a_very_long_or_indented_module_name_yada_yada import ( + long_argument_1, long_argument_2) + """) + try: style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: pep8, split_penalty_import_names: 350}')) - unformatted_code = textwrap.dedent("""\ - from a_very_long_or_indented_module_name_yada_yada import (long_argument_1, - long_argument_2) - """) - expected_formatted_code = textwrap.dedent("""\ - from a_very_long_or_indented_module_name_yada_yada import ( - long_argument_1, long_argument_2) - """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) + code = textwrap.dedent("""\ + class foo(): + + def __eq__(self, other): + return (isinstance(other, type(self)) + and self.xxxxxxxxxxx == other.xxxxxxxxxxx + and self.xxxxxxxx == other.xxxxxxxx + and self.aaaaaaaaaaaa == other.aaaaaaaaaaaa + and self.bbbbbbbbbbb == other.bbbbbbbbbbb + and self.ccccccccccccccccc == other.ccccccccccccccccc + and self.ddddddddddddddddddddddd == other.ddddddddddddddddddddddd + and self.eeeeeeeeeeee == other.eeeeeeeeeeee + and self.ffffffffffffff == other.time_completed + and self.gggggg == other.gggggg and self.hhh == other.hhh + and len(self.iiiiiiii) == len(other.iiiiiiii) + and all(jjjjjjj in other.iiiiiiii for jjjjjjj in self.iiiiiiii)) + """) + try: style.SetGlobalStyle( style.CreateStyleFromConfig('{based_on_style: chromium, ' 'split_before_logical_operator: True}')) - code = textwrap.dedent("""\ - class foo(): - - def __eq__(self, other): - return (isinstance(other, type(self)) - and self.xxxxxxxxxxx == other.xxxxxxxxxxx - and self.xxxxxxxx == other.xxxxxxxx - and self.aaaaaaaaaaaa == other.aaaaaaaaaaaa - and self.bbbbbbbbbbb == other.bbbbbbbbbbb - and self.ccccccccccccccccc == other.ccccccccccccccccc - and self.ddddddddddddddddddddddd == other.ddddddddddddddddddddddd - and self.eeeeeeeeeeee == other.eeeeeeeeeeee - and self.ffffffffffffff == other.time_completed - and self.gggggg == other.gggggg and self.hhh == other.hhh - and len(self.iiiiiiii) == len(other.iiiiiiii) - and all(jjjjjjj in other.iiiiiiii for jjjjjjj in self.iiiiiiii)) - """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) finally: @@ -1873,9 +1877,11 @@ def f(): if c: break return 0 """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) + try: style.SetGlobalStyle(style.CreatePEP8Style()) + + uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) finally: style.SetGlobalStyle(style.CreateChromiumStyle()) diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 8f59988aa..28798e3d3 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -16,6 +16,7 @@ import textwrap import unittest +from yapf.yapflib import py3compat from yapf.yapflib import reformatter from yapf.yapflib import style @@ -643,6 +644,60 @@ def func2( uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + def testTwoWordComparisonOperators(self): + unformatted_code = textwrap.dedent("""\ + _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl is not ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj) + _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl not in {ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj}) + """) + expected_formatted_code = textwrap.dedent("""\ + _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl + is not ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj) + _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl + not in {ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj}) + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + @unittest.skipUnless(not py3compat.PY3, 'Requires Python 2.7') + def testAsyncAsNonKeyword(self): + # In Python 2, async may be used as a non-keyword identifier. + code = textwrap.dedent("""\ + from util import async + + + class A(object): + def foo(self): + async.run() + + def bar(self): + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines, verify=False)) + + def testStableInlinedDictionaryFormatting(self): + unformatted_code = textwrap.dedent("""\ + def _(): + url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( + value, urllib.urlencode({'action': 'update', 'parameter': value})) + """) + expected_formatted_code = textwrap.dedent("""\ + def _(): + url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( + value, urllib.urlencode({ + 'action': 'update', + 'parameter': value + })) + """) + + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + reformatted_code = reformatter.Reformat(uwlines) + self.assertCodeEqual(expected_formatted_code, reformatted_code) + + uwlines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + reformatted_code = reformatter.Reformat(uwlines) + self.assertCodeEqual(expected_formatted_code, reformatted_code) + if __name__ == '__main__': unittest.main() diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index 98ce5a654..d06e40623 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -130,16 +130,18 @@ async def main(): self.assertCodeEqual(code, reformatter.Reformat(uwlines, verify=False)) def testNoSpacesAroundPowerOperator(self): + unformatted_code = textwrap.dedent("""\ + a**b + """) + expected_formatted_code = textwrap.dedent("""\ + a ** b + """) + try: style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: pep8, SPACES_AROUND_POWER_OPERATOR: True}')) - unformatted_code = textwrap.dedent("""\ - a**b - """) - expected_formatted_code = textwrap.dedent("""\ - a ** b - """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -147,17 +149,19 @@ def testNoSpacesAroundPowerOperator(self): style.SetGlobalStyle(style.CreatePEP8Style()) def testSpacesAroundDefaultOrNamedAssign(self): + unformatted_code = textwrap.dedent("""\ + f(a=5) + """) + expected_formatted_code = textwrap.dedent("""\ + f(a = 5) + """) + try: style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: pep8, ' 'SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN: True}')) - unformatted_code = textwrap.dedent("""\ - f(a=5) - """) - expected_formatted_code = textwrap.dedent("""\ - f(a = 5) - """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -279,16 +283,8 @@ async def start_websocket(): def testSplittingArguments(self): if sys.version_info[1] < 5: return - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: pep8, ' - 'dedent_closing_brackets: true, ' - 'coalesce_brackets: false, ' - 'space_between_ending_comma_and_closing_bracket: false, ' - 'split_arguments_when_comma_terminated: true, ' - 'split_before_first_argument: true}')) - unformatted_code = """\ + + unformatted_code = """\ async def open_file(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None): pass @@ -301,7 +297,7 @@ def open_file(file, mode='r', buffering=-1, encoding=None, errors=None, newline= def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): pass """ - expected_formatted_code = """\ + expected_formatted_code = """\ async def open_file( file, mode='r', @@ -337,6 +333,17 @@ def open_file( def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): pass """ + + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: pep8, ' + 'dedent_closing_brackets: true, ' + 'coalesce_brackets: false, ' + 'space_between_ending_comma_and_closing_bracket: false, ' + 'split_arguments_when_comma_terminated: true, ' + 'split_before_first_argument: true}')) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) From f659ecc5dc282377d4f58c07651ea8fdd6ea5025 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 3 Feb 2020 17:22:46 -0800 Subject: [PATCH 442/719] Reformat --- yapf/yapflib/blank_line_calculator.py | 4 ++-- yapf/yapflib/format_decision_state.py | 8 ++++---- yapf/yapflib/unwrapped_line.py | 5 ++--- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/yapf/yapflib/blank_line_calculator.py b/yapf/yapflib/blank_line_calculator.py index c239ee7eb..50d834fcc 100644 --- a/yapf/yapflib/blank_line_calculator.py +++ b/yapf/yapflib/blank_line_calculator.py @@ -139,8 +139,8 @@ def _SetBlankLinesBetweenCommentAndClassFunc(self, node): if not self.last_was_decorator: self._SetNumNewlines(node.children[index].children[0], _ONE_BLANK_LINE) index += 1 - if (index and node.children[index].lineno - - 1 == node.children[index - 1].children[0].lineno): + if (index and node.children[index].lineno - 1 + == node.children[index - 1].children[0].lineno): self._SetNumNewlines(node.children[index], _NO_BLANK_LINES) else: if self.last_comment_lineno + 1 == node.children[index].lineno: diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 18e29ac73..e3057849c 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -370,8 +370,8 @@ def SurroundedByParens(token): ########################################################################### # Argument List Splitting if (style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and not current.is_comment and - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in - current.subtypes): + format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST + in current.subtypes): if (previous.value not in {'=', ':', '*', '**'} and current.value not in ':=,)' and not _IsFunctionDefinition(previous)): # If we're going to split the lines because of named arguments, then we @@ -966,8 +966,8 @@ def _GetNewlineColumn(self): if (self.param_list_stack and not self.param_list_stack[-1].SplitBeforeClosingBracket( - top_of_stack.indent) and top_of_stack.indent == ( - (self.line.depth + 1) * style.Get('INDENT_WIDTH'))): + top_of_stack.indent) and top_of_stack.indent + == ((self.line.depth + 1) * style.Get('INDENT_WIDTH'))): if (format_token.Subtype.PARAMETER_START in current.subtypes or (previous.is_comment and format_token.Subtype.PARAMETER_START in previous.subtypes)): diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index ff51db504..c75d285ae 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -319,9 +319,8 @@ def _SpaceRequiredBetween(left, right): # A typed argument should have a space after the colon. return True if left.is_string: - if (rval == '=' and - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in right.subtypes - ): + if (rval == '=' and format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST + in right.subtypes): # If there is a type hint, then we don't want to add a space between the # equal sign and the hint. return False From 1b1f22db1bb6e6381aaddb4ddc1bc0554c10a1ff Mon Sep 17 00:00:00 2001 From: Brian Mego Date: Tue, 4 Feb 2020 07:08:51 -0600 Subject: [PATCH 443/719] Comments and formatting --- yapf/__init__.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 0890d8d86..84f1e3bed 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -216,18 +216,20 @@ def main(argv): return 1 if changed and (args.diff or args.quiet) else 0 def print_help(args): - if args.style is None and not args.no_local_style: - args.style = file_resources.GetDefaultStyleForDir(os.getcwd()) - style.SetGlobalStyle(style.CreateStyleFromConfig(args.style)) - print('[style]') - for option, docstring in sorted(style.Help().items()): - for line in docstring.splitlines(): - print('#', line and ' ' or '', line, sep='') - option_value = style.Get(option) - if isinstance(option_value, set) or isinstance(option_value, list): - option_value = ', '.join(map(str, option_value)) - print(option.lower(), '=', option_value, sep='') - print() + """Prints the help menu.""" + + if args.style is None and not args.no_local_style: + args.style = file_resources.GetDefaultStyleForDir(os.getcwd()) + style.SetGlobalStyle(style.CreateStyleFromConfig(args.style)) + print('[style]') + for option, docstring in sorted(style.Help().items()): + for line in docstring.splitlines(): + print('#', line and ' ' or '', line, sep='') + option_value = style.Get(option) + if isinstance(option_value, set) or isinstance(option_value, list): + option_value = ', '.join(map(str, option_value)) + print(option.lower(), '=', option_value, sep='') + print() def FormatFiles(filenames, From b0105fb95161e1da03c23cb2a1ce634a119aceb5 Mon Sep 17 00:00:00 2001 From: Bill Wendling <5993918+gwelymernans@users.noreply.github.com> Date: Tue, 4 Feb 2020 12:29:30 -0800 Subject: [PATCH 444/719] Update __init__.py --- yapf/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/yapf/__init__.py b/yapf/__init__.py index 84f1e3bed..fbee30629 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -215,6 +215,7 @@ def main(argv): verbose=args.verbose) return 1 if changed and (args.diff or args.quiet) else 0 + def print_help(args): """Prints the help menu.""" From b55693f01b3036d1826a43e7f25183c840735a5e Mon Sep 17 00:00:00 2001 From: Wade Carpenter Date: Fri, 28 Feb 2020 16:22:27 -0800 Subject: [PATCH 445/719] Add space inside brackets For issue #811, add a style option "SPACE_INSIDE_BRACKETS". ``SPACE_INSIDE_BRACKETS`` Use spaces inside brackets and parens. For example: .. code-block:: python method_call( 1 ) my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] my_set = { 1, 2, 3 } This Bool option (False by default) inserts spaces after opening, and before closing brackets (parens, brackets, and braces, to be precise). Added a new test case to cover the changes in reformatter_pep8_test.py. Slight overall increase in test coverage +3 total, +1 in unwrapped_line. --- README.rst | 13 +++- yapf/yapflib/style.py | 9 +++ yapf/yapflib/unwrapped_line.py | 16 +++-- yapftests/reformatter_pep8_test.py | 106 +++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index 31f6d288c..1fd04ea43 100644 --- a/README.rst +++ b/README.rst @@ -594,6 +594,15 @@ Knobs ``SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET`` Insert a space between the ending comma and closing bracket of a list, etc. +``SPACE_INSIDE_BRACKETS`` + Use spaces inside brackets, braces, and parentheses. For example: + + .. code-block:: python + + method_call( 1 ) + my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] + my_set = { 1, 2, 3 } + ``SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED`` Split before arguments if the argument list is terminated by a comma. @@ -813,7 +822,7 @@ I still get non Pep8 compliant code! Why? YAPF tries very hard to be fully PEP 8 compliant. However, it is paramount to not risk altering the semantics of your code. Thus, YAPF tries to be as safe as possible and does not change the token stream -(e.g., by adding parenthesis). +(e.g., by adding parentheses). All these cases however, can be easily fixed manually. For instance, .. code-block:: python @@ -822,7 +831,7 @@ All these cases however, can be easily fixed manually. For instance, FOO = my_variable_1 + my_variable_2 + my_variable_3 + my_variable_4 + my_variable_5 + my_variable_6 + my_variable_7 + my_variable_8 -won't be split, but you can easily get it right by just adding parenthesis: +won't be split, but you can easily get it right by just adding parentheses: .. code-block:: python diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 87cab028b..5f2483fb8 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -208,6 +208,13 @@ def method(): SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=textwrap.dedent("""\ Insert a space between the ending comma and closing bracket of a list, etc."""), + SPACE_INSIDE_BRACKETS=textwrap.dedent("""\ + Use spaces inside brackets, braces, and parentheses. For example: + + method_call( 1 ) + my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] + my_set = { 1, 2, 3 } + """), SPACES_AROUND_POWER_OPERATOR=textwrap.dedent("""\ Use spaces around the power operator."""), SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=textwrap.dedent("""\ @@ -384,6 +391,7 @@ def CreatePEP8Style(): JOIN_MULTIPLE_LINES=True, NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=set(), SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=True, + SPACE_INSIDE_BRACKETS=False, SPACES_AROUND_POWER_OPERATOR=False, SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=False, SPACES_BEFORE_COMMENT=2, @@ -566,6 +574,7 @@ def _IntOrIntListConverter(s): JOIN_MULTIPLE_LINES=_BoolConverter, NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=_StringSetConverter, SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=_BoolConverter, + SPACE_INSIDE_BRACKETS=_BoolConverter, SPACES_AROUND_POWER_OPERATOR=_BoolConverter, SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=_BoolConverter, SPACES_BEFORE_COMMENT=_IntOrIntListConverter, diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index c75d285ae..3d5464049 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -287,6 +287,8 @@ def _SpaceRequiredBetween(left, right): if lval == ',' and rval == ':': # We do want a space between a comma and colon. return True + if lval in pytree_utils.OPENING_BRACKETS and rval == ':': + return style.Get('SPACE_INSIDE_BRACKETS') if rval in ':,': # Otherwise, we never want a space before a colon or comma. return False @@ -394,43 +396,43 @@ def _SpaceRequiredBetween(left, right): if (lval in pytree_utils.OPENING_BRACKETS and rval in pytree_utils.OPENING_BRACKETS): # Nested objects' opening brackets shouldn't be separated. - return False + return style.Get('SPACE_INSIDE_BRACKETS') if (lval in pytree_utils.CLOSING_BRACKETS and rval in pytree_utils.CLOSING_BRACKETS): # Nested objects' closing brackets shouldn't be separated. - return False + return style.Get('SPACE_INSIDE_BRACKETS') if lval in pytree_utils.CLOSING_BRACKETS and rval in '([': # A call, set, dictionary, or subscript that has a call or subscript after # it shouldn't have a space between them. return False if lval in pytree_utils.OPENING_BRACKETS and _IsIdNumberStringToken(right): # Don't separate the opening bracket from the first item. - return False + return style.Get('SPACE_INSIDE_BRACKETS') if left.is_name and rval in '([': # Don't separate a call or array access from the name. return False if rval in pytree_utils.CLOSING_BRACKETS: # Don't separate the closing bracket from the last item. # FIXME(morbo): This might be too permissive. - return False + return style.Get('SPACE_INSIDE_BRACKETS') if lval == 'print' and rval == '(': # Special support for the 'print' function. return False if lval in pytree_utils.OPENING_BRACKETS and _IsUnaryOperator(right): # Don't separate a unary operator from the opening bracket. - return False + return style.Get('SPACE_INSIDE_BRACKETS') if (lval in pytree_utils.OPENING_BRACKETS and (format_token.Subtype.VARARGS_STAR in right.subtypes or format_token.Subtype.KWARGS_STAR_STAR in right.subtypes)): # Don't separate a '*' or '**' from the opening bracket. - return False + return style.Get('SPACE_INSIDE_BRACKETS') if rval == ';': # Avoid spaces before a semicolon. (Why is there a semicolon?!) return False if lval == '(' and rval == 'await': # Special support for the 'await' keyword. Don't separate the 'await' # keyword from an opening paren. - return False + return style.Get('SPACE_INSIDE_BRACKETS') return True diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 28798e3d3..dd45531ff 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -699,5 +699,111 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatted_code) +class TestsForSpacesInsideBrackets(yapf_test_helper.YAPFTest): + """Test the SPACE_INSIDE_BRACKETS style option.""" + unformatted_code = textwrap.dedent("""\ + foo( ) + foo((1,)) + foo((1, 2, 3)) + foo((1, + 2, + 3,)) + my_dict[3][1][get_index(*args,**kwargs)] + my_dict[3][1][get_index(**kwargs)] + my_set={1,2,3} + copy_dict = my_dict[:] + print (my_set) + x = my_dict[4] (foo(*args)) + xyz = ((10+ 3)/(5- 2**(6+x))) + val = "mystring"[3] + """) + + def testEnabled(self): + style.SetGlobalStyle( + style.CreateStyleFromConfig('{space_inside_brackets: True}')) + + expected_formatted_code = textwrap.dedent("""\ + foo() + foo( ( 1, ) ) + foo( ( 1, 2, 3 ) ) + foo( ( + 1, + 2, + 3, + ) ) + my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] + my_dict[ 3 ][ 1 ][ get_index( **kwargs ) ] + my_set = { 1, 2, 3 } + copy_dict = my_dict[ : ] + print( my_set ) + x = my_dict[ 4 ]( foo( *args ) ) + xyz = ( ( 10 + 3 ) / ( 5 - 2**( 6 + x ) ) ) + val = "mystring"[ 3 ] + """) + + uwlines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testDefault(self): + style.SetGlobalStyle(style.CreatePEP8Style()) + + expected_formatted_code = textwrap.dedent("""\ + foo() + foo((1, )) + foo((1, 2, 3)) + foo(( + 1, + 2, + 3, + )) + my_dict[3][1][get_index(*args, **kwargs)] + my_dict[3][1][get_index(**kwargs)] + my_set = {1, 2, 3} + copy_dict = my_dict[:] + print(my_set) + x = my_dict[4](foo(*args)) + xyz = ((10 + 3) / (5 - 2**(6 + x))) + val = "mystring"[3] + """) + + uwlines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') + def testAwait(self): + style.SetGlobalStyle( + style.CreateStyleFromConfig('{space_inside_brackets: True}')) + unformatted_code = textwrap.dedent("""\ + import asyncio + import time + + @print_args + async def slow_operation(): + await asyncio.sleep(1) + # print("Slow operation {} complete".format(n)) + async def main(): + start = time.time() + if (await get_html()): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + import asyncio + import time + + + @print_args + async def slow_operation(): + await asyncio.sleep( 1 ) + + # print("Slow operation {} complete".format(n)) + async def main(): + start = time.time() + if ( await get_html() ): + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + if __name__ == '__main__': unittest.main() From 95821d6143f54d69c62f3305990eab1b9d14aa20 Mon Sep 17 00:00:00 2001 From: Wade Carpenter Date: Mon, 2 Mar 2020 20:49:28 -0800 Subject: [PATCH 446/719] Fix SPACE_INSIDE_BRACKETS special cases 1. There were a few special cases missed in the original change: - my_list[ : ] - my_list[ x: ] - foo( "abc" ) 2. Updated comments where SPACE_INSIDE_BRACKETS is used. 3. Updated test cases to catch the special cases in (1). For issue #811. --- yapf/yapflib/unwrapped_line.py | 33 ++++++--- yapftests/reformatter_pep8_test.py | 104 ++++++++++++++++++++--------- 2 files changed, 95 insertions(+), 42 deletions(-) diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 3d5464049..e4cb42853 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -287,8 +287,12 @@ def _SpaceRequiredBetween(left, right): if lval == ',' and rval == ':': # We do want a space between a comma and colon. return True - if lval in pytree_utils.OPENING_BRACKETS and rval == ':': - return style.Get('SPACE_INSIDE_BRACKETS') + if style.Get('SPACE_INSIDE_BRACKETS'): + # Supersede the "no space before a colon or comma" check. + if lval in pytree_utils.OPENING_BRACKETS and rval == ':': + return True + if rval in pytree_utils.CLOSING_BRACKETS and lval == ':': + return True if rval in ':,': # Otherwise, we never want a space before a colon or comma. return False @@ -330,6 +334,11 @@ def _SpaceRequiredBetween(left, right): # A string followed by something other than a subscript, closing bracket, # dot, or a binary op should have a space after it. return True + if rval in pytree_utils.CLOSING_BRACKETS: + # A string followed by closing brackets should have a space after it + # depending on SPACE_INSIDE_BRACKETS. A string followed by opening + # brackets, however, should not. + return style.Get('SPACE_INSIDE_BRACKETS') if format_token.Subtype.SUBSCRIPT_BRACKET in right.subtypes: # It's legal to do this in Python: 'hello'[a] return False @@ -395,43 +404,49 @@ def _SpaceRequiredBetween(left, right): return False if (lval in pytree_utils.OPENING_BRACKETS and rval in pytree_utils.OPENING_BRACKETS): - # Nested objects' opening brackets shouldn't be separated. + # Nested objects' opening brackets shouldn't be separated, unless enabled + # by SPACE_INSIDE_BRACKETS. return style.Get('SPACE_INSIDE_BRACKETS') if (lval in pytree_utils.CLOSING_BRACKETS and rval in pytree_utils.CLOSING_BRACKETS): - # Nested objects' closing brackets shouldn't be separated. + # Nested objects' closing brackets shouldn't be separated, unless enabled + # by SPACE_INSIDE_BRACKETS. return style.Get('SPACE_INSIDE_BRACKETS') if lval in pytree_utils.CLOSING_BRACKETS and rval in '([': # A call, set, dictionary, or subscript that has a call or subscript after # it shouldn't have a space between them. return False if lval in pytree_utils.OPENING_BRACKETS and _IsIdNumberStringToken(right): - # Don't separate the opening bracket from the first item. + # Don't separate the opening bracket from the first item, unless enabled + # by SPACE_INSIDE_BRACKETS. return style.Get('SPACE_INSIDE_BRACKETS') if left.is_name and rval in '([': # Don't separate a call or array access from the name. return False if rval in pytree_utils.CLOSING_BRACKETS: - # Don't separate the closing bracket from the last item. + # Don't separate the closing bracket from the last item, unless enabled + # by SPACE_INSIDE_BRACKETS. # FIXME(morbo): This might be too permissive. return style.Get('SPACE_INSIDE_BRACKETS') if lval == 'print' and rval == '(': # Special support for the 'print' function. return False if lval in pytree_utils.OPENING_BRACKETS and _IsUnaryOperator(right): - # Don't separate a unary operator from the opening bracket. + # Don't separate a unary operator from the opening bracket, unless enabled + # by SPACE_INSIDE_BRACKETS. return style.Get('SPACE_INSIDE_BRACKETS') if (lval in pytree_utils.OPENING_BRACKETS and (format_token.Subtype.VARARGS_STAR in right.subtypes or format_token.Subtype.KWARGS_STAR_STAR in right.subtypes)): - # Don't separate a '*' or '**' from the opening bracket. + # Don't separate a '*' or '**' from the opening bracket, unless enabled + # by SPACE_INSIDE_BRACKETS. return style.Get('SPACE_INSIDE_BRACKETS') if rval == ';': # Avoid spaces before a semicolon. (Why is there a semicolon?!) return False if lval == '(' and rval == 'await': # Special support for the 'await' keyword. Don't separate the 'await' - # keyword from an opening paren. + # keyword from an opening paren, unless enabled by SPACE_INSIDE_BRACKETS. return style.Get('SPACE_INSIDE_BRACKETS') return True diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index dd45531ff..8f336e154 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -702,20 +702,32 @@ def _(): class TestsForSpacesInsideBrackets(yapf_test_helper.YAPFTest): """Test the SPACE_INSIDE_BRACKETS style option.""" unformatted_code = textwrap.dedent("""\ - foo( ) + foo() + foo(1) + foo(1,2) foo((1,)) - foo((1, 2, 3)) - foo((1, - 2, - 3,)) - my_dict[3][1][get_index(*args,**kwargs)] - my_dict[3][1][get_index(**kwargs)] - my_set={1,2,3} - copy_dict = my_dict[:] - print (my_set) - x = my_dict[4] (foo(*args)) - xyz = ((10+ 3)/(5- 2**(6+x))) - val = "mystring"[3] + foo((1, 2)) + foo((1, 2,)) + foo(bar['baz'][0]) + set1 = {1, 2, 3} + dict1 = {1: 1, foo: 2, 3: bar} + dict2 = { + 1: 1, + foo: 2, + 3: bar, + } + dict3[3][1][get_index(*args,**kwargs)] + dict4[3][1][get_index(**kwargs)] + x = dict5[4](foo(*args)) + a = list1[:] + b = list2[slice_start:] + c = list3[slice_start:slice_end] + d = list4[slice_start:slice_end:] + e = list5[slice_start:slice_end:slice_step] + # Print gets special handling + print(set2) + compound = ((10+3)/(5-2**(6+x))) + string_idx = "mystring"[3] """) def testEnabled(self): @@ -724,21 +736,34 @@ def testEnabled(self): expected_formatted_code = textwrap.dedent("""\ foo() + foo( 1 ) + foo( 1, 2 ) foo( ( 1, ) ) - foo( ( 1, 2, 3 ) ) + foo( ( 1, 2 ) ) foo( ( 1, 2, - 3, ) ) - my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] - my_dict[ 3 ][ 1 ][ get_index( **kwargs ) ] - my_set = { 1, 2, 3 } - copy_dict = my_dict[ : ] - print( my_set ) - x = my_dict[ 4 ]( foo( *args ) ) - xyz = ( ( 10 + 3 ) / ( 5 - 2**( 6 + x ) ) ) - val = "mystring"[ 3 ] + foo( bar[ 'baz' ][ 0 ] ) + set1 = { 1, 2, 3 } + dict1 = { 1: 1, foo: 2, 3: bar } + dict2 = { + 1: 1, + foo: 2, + 3: bar, + } + dict3[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] + dict4[ 3 ][ 1 ][ get_index( **kwargs ) ] + x = dict5[ 4 ]( foo( *args ) ) + a = list1[ : ] + b = list2[ slice_start: ] + c = list3[ slice_start:slice_end ] + d = list4[ slice_start:slice_end: ] + e = list5[ slice_start:slice_end:slice_step ] + # Print gets special handling + print( set2 ) + compound = ( ( 10 + 3 ) / ( 5 - 2**( 6 + x ) ) ) + string_idx = "mystring"[ 3 ] """) uwlines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) @@ -749,21 +774,34 @@ def testDefault(self): expected_formatted_code = textwrap.dedent("""\ foo() + foo(1) + foo(1, 2) foo((1, )) - foo((1, 2, 3)) + foo((1, 2)) foo(( 1, 2, - 3, )) - my_dict[3][1][get_index(*args, **kwargs)] - my_dict[3][1][get_index(**kwargs)] - my_set = {1, 2, 3} - copy_dict = my_dict[:] - print(my_set) - x = my_dict[4](foo(*args)) - xyz = ((10 + 3) / (5 - 2**(6 + x))) - val = "mystring"[3] + foo(bar['baz'][0]) + set1 = {1, 2, 3} + dict1 = {1: 1, foo: 2, 3: bar} + dict2 = { + 1: 1, + foo: 2, + 3: bar, + } + dict3[3][1][get_index(*args, **kwargs)] + dict4[3][1][get_index(**kwargs)] + x = dict5[4](foo(*args)) + a = list1[:] + b = list2[slice_start:] + c = list3[slice_start:slice_end] + d = list4[slice_start:slice_end:] + e = list5[slice_start:slice_end:slice_step] + # Print gets special handling + print(set2) + compound = ((10 + 3) / (5 - 2**(6 + x))) + string_idx = "mystring"[3] """) uwlines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) From 741cbcf498956e4c0863680a463c3da6f5a5dd44 Mon Sep 17 00:00:00 2001 From: Wade Carpenter Date: Mon, 2 Mar 2020 21:52:14 -0800 Subject: [PATCH 447/719] Update CHANGELOG for SPACE_INSIDE_BRACKETS --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index d0c0b808d..e1feffb27 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,8 @@ - Don't over-indent a parameter list when not needed. But make sure it is properly indented so that it doesn't collide with the lines afterwards. - Don't split between two-word comparison operators: "is not", "not in", etc. +- New knob `SPACE_INSIDE_BRACKETS` to add spaces inside brackets, braces, and + parentheses. ## [0.29.0] 2019-11-28 ### Added From 88e70b2111ee6a7684d461552e4cd9958fa564ce Mon Sep 17 00:00:00 2001 From: Wade Carpenter Date: Tue, 3 Mar 2020 15:43:19 -0800 Subject: [PATCH 448/719] Knob for spaces around subscript colon *SPACES_AROUND_SUBSCRIPT_COLON* Use spaces around the subscript / slice operator. For example: ```python my_list[1 : 10 : 2] ``` This Bool option (False by default) inserts spaces around colons when they're used as a subscript / slice operator. There's a potential interaction with SPACE_INSIDE_BRACKETS, so there's an extra test case in TestsForSpacesAroundSubscriptColon to verify the behaviour with both enabled. --- CHANGELOG | 2 + README.rst | 7 +++ yapf/yapflib/format_token.py | 6 +++ yapf/yapflib/style.py | 7 +++ yapf/yapflib/unwrapped_line.py | 9 ++++ yapftests/reformatter_pep8_test.py | 72 ++++++++++++++++++++++++++++++ 6 files changed, 103 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index e1feffb27..e24d0ee07 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,8 @@ - Don't split between two-word comparison operators: "is not", "not in", etc. - New knob `SPACE_INSIDE_BRACKETS` to add spaces inside brackets, braces, and parentheses. +- New knob `SPACES_AROUND_SUBSCRIPT_COLON` to add spaces around the subscript / + slice operator. ## [0.29.0] 2019-11-28 ### Added diff --git a/README.rst b/README.rst index 1fd04ea43..125a3b59e 100644 --- a/README.rst +++ b/README.rst @@ -545,6 +545,13 @@ Knobs Set to ``True`` to prefer spaces around the assignment operator for default or keyword arguments. +``SPACES_AROUND_SUBSCRIPT_COLON`` + Use spaces around the subscript / slice operator. For example: + + .. code-block:: python + + my_list[1 : 10 : 2] + ``SPACES_BEFORE_COMMENT`` The number of spaces required before a trailing comment. This can be a single value (representing the number of spaces diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 79b2b5c92..e6af9422f 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -313,6 +313,12 @@ def is_simple_expr(self): """Token is an operator in a simple expression.""" return Subtype.SIMPLE_EXPRESSION in self.subtypes + @property + @py3compat.lru_cache() + def is_subscript_colon(self): + """Token is a subscript colon.""" + return Subtype.SUBSCRIPT_COLON in self.subtypes + @property @py3compat.lru_cache() def name(self): diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 5f2483fb8..84994b323 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -219,6 +219,11 @@ def method(): Use spaces around the power operator."""), SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=textwrap.dedent("""\ Use spaces around default or named assigns."""), + SPACES_AROUND_SUBSCRIPT_COLON=textwrap.dedent("""\ + Use spaces around the subscript / slice operator. For example: + + my_list[1 : 10 : 2] + """), SPACES_BEFORE_COMMENT=textwrap.dedent("""\ The number of spaces required before a trailing comment. This can be a single value (representing the number of spaces @@ -394,6 +399,7 @@ def CreatePEP8Style(): SPACE_INSIDE_BRACKETS=False, SPACES_AROUND_POWER_OPERATOR=False, SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=False, + SPACES_AROUND_SUBSCRIPT_COLON=False, SPACES_BEFORE_COMMENT=2, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False, SPLIT_ALL_COMMA_SEPARATED_VALUES=False, @@ -577,6 +583,7 @@ def _IntOrIntListConverter(s): SPACE_INSIDE_BRACKETS=_BoolConverter, SPACES_AROUND_POWER_OPERATOR=_BoolConverter, SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=_BoolConverter, + SPACES_AROUND_SUBSCRIPT_COLON=_BoolConverter, SPACES_BEFORE_COMMENT=_IntOrIntListConverter, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter, SPLIT_ALL_COMMA_SEPARATED_VALUES=_BoolConverter, diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index e4cb42853..ec28f9b2d 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -261,6 +261,10 @@ def _PriorityIndicatingNoSpace(tok): return _HasPrecedence(tok) +def _IsSubscriptColonAndValuePair(token1, token2): + return (token1.is_number or token1.is_name) and token2.is_subscript_colon + + def _SpaceRequiredBetween(left, right): """Return True if a space is required between the left and right token.""" lval = left.value @@ -293,6 +297,11 @@ def _SpaceRequiredBetween(left, right): return True if rval in pytree_utils.CLOSING_BRACKETS and lval == ':': return True + if (style.Get('SPACES_AROUND_SUBSCRIPT_COLON') and + (_IsSubscriptColonAndValuePair(left, right) or + _IsSubscriptColonAndValuePair(right, left))): + # Supersede the "never want a space before a colon or comma" check. + return True if rval in ':,': # Otherwise, we never want a space before a colon or comma. return False diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 8f336e154..bdd074a7f 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -843,5 +843,77 @@ async def main(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) +class TestsForSpacesAroundSubscriptColon(yapf_test_helper.YAPFTest): + """Test the SPACES_AROUND_SUBSCRIPT_COLON style option.""" + unformatted_code = textwrap.dedent("""\ + a = list1[ : ] + b = list2[ slice_start: ] + c = list3[ slice_start:slice_end ] + d = list4[ slice_start:slice_end: ] + e = list5[ slice_start:slice_end:slice_step ] + a1 = list1[ : ] + b1 = list2[ 1: ] + c1 = list3[ 1:20 ] + d1 = list4[ 1:20: ] + e1 = list5[ 1:20:3 ] + """) + + def testEnabled(self): + style.SetGlobalStyle( + style.CreateStyleFromConfig('{spaces_around_subscript_colon: True}')) + expected_formatted_code = textwrap.dedent("""\ + a = list1[:] + b = list2[slice_start :] + c = list3[slice_start : slice_end] + d = list4[slice_start : slice_end :] + e = list5[slice_start : slice_end : slice_step] + a1 = list1[:] + b1 = list2[1 :] + c1 = list3[1 : 20] + d1 = list4[1 : 20 :] + e1 = list5[1 : 20 : 3] + """) + uwlines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testWithSpaceInsideBrackets(self): + style.SetGlobalStyle( + style.CreateStyleFromConfig('{' + 'spaces_around_subscript_colon: true, ' + 'space_inside_brackets: true,' + '}')) + expected_formatted_code = textwrap.dedent("""\ + a = list1[ : ] + b = list2[ slice_start : ] + c = list3[ slice_start : slice_end ] + d = list4[ slice_start : slice_end : ] + e = list5[ slice_start : slice_end : slice_step ] + a1 = list1[ : ] + b1 = list2[ 1 : ] + c1 = list3[ 1 : 20 ] + d1 = list4[ 1 : 20 : ] + e1 = list5[ 1 : 20 : 3 ] + """) + uwlines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + def testDefault(self): + style.SetGlobalStyle(style.CreatePEP8Style()) + expected_formatted_code = textwrap.dedent("""\ + a = list1[:] + b = list2[slice_start:] + c = list3[slice_start:slice_end] + d = list4[slice_start:slice_end:] + e = list5[slice_start:slice_end:slice_step] + a1 = list1[:] + b1 = list2[1:] + c1 = list3[1:20] + d1 = list4[1:20:] + e1 = list5[1:20:3] + """) + uwlines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + if __name__ == '__main__': unittest.main() From ecfaa2f672ea9ca8bc6d54a9183e061ff3aabd81 Mon Sep 17 00:00:00 2001 From: Brian Mego Date: Sat, 14 Mar 2020 15:38:29 -0500 Subject: [PATCH 449/719] Adds FORCE_MULTILINE_DICT knob (#808) * Adds FORCE_MULTILINE_DICT knob * Add lineending tests * Formatting --- CHANGELOG | 2 ++ README.rst | 4 ++++ yapf/yapflib/reformatter.py | 3 +++ yapf/yapflib/style.py | 9 +++++++ yapftests/file_resources_test.py | 28 ++++++++++++++++++++++ yapftests/reformatter_basic_test.py | 37 +++++++++++++++++++++++++++-- 6 files changed, 81 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e24d0ee07..236ca8979 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,8 @@ - Don't over-indent a parameter list when not needed. But make sure it is properly indented so that it doesn't collide with the lines afterwards. - Don't split between two-word comparison operators: "is not", "not in", etc. +- Adds `FORCE_MULTILINE_DICT` knob to ensure dictionaries always split, + even when shorter than the max line length. - New knob `SPACE_INSIDE_BRACKETS` to add spaces inside brackets, braces, and parentheses. - New knob `SPACES_AROUND_SUBSCRIPT_COLON` to add spaces around the subscript / diff --git a/README.rst b/README.rst index 125a3b59e..274e1f81b 100644 --- a/README.rst +++ b/README.rst @@ -473,6 +473,10 @@ Knobs ``EACH_DICT_ENTRY_ON_SEPARATE_LINE`` Place each dictionary entry onto its own line. +``FORCE_MULTILINE_DICT`` + Respect EACH_DICT_ENTRY_ON_SEPARATE_LINE even if the line is shorter than + COLUMN_LIMIT. + ``I18N_COMMENT`` The regex for an internationalization comment. The presence of this comment stops reformatting of that line, because the comments are required to be diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 0faa91ff4..7ec9888ad 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -257,6 +257,9 @@ def _CanPlaceOnSingleLine(uwline): Returns: True if the line can or should be added to a single line. False otherwise. """ + token_names = [x.name for x in uwline.tokens] + if (style.Get('FORCE_MULTILINE_DICT') and 'LBRACE' in token_names): + return False indent_amt = style.Get('INDENT_WIDTH') * uwline.depth last = uwline.last last_index = -1 diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 84994b323..374794119 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -172,6 +172,13 @@ def method(): if the list is comma-terminated."""), EACH_DICT_ENTRY_ON_SEPARATE_LINE=textwrap.dedent("""\ Place each dictionary entry onto its own line."""), + FORCE_MULTILINE_DICT=textwrap.dedent("""\ + Require multiline dictionary even if it would normally fit on one line. + For example: + + config = { + 'key1': 'value1' + }"""), I18N_COMMENT=textwrap.dedent("""\ The regex for an i18n comment. The presence of this comment stops reformatting of that line, because the comments are required to be @@ -388,6 +395,7 @@ def CreatePEP8Style(): INDENT_CLOSING_BRACKETS=False, DISABLE_ENDING_COMMA_HEURISTIC=False, EACH_DICT_ENTRY_ON_SEPARATE_LINE=True, + FORCE_MULTILINE_DICT=False, I18N_COMMENT='', I18N_FUNCTION_CALL='', INDENT_DICTIONARY_VALUE=False, @@ -572,6 +580,7 @@ def _IntOrIntListConverter(s): INDENT_CLOSING_BRACKETS=_BoolConverter, DISABLE_ENDING_COMMA_HEURISTIC=_BoolConverter, EACH_DICT_ENTRY_ON_SEPARATE_LINE=_BoolConverter, + FORCE_MULTILINE_DICT=_BoolConverter, I18N_COMMENT=str, I18N_FUNCTION_CALL=_StringListConverter, INDENT_DICTIONARY_VALUE=_BoolConverter, diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 07e31342e..c91d93cf8 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -439,5 +439,33 @@ def test_write_encoded_to_stdout(self): self.assertEqual(stream.getvalue(), s) +class LineEndingTest(unittest.TestCase): + + def test_line_ending_linefeed(self): + lines = ['spam\n', 'spam\n'] + actual = file_resources.LineEnding(lines) + self.assertEqual(actual, '\n') + + def test_line_ending_carriage_return(self): + lines = ['spam\r', 'spam\r'] + actual = file_resources.LineEnding(lines) + self.assertEqual(actual, '\r') + + def test_line_ending_combo(self): + lines = ['spam\r\n', 'spam\r\n'] + actual = file_resources.LineEnding(lines) + self.assertEqual(actual, '\r\n') + + def test_line_ending_weighted(self): + lines = [ + 'spam\n', + 'spam\n', + 'spam\r', + 'spam\r\n', + ] + actual = file_resources.LineEnding(lines) + self.assertEqual(actual, '\n') + + if __name__ == '__main__': unittest.main() diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 8e93042e5..7868d0b06 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1937,8 +1937,8 @@ def mark_game_scored(gid): def testDontAddBlankLineAfterMultilineString(self): code = textwrap.dedent("""\ - query = '''SELECT id - FROM table + query = '''SELECT id + FROM table WHERE day in {}''' days = ",".join(days) """) @@ -2954,6 +2954,39 @@ def b(): uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testForceMultilineDict_True(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{force_multiline_dict: true}')) + unformatted_code = textwrap.dedent( + "responseDict = {'childDict': {'spam': 'eggs'}}\n") + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + actual = reformatter.Reformat(uwlines) + expected = textwrap.dedent("""\ + responseDict = { + 'childDict': { + 'spam': 'eggs' + } + } + """) + self.assertCodeEqual(expected, actual) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + + def testForceMultilineDict_False(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{force_multiline_dict: false}')) + unformatted_code = textwrap.dedent("""\ + responseDict = {'childDict': {'spam': 'eggs'}} + """) + expected_formatted_code = unformatted_code + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateChromiumStyle()) + if __name__ == '__main__': unittest.main() From ae08fbe2e3bdb28efffb7345c806bf8a900afb85 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 23 Apr 2020 10:47:13 -0700 Subject: [PATCH 450/719] Added functionality to insert spaces around dicts, lists, and tuples. (#657) * Added functionality to insert spaces around dicts, lists, and tuples. * Removed hard-coded values * Added missing vertical whitespace * Modified whitespacing around examples * Use "OpensScope()" and "ClosesScope()" Co-authored-by: Bill Wendling <5993918+gwelymernans@users.noreply.github.com> --- CHANGELOG | 18 ++-- README.rst | 39 +++++++ yapf/yapflib/style.py | 79 ++++++++++---- yapf/yapflib/unwrapped_line.py | 49 ++++++++- yapftests/yapf_test.py | 183 +++++++++++++++++++++++++++++++++ 5 files changed, 340 insertions(+), 28 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 236ca8979..dd0265e93 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,17 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.29.1] UNRELEASED +## [0.30.0] UNRELEASED +### Added +- Added `SPACES_AROUND_LIST_DELIMITERS`, `SPACES_AROUND_DICT_DELIMITERS`, + and `SPACES_AROUND_TUPLE_DELIMITERS` to add spaces after the opening- + and before the closing-delimiters for lists, dicts, and tuples. +- Adds `FORCE_MULTILINE_DICT` knob to ensure dictionaries always split, + even when shorter than the max line length. +- New knob `SPACE_INSIDE_BRACKETS` to add spaces inside brackets, braces, and + parentheses. +- New knob `SPACES_AROUND_SUBSCRIPT_COLON` to add spaces around the subscript / + slice operator. ### Fixed - Honor a disable directive at the end of a multiline comment. - Don't require splitting before comments in a list when @@ -11,12 +21,6 @@ - Don't over-indent a parameter list when not needed. But make sure it is properly indented so that it doesn't collide with the lines afterwards. - Don't split between two-word comparison operators: "is not", "not in", etc. -- Adds `FORCE_MULTILINE_DICT` knob to ensure dictionaries always split, - even when shorter than the max line length. -- New knob `SPACE_INSIDE_BRACKETS` to add spaces inside brackets, braces, and - parentheses. -- New knob `SPACES_AROUND_SUBSCRIPT_COLON` to add spaces around the subscript / - slice operator. ## [0.29.0] 2019-11-28 ### Added diff --git a/README.rst b/README.rst index 274e1f81b..cc53c891a 100644 --- a/README.rst +++ b/README.rst @@ -549,6 +549,32 @@ Knobs Set to ``True`` to prefer spaces around the assignment operator for default or keyword arguments. +``SPACES_AROUND_DICT_DELIMITERS`` + Adds a space after the opening '{' and before the ending '}' dict delimiters. + + .. code-block:: python + + {1: 2} + + will be formatted as: + + .. code-block:: python + + { 1: 2 } + +``SPACES_AROUND_LIST_DELIMITERS`` + Adds a space after the opening '[' and before the ending ']' list delimiters. + + .. code-block:: python + + [1, 2] + + will be formatted as: + + .. code-block:: python + + [ 1, 2 ] + ``SPACES_AROUND_SUBSCRIPT_COLON`` Use spaces around the subscript / slice operator. For example: @@ -556,6 +582,19 @@ Knobs my_list[1 : 10 : 2] +``SPACES_AROUND_TUPLE_DELIMITERS`` + Adds a space after the opening '(' and before the ending ')' tuple delimiters. + + .. code-block:: python + + (1, 2, 3) + + will be formatted as: + + .. code-block:: python + + ( 1, 2, 3 ) + ``SPACES_BEFORE_COMMENT`` The number of spaces required before a trailing comment. This can be a single value (representing the number of spaces diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 374794119..b8213cde2 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -31,6 +31,11 @@ def Get(setting_name): return _style[setting_name] +def GetOrDefault(setting_name, default_value): + """Get a style setting or default value if the setting does not exist.""" + return _style.get(setting_name, default_value) + + def Help(): """Return dict mapping style names to help strings.""" return _STYLE_HELP @@ -149,24 +154,8 @@ def method(): transform=Transformation.AVERAGE(window=timedelta(seconds=60)), start_ts=now()-timedelta(days=3), end_ts=now(), - ) # <--- this bracket is dedented and on a separate line"""), - INDENT_CLOSING_BRACKETS=textwrap.dedent("""\ - Put closing brackets on a separate line, indented, if the bracketed - expression can't fit in a single line. Applies to all kinds of brackets, - including function definitions and calls. For example: - - config = { - 'key1': 'value1', - 'key2': 'value2', - } # <--- this bracket is indented and on a separate line - - time_series = self.remote_client.query_entity_counters( - entity='dev3246.region1', - key='dns.query_latency_tcp', - transform=Transformation.AVERAGE(window=timedelta(seconds=60)), - start_ts=now()-timedelta(days=3), - end_ts=now(), - ) # <--- this bracket is indented and on a separate line"""), + ) # <--- this bracket is dedented and on a separate line + """), DISABLE_ENDING_COMMA_HEURISTIC=textwrap.dedent("""\ Disable the heuristic which places each list element on a separate line if the list is comma-terminated."""), @@ -187,6 +176,24 @@ def method(): The i18n function call names. The presence of this function stops reformattting on that line, because the string it has cannot be moved away from the i18n comment."""), + INDENT_CLOSING_BRACKETS=textwrap.dedent("""\ + Put closing brackets on a separate line, indented, if the bracketed + expression can't fit in a single line. Applies to all kinds of brackets, + including function definitions and calls. For example: + + config = { + 'key1': 'value1', + 'key2': 'value2', + } # <--- this bracket is indented and on a separate line + + time_series = self.remote_client.query_entity_counters( + entity='dev3246.region1', + key='dns.query_latency_tcp', + transform=Transformation.AVERAGE(window=timedelta(seconds=60)), + start_ts=now()-timedelta(days=3), + end_ts=now(), + ) # <--- this bracket is indented and on a separate line + """), INDENT_DICTIONARY_VALUE=textwrap.dedent("""\ Indent the dictionary value if it cannot fit on the same line as the dictionary key. For example: @@ -196,7 +203,8 @@ def method(): 'value1', 'key2': value1 + value2, - }"""), + } + """), INDENT_WIDTH=textwrap.dedent("""\ The number of columns to use for indentation."""), INDENT_BLANK_LINES=textwrap.dedent("""\ @@ -226,10 +234,37 @@ def method(): Use spaces around the power operator."""), SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=textwrap.dedent("""\ Use spaces around default or named assigns."""), + SPACES_AROUND_DICT_DELIMITERS=textwrap.dedent("""\ + Adds a space after the opening '{' and before the ending '}' dict delimiters. + + {1: 2} + + will be formatted as: + + { 1: 2 } + """), + SPACES_AROUND_LIST_DELIMITERS=textwrap.dedent("""\ + Adds a space after the opening '[' and before the ending ']' list delimiters. + + [1, 2] + + will be formatted as: + + [ 1, 2 ] + """), SPACES_AROUND_SUBSCRIPT_COLON=textwrap.dedent("""\ Use spaces around the subscript / slice operator. For example: my_list[1 : 10 : 2] + """) + SPACES_AROUND_TUPLE_DELIMITERS=textwrap.dedent("""\ + Adds a space after the opening '(' and before the ending ')' tuple delimiters. + + (1, 2, 3) + + will be formatted as: + + ( 1, 2, 3 ) """), SPACES_BEFORE_COMMENT=textwrap.dedent("""\ The number of spaces required before a trailing comment. @@ -407,7 +442,10 @@ def CreatePEP8Style(): SPACE_INSIDE_BRACKETS=False, SPACES_AROUND_POWER_OPERATOR=False, SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=False, + SPACES_AROUND_DICT_DELIMITERS=False, + SPACES_AROUND_LIST_DELIMITERS=False, SPACES_AROUND_SUBSCRIPT_COLON=False, + SPACES_AROUND_TUPLE_DELIMITERS=False, SPACES_BEFORE_COMMENT=2, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False, SPLIT_ALL_COMMA_SEPARATED_VALUES=False, @@ -592,7 +630,10 @@ def _IntOrIntListConverter(s): SPACE_INSIDE_BRACKETS=_BoolConverter, SPACES_AROUND_POWER_OPERATOR=_BoolConverter, SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=_BoolConverter, + SPACES_AROUND_DICT_DELIMITERS=_BoolConverter, + SPACES_AROUND_LIST_DELIMITERS=_BoolConverter, SPACES_AROUND_SUBSCRIPT_COLON=_BoolConverter, + SPACES_AROUND_TUPLE_DELIMITERS=_BoolConverter, SPACES_BEFORE_COMMENT=_IntOrIntListConverter, SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter, SPLIT_ALL_COMMA_SEPARATED_VALUES=_BoolConverter, diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index ec28f9b2d..38501c0d0 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -25,6 +25,8 @@ from yapf.yapflib import split_penalty from yapf.yapflib import style +from lib2to3.fixer_util import syms as python_symbols + class UnwrappedLine(object): """Represents a single unwrapped line in the output. @@ -69,7 +71,7 @@ def CalculateFormattingInformation(self): prev_length = self.first.total_length for token in self._tokens[1:]: if (token.spaces_required_before == 0 and - _SpaceRequiredBetween(prev_token, token)): + _SpaceRequiredBetween(prev_token, token, self.disable)): token.spaces_required_before = 1 tok_len = len(token.value) if not token.is_pseudo_paren else 0 @@ -265,7 +267,7 @@ def _IsSubscriptColonAndValuePair(token1, token2): return (token1.is_number or token1.is_name) and token2.is_subscript_colon -def _SpaceRequiredBetween(left, right): +def _SpaceRequiredBetween(left, right, is_line_disabled): """Return True if a space is required between the left and right token.""" lval = left.value rval = right.value @@ -411,6 +413,22 @@ def _SpaceRequiredBetween(left, right): (lval == '{' and rval == '}')): # Empty objects shouldn't be separated by spaces. return False + if not is_line_disabled and (left.OpensScope() or right.ClosesScope()): + if (style.GetOrDefault('SPACES_AROUND_DICT_DELIMITERS', False) and ( + (lval == '{' and _IsDictListTupleDelimiterTok(left, is_opening=True)) or + (rval == '}' and + _IsDictListTupleDelimiterTok(right, is_opening=False)))): + return True + if (style.GetOrDefault('SPACES_AROUND_LIST_DELIMITERS', False) and ( + (lval == '[' and _IsDictListTupleDelimiterTok(left, is_opening=True)) or + (rval == ']' and + _IsDictListTupleDelimiterTok(right, is_opening=False)))): + return True + if (style.GetOrDefault('SPACES_AROUND_TUPLE_DELIMITERS', False) and ( + (lval == '(' and _IsDictListTupleDelimiterTok(left, is_opening=True)) or + (rval == ')' and + _IsDictListTupleDelimiterTok(right, is_opening=False)))): + return True if (lval in pytree_utils.OPENING_BRACKETS and rval in pytree_utils.OPENING_BRACKETS): # Nested objects' opening brackets shouldn't be separated, unless enabled @@ -549,6 +567,33 @@ def IsSurroundedByBrackets(tok): return None +def _IsDictListTupleDelimiterTok(tok, is_opening): + assert tok + + if tok.matching_bracket is None: + return False + + if is_opening: + open_tok = tok + close_tok = tok.matching_bracket + else: + open_tok = tok.matching_bracket + close_tok = tok + + # There must be something in between the tokens + if open_tok.next_token == close_tok: + return False + + assert open_tok.next_token.node + assert open_tok.next_token.node.parent + + return open_tok.next_token.node.parent.type in [ + python_symbols.dictsetmaker, + python_symbols.listmaker, + python_symbols.testlist_gexp, + ] + + _LOGICAL_OPERATORS = frozenset({'and', 'or'}) _BITWISE_OPERATORS = frozenset({'&', '|', '^'}) _ARITHMETIC_OPERATORS = frozenset({'+', '-', '*', '/', '%', '//', '@'}) diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 25e4f9bd2..46fde99d2 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1778,5 +1778,188 @@ def testDisabledLine(self): self._Check(unformatted_code, expected_formatted_code) +class _SpacesAroundDictListTupleTestImpl(unittest.TestCase): + + @staticmethod + def _OwnStyle(): + my_style = style.CreatePEP8Style() + my_style['DISABLE_ENDING_COMMA_HEURISTIC'] = True + my_style['SPLIT_ALL_COMMA_SEPARATED_VALUES'] = False + my_style['SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED'] = False + return my_style + + def _Check(self, unformatted_code, expected_formatted_code): + formatted_code, _ = yapf_api.FormatCode( + unformatted_code, style_config=style.SetGlobalStyle(self._OwnStyle())) + self.assertEqual(expected_formatted_code, formatted_code) + + def setUp(self): + self.maxDiff = None + + +class SpacesAroundDictTest(_SpacesAroundDictListTupleTestImpl): + + @classmethod + def _OwnStyle(cls): + style = super(SpacesAroundDictTest, cls)._OwnStyle() + style['SPACES_AROUND_DICT_DELIMITERS'] = True + + return style + + def testStandard(self): + unformatted_code = textwrap.dedent("""\ + {1 : 2} + {k:v for k, v in other.items()} + {k for k in [1, 2, 3]} + + # The following statements should not change + {} + {1 : 2} # yapf: disable + + # yapf: disable + {1 : 2} + # yapf: enable + + # Dict settings should not impact lists or tuples + [1, 2] + (3, 4) + """) + expected_formatted_code = textwrap.dedent("""\ + { 1: 2 } + { k: v for k, v in other.items() } + { k for k in [1, 2, 3] } + + # The following statements should not change + {} + {1 : 2} # yapf: disable + + # yapf: disable + {1 : 2} + # yapf: enable + + # Dict settings should not impact lists or tuples + [1, 2] + (3, 4) + """) + + self._Check(unformatted_code, expected_formatted_code) + + +class SpacesAroundListTest(_SpacesAroundDictListTupleTestImpl): + + @classmethod + def _OwnStyle(cls): + style = super(SpacesAroundListTest, cls)._OwnStyle() + style['SPACES_AROUND_LIST_DELIMITERS'] = True + + return style + + def testStandard(self): + unformatted_code = textwrap.dedent("""\ + [a,b,c] + [4,5,] + [6, [7, 8], 9] + [v for v in [1,2,3] if v & 1] + + # The following statements should not change + index[0] + index[a, b] + [] + [v for v in [1,2,3] if v & 1] # yapf: disable + + # yapf: disable + [a,b,c] + [4,5,] + # yapf: enable + + # List settings should not impact dicts or tuples + {a: b} + (1, 2) + """) + expected_formatted_code = textwrap.dedent("""\ + [ a, b, c ] + [ 4, 5, ] + [ 6, [ 7, 8 ], 9 ] + [ v for v in [ 1, 2, 3 ] if v & 1 ] + + # The following statements should not change + index[0] + index[a, b] + [] + [v for v in [1,2,3] if v & 1] # yapf: disable + + # yapf: disable + [a,b,c] + [4,5,] + # yapf: enable + + # List settings should not impact dicts or tuples + {a: b} + (1, 2) + """) + + self._Check(unformatted_code, expected_formatted_code) + + +class SpacesAroundTupleTest(_SpacesAroundDictListTupleTestImpl): + + @classmethod + def _OwnStyle(cls): + style = super(SpacesAroundTupleTest, cls)._OwnStyle() + style['SPACES_AROUND_TUPLE_DELIMITERS'] = True + + return style + + def testStandard(self): + unformatted_code = textwrap.dedent("""\ + (0, 1) + (2, 3) + (4, 5, 6,) + func((7, 8), 9) + + # The following statements should not change + func(1, 2) + (this_func or that_func)(3, 4) + if (True and False): pass + () + + (0, 1) # yapf: disable + + # yapf: disable + (0, 1) + (2, 3) + # yapf: enable + + # Tuple settings should not impact dicts or lists + {a: b} + [3, 4] + """) + expected_formatted_code = textwrap.dedent("""\ + ( 0, 1 ) + ( 2, 3 ) + ( 4, 5, 6, ) + func(( 7, 8 ), 9) + + # The following statements should not change + func(1, 2) + (this_func or that_func)(3, 4) + if (True and False): pass + () + + (0, 1) # yapf: disable + + # yapf: disable + (0, 1) + (2, 3) + # yapf: enable + + # Tuple settings should not impact dicts or lists + {a: b} + [3, 4] + """) + + self._Check(unformatted_code, expected_formatted_code) + + if __name__ == '__main__': unittest.main() From 2ae75c4fb3502e432d4410f0e8b4e0b43808ee10 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 5 Feb 2020 19:23:29 -0800 Subject: [PATCH 451/719] Move argument parsing into its own function. --- yapf/__init__.py | 174 +++++++++++++++++++++++++---------------------- 1 file changed, 93 insertions(+), 81 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 41b2a5dda..f7d53d7b4 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -57,87 +57,7 @@ def main(argv): Raises: YapfError: if none of the supplied files were Python files. """ - parser = argparse.ArgumentParser(description='Formatter for Python code.') - parser.add_argument( - '-v', - '--version', - action='store_true', - help='show version number and exit') - - diff_inplace_quiet_group = parser.add_mutually_exclusive_group() - diff_inplace_quiet_group.add_argument( - '-d', - '--diff', - action='store_true', - help='print the diff for the fixed source') - diff_inplace_quiet_group.add_argument( - '-i', - '--in-place', - action='store_true', - help='make changes to files in place') - diff_inplace_quiet_group.add_argument( - '-q', - '--quiet', - action='store_true', - help='output nothing and set return value') - - lines_recursive_group = parser.add_mutually_exclusive_group() - lines_recursive_group.add_argument( - '-r', - '--recursive', - action='store_true', - help='run recursively over directories') - lines_recursive_group.add_argument( - '-l', - '--lines', - metavar='START-END', - action='append', - default=None, - help='range of lines to reformat, one-based') - - parser.add_argument( - '-e', - '--exclude', - metavar='PATTERN', - action='append', - default=None, - help='patterns for files to exclude from formatting') - parser.add_argument( - '--style', - action='store', - help=('specify formatting style: either a style name (for example "pep8" ' - 'or "google"), or the name of a file with style settings. The ' - 'default is pep8 unless a %s or %s file located in the same ' - 'directory as the source or one of its parent directories ' - '(for stdin, the current directory is used).' % - (style.LOCAL_STYLE, style.SETUP_CONFIG))) - parser.add_argument( - '--style-help', - action='store_true', - help=('show style settings and exit; this output can be ' - 'saved to .style.yapf to make your settings ' - 'permanent')) - parser.add_argument( - '--no-local-style', - action='store_true', - help="don't search for local style definition") - parser.add_argument('--verify', action='store_true', help=argparse.SUPPRESS) - parser.add_argument( - '-p', - '--parallel', - action='store_true', - help=('run yapf in parallel when formatting multiple files. Requires ' - 'concurrent.futures in Python 2.X')) - parser.add_argument( - '-vv', - '--verbose', - action='store_true', - help='print out file names while processing') - - parser.add_argument( - 'files', nargs='*', help='reads from stdin when no files are specified.') - args = parser.parse_args(argv[1:]) - + args = _ParseArguments(argv) if args.version: print('yapf {}'.format(__version__)) return 0 @@ -348,6 +268,98 @@ def _GetLines(line_strings): return lines +def _ParseArguments(argv): + """Parse the command line arguments. + + Arguments: + argv: command-line arguments, such as sys.argv (including the program name + in argv[0]). + + Returns: + An object containing the arguments used to invoke the program. + """ + parser = argparse.ArgumentParser(description='Formatter for Python code.') + parser.add_argument( + '-v', + '--version', + action='store_true', + help='show version number and exit') + + diff_inplace_quiet_group = parser.add_mutually_exclusive_group() + diff_inplace_quiet_group.add_argument( + '-d', + '--diff', + action='store_true', + help='print the diff for the fixed source') + diff_inplace_quiet_group.add_argument( + '-i', + '--in-place', + action='store_true', + help='make changes to files in place') + diff_inplace_quiet_group.add_argument( + '-q', + '--quiet', + action='store_true', + help='output nothing and set return value') + + lines_recursive_group = parser.add_mutually_exclusive_group() + lines_recursive_group.add_argument( + '-r', + '--recursive', + action='store_true', + help='run recursively over directories') + lines_recursive_group.add_argument( + '-l', + '--lines', + metavar='START-END', + action='append', + default=None, + help='range of lines to reformat, one-based') + + parser.add_argument( + '-e', + '--exclude', + metavar='PATTERN', + action='append', + default=None, + help='patterns for files to exclude from formatting') + parser.add_argument( + '--style', + action='store', + help=('specify formatting style: either a style name (for example "pep8" ' + 'or "google"), or the name of a file with style settings. The ' + 'default is pep8 unless a %s or %s file located in the same ' + 'directory as the source or one of its parent directories ' + '(for stdin, the current directory is used).' % + (style.LOCAL_STYLE, style.SETUP_CONFIG))) + parser.add_argument( + '--style-help', + action='store_true', + help=('show style settings and exit; this output can be ' + 'saved to .style.yapf to make your settings ' + 'permanent')) + parser.add_argument( + '--no-local-style', + action='store_true', + help="don't search for local style definition") + parser.add_argument('--verify', action='store_true', help=argparse.SUPPRESS) + parser.add_argument( + '-p', + '--parallel', + action='store_true', + help=('run yapf in parallel when formatting multiple files. Requires ' + 'concurrent.futures in Python 2.X')) + parser.add_argument( + '-vv', + '--verbose', + action='store_true', + help='print out file names while processing') + + parser.add_argument( + 'files', nargs='*', help='reads from stdin when no files are specified.') + return parser.parse_args(argv[1:]) + + def run_main(): # pylint: disable=invalid-name try: sys.exit(main(sys.argv)) From 244680e170af4f02a8cf70b76dd820bc20177b6b Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 5 Feb 2020 19:37:48 -0800 Subject: [PATCH 452/719] Inline functions used only once. Also move class methods out if they don't require to be in the class. --- yapf/yapflib/blank_line_calculator.py | 23 ++++++++++++----------- yapf/yapflib/split_penalty.py | 27 +++++++-------------------- yapf/yapflib/style.py | 2 +- 3 files changed, 20 insertions(+), 32 deletions(-) diff --git a/yapf/yapflib/blank_line_calculator.py b/yapf/yapflib/blank_line_calculator.py index 50d834fcc..374134853 100644 --- a/yapf/yapflib/blank_line_calculator.py +++ b/yapf/yapflib/blank_line_calculator.py @@ -70,9 +70,9 @@ def Visit_simple_stmt(self, node): # pylint: disable=invalid-name def Visit_decorator(self, node): # pylint: disable=invalid-name if (self.last_comment_lineno and self.last_comment_lineno == node.children[0].lineno - 1): - self._SetNumNewlines(node.children[0], _NO_BLANK_LINES) + _SetNumNewlines(node.children[0], _NO_BLANK_LINES) else: - self._SetNumNewlines(node.children[0], self._GetNumNewlines(node)) + _SetNumNewlines(node.children[0], self._GetNumNewlines(node)) for child in node.children: self.Visit(child) self.last_was_decorator = True @@ -93,7 +93,7 @@ def Visit_funcdef(self, node): # pylint: disable=invalid-name if _AsyncFunction(node): index = self._SetBlankLinesBetweenCommentAndClassFunc( node.prev_sibling.parent) - self._SetNumNewlines(node.children[0], None) + _SetNumNewlines(node.children[0], None) else: index = self._SetBlankLinesBetweenCommentAndClassFunc(node) self.last_was_decorator = False @@ -115,7 +115,7 @@ def DefaultNodeVisit(self, node): if self.last_was_class_or_function: if pytree_utils.NodeName(node) in _PYTHON_STATEMENTS: leaf = pytree_utils.FirstLeafNode(node) - self._SetNumNewlines(leaf, self._GetNumNewlines(leaf)) + _SetNumNewlines(leaf, self._GetNumNewlines(leaf)) self.last_was_class_or_function = False super(_BlankLineCalculator, self).DefaultNodeVisit(node) @@ -137,17 +137,17 @@ def _SetBlankLinesBetweenCommentAndClassFunc(self, node): # node as its only child. self.Visit(node.children[index].children[0]) if not self.last_was_decorator: - self._SetNumNewlines(node.children[index].children[0], _ONE_BLANK_LINE) + _SetNumNewlines(node.children[index].children[0], _ONE_BLANK_LINE) index += 1 if (index and node.children[index].lineno - 1 == node.children[index - 1].children[0].lineno): - self._SetNumNewlines(node.children[index], _NO_BLANK_LINES) + _SetNumNewlines(node.children[index], _NO_BLANK_LINES) else: if self.last_comment_lineno + 1 == node.children[index].lineno: num_newlines = _NO_BLANK_LINES else: num_newlines = self._GetNumNewlines(node) - self._SetNumNewlines(node.children[index], num_newlines) + _SetNumNewlines(node.children[index], num_newlines) return index def _GetNumNewlines(self, node): @@ -157,15 +157,16 @@ def _GetNumNewlines(self, node): return 1 + style.Get('BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION') return _ONE_BLANK_LINE - def _SetNumNewlines(self, node, num_newlines): - pytree_utils.SetNodeAnnotation(node, pytree_utils.Annotation.NEWLINES, - num_newlines) - def _IsTopLevel(self, node): return (not (self.class_level or self.function_level) and _StartsInZerothColumn(node)) +def _SetNumNewlines(node, num_newlines): + pytree_utils.SetNodeAnnotation(node, pytree_utils.Annotation.NEWLINES, + num_newlines) + + def _StartsInZerothColumn(node): return (pytree_utils.FirstLeafNode(node).column == 0 or (_AsyncFunction(node) and node.prev_sibling.column == 0)) diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 819dbda0f..d4c3dc475 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -188,7 +188,11 @@ def Visit_tname(self, node): # pylint: disable=invalid-name def Visit_dotted_name(self, node): # pylint: disable=invalid-name # dotted_name ::= NAME ('.' NAME)* - self._SetUnbreakableOnChildren(node) + for child in node.children: + self.Visit(child) + start = 2 if hasattr(node.children[0], 'is_pseudo') else 1 + for i in py3compat.range(start, len(node.children)): + _SetUnbreakable(node.children[i]) def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name # dictsetmaker ::= ( (test ':' test @@ -244,7 +248,8 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name pytree_utils.FirstLeafNode(node.children[1].children[2]), 0) # Don't split the ending bracket of a subscript list. - _SetVeryStronglyConnected(node.children[-1]) + _RecAnnotate(node.children[-1], pytree_utils.Annotation.SPLIT_PENALTY, + VERY_STRONGLY_CONNECTED) elif name not in { 'arglist', 'argument', 'term', 'or_test', 'and_test', 'comparison', 'atom', 'power' @@ -499,17 +504,6 @@ def Visit_testlist_gexp(self, node): # pylint: disable=invalid-name _SetSplitPenalty(pytree_utils.FirstLeafNode(child), TOGETHER) prev_was_comma = False - ############################################################################ - # Helper methods that set the annotations. - - def _SetUnbreakableOnChildren(self, node): - """Set an UNBREAKABLE penalty annotation on children of node.""" - for child in node.children: - self.Visit(child) - start = 2 if hasattr(node.children[0], 'is_pseudo') else 1 - for i in py3compat.range(start, len(node.children)): - _SetUnbreakable(node.children[i]) - def _SetUnbreakable(node): """Set an UNBREAKABLE penalty annotation for the given node.""" @@ -523,13 +517,6 @@ def _SetStronglyConnected(*nodes): STRONGLY_CONNECTED) -def _SetVeryStronglyConnected(*nodes): - """Set a VERY_STRONGLY_CONNECTED penalty annotation for the given nodes.""" - for node in nodes: - _RecAnnotate(node, pytree_utils.Annotation.SPLIT_PENALTY, - VERY_STRONGLY_CONNECTED) - - def _SetExpressionPenalty(node, penalty): """Set a penalty annotation on children nodes.""" diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index b8213cde2..1cc49ad13 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -256,7 +256,7 @@ def method(): Use spaces around the subscript / slice operator. For example: my_list[1 : 10 : 2] - """) + """), SPACES_AROUND_TUPLE_DELIMITERS=textwrap.dedent("""\ Adds a space after the opening '(' and before the ending ')' tuple delimiters. From fa7a293e310a435fd4dd1844fc433f86e28aac61 Mon Sep 17 00:00:00 2001 From: agrieve Date: Thu, 23 Apr 2020 14:23:20 -0400 Subject: [PATCH 453/719] Update chromium style to match what's used in Chromium (#789) * Rename "chromium" style to "yapf". Chromium has decided to just follow PEP-8 Relevant Chromium style discussion: https://groups.google.com/a/chromium.org/g/chromium-dev/c/RcJgJdkNIdg/discussion * Added "yapf" to the style list. Co-authored-by: Andrew Grieve Co-authored-by: Bill Wendling Co-authored-by: Bill Wendling <5993918+gwelymernans@users.noreply.github.com> --- .style.yapf | 3 +- CHANGELOG | 2 + CONTRIBUTING.rst | 5 +- README.rst | 8 +- yapf/yapflib/style.py | 9 +- yapftests/blank_line_calculator_test.py | 2 +- yapftests/format_decision_state_test.py | 2 +- yapftests/main_test.py | 6 +- yapftests/reformatter_basic_test.py | 124 ++++++++++++++------- yapftests/reformatter_buganizer_test.py | 8 +- yapftests/reformatter_style_config_test.py | 2 +- yapftests/split_penalty_test.py | 2 +- yapftests/style_test.py | 50 +++------ yapftests/yapf_test.py | 44 ++++---- 14 files changed, 147 insertions(+), 120 deletions(-) diff --git a/.style.yapf b/.style.yapf index 823a973ea..fdd07237c 100644 --- a/.style.yapf +++ b/.style.yapf @@ -1,3 +1,2 @@ [style] -# YAPF uses the chromium style -based_on_style = chromium +based_on_style = yapf diff --git a/CHANGELOG b/CHANGELOG index dd0265e93..06192982a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,8 @@ parentheses. - New knob `SPACES_AROUND_SUBSCRIPT_COLON` to add spaces around the subscript / slice operator. +### Changed +- Renamed "chromium" style to "yapf". Chromium will now use PEP-8 directly. ### Fixed - Honor a disable directive at the end of a multiline comment. - Don't require splitting before comments in a list when diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index d68dedb77..fa6cda064 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -27,9 +27,8 @@ use Github pull requests for this purpose. YAPF coding style ----------------- -YAPF follows the `Chromium Python Style Guide -`_. It's the same -as the Google Python Style guide with two exceptions: +YAPF follows the `Google Python Style Guide +`_ with two exceptions: - 2 spaces for indentation rather than 4. - CamelCase for function and method names rather than snake_case. diff --git a/README.rst b/README.rst index cc53c891a..316d8a0c6 100644 --- a/README.rst +++ b/README.rst @@ -178,8 +178,8 @@ with a ``[yapf]`` heading. For example: The ``based_on_style`` setting determines which of the predefined styles this custom style is based on (think of it like subclassing). Four -styles are predefined: ``pep8`` (default), ``chromium``, ``google`` and -``facebook`` (see ``_STYLE_NAME_TO_FACTORY`` in style.py_). +styles are predefined: ``pep8`` (default), ``google``, ``yapf``, and ``facebook`` +(see ``_STYLE_NAME_TO_FACTORY`` in style.py_). .. _style.py: https://github.com/google/yapf/blob/master/yapf/yapflib/style.py#L445 @@ -188,9 +188,9 @@ example: .. code-block:: shell - --style='{based_on_style: chromium, indent_width: 4}' + --style='{based_on_style: pep8, indent_width: 2}' -This will take the ``chromium`` base style and modify it to have four space +This will take the ``pep8`` base style and modify it to have two space indentations. YAPF will search for the formatting style in the following manner: diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 1cc49ad13..4e0836549 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -494,12 +494,11 @@ def CreateGoogleStyle(): return style -def CreateChromiumStyle(): - """Create the Chromium formatting style.""" +def CreateYapfStyle(): + """Create the YAPF formatting style.""" style = CreateGoogleStyle() style['ALLOW_MULTILINE_DICTIONARY_KEYS'] = True style['ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS'] = False - style['INDENT_DICTIONARY_VALUE'] = True style['INDENT_WIDTH'] = 2 style['SPLIT_BEFORE_BITWISE_OPERATOR'] = True style['SPLIT_BEFORE_DOT'] = True @@ -527,16 +526,16 @@ def CreateFacebookStyle(): _STYLE_NAME_TO_FACTORY = dict( pep8=CreatePEP8Style, - chromium=CreateChromiumStyle, google=CreateGoogleStyle, facebook=CreateFacebookStyle, + yapf=CreateYapfStyle, ) _DEFAULT_STYLE_TO_FACTORY = [ - (CreateChromiumStyle(), CreateChromiumStyle), (CreateFacebookStyle(), CreateFacebookStyle), (CreateGoogleStyle(), CreateGoogleStyle), (CreatePEP8Style(), CreatePEP8Style), + (CreateYapfStyle(), CreateYapfStyle), ] diff --git a/yapftests/blank_line_calculator_test.py b/yapftests/blank_line_calculator_test.py index 8738c73df..1ec0a5e59 100644 --- a/yapftests/blank_line_calculator_test.py +++ b/yapftests/blank_line_calculator_test.py @@ -27,7 +27,7 @@ class BasicBlankLineCalculatorTest(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testDecorators(self): unformatted_code = textwrap.dedent("""\ diff --git a/yapftests/format_decision_state_test.py b/yapftests/format_decision_state_test.py index 612296008..39e7e8e03 100644 --- a/yapftests/format_decision_state_test.py +++ b/yapftests/format_decision_state_test.py @@ -28,7 +28,7 @@ class FormatDecisionStateTest(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testSimpleFunctionDefWithNoSplitting(self): code = textwrap.dedent(r""" diff --git a/yapftests/main_test.py b/yapftests/main_test.py index 138853ceb..94daaaa94 100644 --- a/yapftests/main_test.py +++ b/yapftests/main_test.py @@ -113,12 +113,12 @@ def testEchoInput(self): def testEchoInputWithStyle(self): code = 'def f(a = 1):\n return 2*a\n' - chromium_code = 'def f(a=1):\n return 2 * a\n' + yapf_code = 'def f(a=1):\n return 2 * a\n' with patched_input(code): with captured_output() as (out, _): - ret = yapf.main(['-', '--style=chromium']) + ret = yapf.main(['-', '--style=yapf']) self.assertEqual(ret, 0) - self.assertEqual(out.getvalue(), chromium_code) + self.assertEqual(out.getvalue(), yapf_code) def testEchoBadInput(self): bad_syntax = ' a = 1\n' diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 7868d0b06..62d6e089b 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -26,8 +26,8 @@ class BasicReformatterTest(yapf_test_helper.YAPFTest): @classmethod - def setUpClass(cls): # pylint: disable=g-missing-super-call - style.SetGlobalStyle(style.CreateChromiumStyle()) + def setUpClass(cls): + style.SetGlobalStyle(style.CreateYapfStyle()) def testSplittingAllArgs(self): style.SetGlobalStyle( @@ -306,13 +306,13 @@ class foo(object):\n \n def foobar(self):\n \n pass\n \n def barfoo(se try: style.SetGlobalStyle( style.CreateStyleFromConfig( - '{based_on_style: chromium, indent_blank_lines: true}')) + '{based_on_style: yapf, indent_blank_lines: true}')) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) unformatted_code, expected_formatted_code = (expected_formatted_code, unformatted_code) @@ -1850,12 +1850,12 @@ def succeeded(self, dddddddddddddd): try: style.SetGlobalStyle( style.CreateStyleFromConfig( - '{based_on_style: chromium, allow_multiline_lambdas: true}')) + '{based_on_style: yapf, allow_multiline_lambdas: true}')) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testMultilineDictionaryKeys(self): unformatted_code = textwrap.dedent("""\ @@ -1882,13 +1882,13 @@ def testMultilineDictionaryKeys(self): try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: chromium, ' + style.CreateStyleFromConfig('{based_on_style: yapf, ' 'allow_multiline_dictionary_keys: true}')) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testStableDictionaryFormatting(self): code = textwrap.dedent("""\ @@ -1919,7 +1919,34 @@ def method(self): reformatted_code = reformatter.Reformat(uwlines) self.assertCodeEqual(code, reformatted_code) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) + + def testStableInlinedDictionaryFormatting(self): + try: + style.SetGlobalStyle(style.CreatePEP8Style()) + unformatted_code = textwrap.dedent("""\ + def _(): + url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( + value, urllib.urlencode({'action': 'update', 'parameter': value})) + """) + expected_formatted_code = textwrap.dedent("""\ + def _(): + url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( + value, urllib.urlencode({ + 'action': 'update', + 'parameter': value + })) + """) + + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + reformatted_code = reformatter.Reformat(uwlines) + self.assertCodeEqual(expected_formatted_code, reformatted_code) + + uwlines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + reformatted_code = reformatter.Reformat(uwlines) + self.assertCodeEqual(expected_formatted_code, reformatted_code) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) def testDontSplitKeywordValueArguments(self): unformatted_code = textwrap.dedent("""\ @@ -1990,7 +2017,7 @@ def testNoSplittingWhenBinPacking(self): reformatted_code = reformatter.Reformat(uwlines) self.assertCodeEqual(code, reformatted_code) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testNotSplittingAfterSubscript(self): unformatted_code = textwrap.dedent("""\ @@ -2102,7 +2129,7 @@ def testSplittingArgumentsTerminatedByComma(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig( - '{based_on_style: chromium, ' + '{based_on_style: yapf, ' 'split_arguments_when_comma_terminated: True}')) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) @@ -2113,7 +2140,7 @@ def testSplittingArgumentsTerminatedByComma(self): reformatted_code = reformatter.Reformat(uwlines) self.assertCodeEqual(expected_formatted_code, reformatted_code) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testImportAsList(self): code = textwrap.dedent("""\ @@ -2402,14 +2429,14 @@ def __init__(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig( - '{based_on_style: chromium, ' + '{based_on_style: yapf, ' 'blank_line_before_class_docstring: True}')) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testBlankLineBeforeModuleDocstring(self): unformatted_code = textwrap.dedent('''\ @@ -2464,7 +2491,7 @@ def foobar(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testTupleCohesion(self): unformatted_code = textwrap.dedent("""\ @@ -2559,13 +2586,13 @@ def testSplittingBeforeFirstArgumentOnFunctionCall(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig( - '{based_on_style: chromium, split_before_first_argument: True}')) + '{based_on_style: yapf, split_before_first_argument: True}')) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testSplittingBeforeFirstArgumentOnFunctionDefinition(self): """Tests split_before_first_argument on a function definition.""" @@ -2583,13 +2610,13 @@ def _GetNumberOfSecondsFromElements( try: style.SetGlobalStyle( style.CreateStyleFromConfig( - '{based_on_style: chromium, split_before_first_argument: True}')) + '{based_on_style: yapf, split_before_first_argument: True}')) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testSplittingBeforeFirstArgumentOnCompoundStatement(self): """Tests split_before_first_argument on a compound statement.""" @@ -2609,13 +2636,13 @@ def testSplittingBeforeFirstArgumentOnCompoundStatement(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig( - '{based_on_style: chromium, split_before_first_argument: True}')) + '{based_on_style: yapf, split_before_first_argument: True}')) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testCoalesceBracketsOnDict(self): """Tests coalesce_brackets on a dictionary.""" @@ -2645,13 +2672,13 @@ def testCoalesceBracketsOnDict(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig( - '{based_on_style: chromium, coalesce_brackets: True}')) + '{based_on_style: yapf, coalesce_brackets: True}')) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testSplitAfterComment(self): code = textwrap.dedent("""\ @@ -2666,13 +2693,32 @@ def testSplitAfterComment(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig( - '{based_on_style: chromium, coalesce_brackets: True, ' + '{based_on_style: yapf, coalesce_brackets: True, ' 'dedent_closing_brackets: true}')) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) + + @unittest.skipUnless(not py3compat.PY3, 'Requires Python 2.7') + def testAsyncAsNonKeyword(self): + try: + style.SetGlobalStyle(style.CreatePEP8Style()) + + # In Python 2, async may be used as a non-keyword identifier. + code = textwrap.dedent("""\ + from util import async + + + class A(object): + def foo(self): + async.run() + """) uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testDisableEndingCommaHeuristic(self): code = textwrap.dedent("""\ @@ -2681,13 +2727,13 @@ def testDisableEndingCommaHeuristic(self): try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: chromium,' + style.CreateStyleFromConfig('{based_on_style: yapf,' ' disable_ending_comma_heuristic: True}')) uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testDedentClosingBracketsWithTypeAnnotationExceedingLineLength(self): unformatted_code = textwrap.dedent("""\ @@ -2713,14 +2759,14 @@ def function( try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: chromium,' + style.CreateStyleFromConfig('{based_on_style: yapf,' ' dedent_closing_brackets: True}')) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testIndentClosingBracketsWithTypeAnnotationExceedingLineLength(self): unformatted_code = textwrap.dedent("""\ @@ -2746,14 +2792,14 @@ def function( try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: chromium,' + style.CreateStyleFromConfig('{based_on_style: yapf,' ' indent_closing_brackets: True}')) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testIndentClosingBracketsInFunctionCall(self): unformatted_code = textwrap.dedent("""\ @@ -2781,14 +2827,14 @@ def function( try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: chromium,' + style.CreateStyleFromConfig('{based_on_style: yapf,' ' indent_closing_brackets: True}')) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testIndentClosingBracketsInTuple(self): unformatted_code = textwrap.dedent("""\ @@ -2816,14 +2862,14 @@ def function(): try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: chromium,' + style.CreateStyleFromConfig('{based_on_style: yapf,' ' indent_closing_brackets: True}')) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testIndentClosingBracketsInList(self): unformatted_code = textwrap.dedent("""\ @@ -2851,14 +2897,14 @@ def function(): try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: chromium,' + style.CreateStyleFromConfig('{based_on_style: yapf,' ' indent_closing_brackets: True}')) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testIndentClosingBracketsInDict(self): unformatted_code = textwrap.dedent("""\ @@ -2892,14 +2938,14 @@ def function(): try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: chromium,' + style.CreateStyleFromConfig('{based_on_style: yapf,' ' indent_closing_brackets: True}')) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testMultipleDictionariesInList(self): unformatted_code = textwrap.dedent("""\ diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index b09445513..653e88557 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -26,7 +26,7 @@ class BuganizerFixes(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testB137580392(self): code = """\ @@ -1720,13 +1720,13 @@ def __eq__(self, other): try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: chromium, ' + style.CreateStyleFromConfig('{based_on_style: yapf, ' 'split_before_logical_operator: True}')) uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testB22527411(self): unformatted_code = textwrap.dedent("""\ @@ -1884,7 +1884,7 @@ def f(): uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testB19353268(self): code = textwrap.dedent("""\ diff --git a/yapftests/reformatter_style_config_test.py b/yapftests/reformatter_style_config_test.py index 5fe9709c1..d77c19700 100644 --- a/yapftests/reformatter_style_config_test.py +++ b/yapftests/reformatter_style_config_test.py @@ -29,7 +29,7 @@ def setUp(self): def testSetGlobalStyle(self): try: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) unformatted_code = textwrap.dedent(u"""\ for i in range(5): print('bar') diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index 895445cfc..4d551291e 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -36,7 +36,7 @@ class SplitPenaltyTest(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def _ParseAndComputePenalties(self, code, dumptree=False): """Parses the code and computes split penalties. diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 3d4e1b141..a9c478daa 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -74,23 +74,20 @@ def testIntOrIntListConverter(self): self.assertEqual(style._IntOrIntListConverter('1, 2, 3'), [1, 2, 3]) -def _LooksLikeChromiumStyle(cfg): - return (cfg['INDENT_WIDTH'] == 2 and - cfg['BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF']) - - def _LooksLikeGoogleStyle(cfg): - return (cfg['INDENT_WIDTH'] == 4 and - cfg['BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF']) + return cfg['COLUMN_LIMIT'] == 80 and cfg['SPLIT_COMPLEX_COMPREHENSION'] def _LooksLikePEP8Style(cfg): - return (cfg['INDENT_WIDTH'] == 4 and - not cfg['BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF']) + return cfg['COLUMN_LIMIT'] == 79 def _LooksLikeFacebookStyle(cfg): - return cfg['INDENT_WIDTH'] == 4 and cfg['DEDENT_CLOSING_BRACKETS'] + return cfg['DEDENT_CLOSING_BRACKETS'] + + +def _LooksLikeYapfStyle(cfg): + return cfg['SPLIT_BEFORE_DOT'] class PredefinedStylesByNameTest(unittest.TestCase): @@ -114,10 +111,10 @@ def testGoogleByName(self): cfg = style.CreateStyleFromConfig(google_name) self.assertTrue(_LooksLikeGoogleStyle(cfg)) - def testChromiumByName(self): - for chromium_name in ('chromium', 'Chromium', 'CHROMIUM'): - cfg = style.CreateStyleFromConfig(chromium_name) - self.assertTrue(_LooksLikeChromiumStyle(cfg)) + def testYapfByName(self): + for yapf_name in ('yapf', 'YAPF'): + cfg = style.CreateStyleFromConfig(yapf_name) + self.assertTrue(_LooksLikeYapfStyle(cfg)) def testFacebookByName(self): for fb_name in ('facebook', 'FACEBOOK', 'Facebook'): @@ -157,17 +154,6 @@ def testDefaultBasedOnPEP8Style(self): self.assertTrue(_LooksLikePEP8Style(cfg)) self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 40) - def testDefaultBasedOnChromiumStyle(self): - cfg = textwrap.dedent(u'''\ - [style] - based_on_style = chromium - continuation_indent_width = 30 - ''') - with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: - cfg = style.CreateStyleFromConfig(filepath) - self.assertTrue(_LooksLikeChromiumStyle(cfg)) - self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 30) - def testDefaultBasedOnGoogleStyle(self): cfg = textwrap.dedent(u'''\ [style] @@ -193,25 +179,25 @@ def testDefaultBasedOnFacebookStyle(self): def testBoolOptionValue(self): cfg = textwrap.dedent(u'''\ [style] - based_on_style = chromium + based_on_style = pep8 SPLIT_BEFORE_NAMED_ASSIGNS=False split_before_logical_operator = true ''') with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: cfg = style.CreateStyleFromConfig(filepath) - self.assertTrue(_LooksLikeChromiumStyle(cfg)) + self.assertTrue(_LooksLikePEP8Style(cfg)) self.assertEqual(cfg['SPLIT_BEFORE_NAMED_ASSIGNS'], False) self.assertEqual(cfg['SPLIT_BEFORE_LOGICAL_OPERATOR'], True) def testStringListOptionValue(self): cfg = textwrap.dedent(u'''\ [style] - based_on_style = chromium + based_on_style = pep8 I18N_FUNCTION_CALL = N_, V_, T_ ''') with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: cfg = style.CreateStyleFromConfig(filepath) - self.assertTrue(_LooksLikeChromiumStyle(cfg)) + self.assertTrue(_LooksLikePEP8Style(cfg)) self.assertEqual(cfg['I18N_FUNCTION_CALL'], ['N_', 'V_', 'T_']) def testErrorNoStyleFile(self): @@ -254,7 +240,7 @@ def testDefaultBasedOnStyle(self): 'blank_line_before_nested_class_or_def': True } cfg = style.CreateStyleFromConfig(config_dict) - self.assertTrue(_LooksLikeChromiumStyle(cfg)) + self.assertTrue(_LooksLikePEP8Style(cfg)) self.assertEqual(cfg['INDENT_WIDTH'], 2) def testDefaultBasedOnStyleBadDict(self): @@ -277,7 +263,7 @@ def testDefaultBasedOnStyle(self): '{based_on_style: pep8,' ' indent_width: 2,' ' blank_line_before_nested_class_or_def: True}') - self.assertTrue(_LooksLikeChromiumStyle(cfg)) + self.assertTrue(_LooksLikePEP8Style(cfg)) self.assertEqual(cfg['INDENT_WIDTH'], 2) def testDefaultBasedOnStyleNotStrict(self): @@ -285,7 +271,7 @@ def testDefaultBasedOnStyleNotStrict(self): '{based_on_style : pep8' ' ,indent_width=2' ' blank_line_before_nested_class_or_def:True}') - self.assertTrue(_LooksLikeChromiumStyle(cfg)) + self.assertTrue(_LooksLikePEP8Style(cfg)) self.assertEqual(cfg['INDENT_WIDTH'], 2) def testDefaultBasedOnExplicitlyUnicodeTypeString(self): diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 46fde99d2..9bd09ac43 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -43,7 +43,7 @@ class FormatCodeTest(yapf_test_helper.YAPFTest): def _Check(self, unformatted_code, expected_formatted_code): formatted_code, _ = yapf_api.FormatCode( - unformatted_code, style_config='chromium') + unformatted_code, style_config='yapf') self.assertCodeEqual(expected_formatted_code, formatted_code) def testSimple(self): @@ -95,7 +95,7 @@ def testFormatFile(self): if True: pass """) - expected_formatted_code_chromium = textwrap.dedent(u"""\ + expected_formatted_code_yapf = textwrap.dedent(u"""\ if True: pass """) @@ -103,9 +103,8 @@ def testFormatFile(self): formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(expected_formatted_code_pep8, formatted_code) - formatted_code, _, _ = yapf_api.FormatFile( - filepath, style_config='chromium') - self.assertCodeEqual(expected_formatted_code_chromium, formatted_code) + formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='yapf') + self.assertCodeEqual(expected_formatted_code_yapf, formatted_code) def testDisableLinesPattern(self): unformatted_code = textwrap.dedent(u"""\ @@ -361,8 +360,7 @@ def testDisabledMultilineStringInDictionary(self): ] """) with utils.TempFileContents(self.test_tmpdir, code) as filepath: - formatted_code, _, _ = yapf_api.FormatFile( - filepath, style_config='chromium') + formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='yapf') self.assertCodeEqual(code, formatted_code) def testDisabledWithPrecedingText(self): @@ -381,15 +379,13 @@ def testDisabledWithPrecedingText(self): ] """) with utils.TempFileContents(self.test_tmpdir, code) as filepath: - formatted_code, _, _ = yapf_api.FormatFile( - filepath, style_config='chromium') + formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='yapf') self.assertCodeEqual(code, formatted_code) def testCRLFLineEnding(self): code = u'class _():\r\n pass\r\n' with utils.TempFileContents(self.test_tmpdir, code) as filepath: - formatted_code, _, _ = yapf_api.FormatFile( - filepath, style_config='chromium') + formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='yapf') self.assertCodeEqual(code, formatted_code) @@ -502,7 +498,7 @@ def testReadFromStdinWithEscapedStrings(self): """) self.assertYapfReformats(unformatted_code, expected_formatted_code) - def testSetChromiumStyle(self): + def testSetYapfStyle(self): unformatted_code = textwrap.dedent("""\ def foo(): # trail x = 37 @@ -514,9 +510,9 @@ def foo(): # trail self.assertYapfReformats( unformatted_code, expected_formatted_code, - extra_options=['--style=chromium']) + extra_options=['--style=yapf']) - def testSetCustomStyleBasedOnChromium(self): + def testSetCustomStyleBasedOnYapf(self): unformatted_code = textwrap.dedent("""\ def foo(): # trail x = 37 @@ -527,7 +523,7 @@ def foo(): # trail """) style_file = textwrap.dedent(u'''\ [style] - based_on_style = chromium + based_on_style = yapf spaces_before_comment = 4 ''') with utils.TempFileContents(self.test_tmpdir, style_file) as stylepath: @@ -1164,7 +1160,7 @@ def bar(): self.assertYapfReformats( unformatted_code, expected_formatted_code, - extra_options=['--lines', '1-1', '--style', 'chromium']) + extra_options=['--lines', '1-1', '--style', 'yapf']) def testMultilineCommentFormattingDisabled(self): unformatted_code = textwrap.dedent("""\ @@ -1198,7 +1194,7 @@ def testMultilineCommentFormattingDisabled(self): self.assertYapfReformats( unformatted_code, expected_formatted_code, - extra_options=['--lines', '1-1', '--style', 'chromium']) + extra_options=['--lines', '1-1', '--style', 'yapf']) def testTrailingCommentsWithDisabledFormatting(self): unformatted_code = textwrap.dedent("""\ @@ -1218,7 +1214,7 @@ def testTrailingCommentsWithDisabledFormatting(self): self.assertYapfReformats( unformatted_code, expected_formatted_code, - extra_options=['--lines', '1-1', '--style', 'chromium']) + extra_options=['--lines', '1-1', '--style', 'yapf']) def testUseTabs(self): unformatted_code = """\ @@ -1233,7 +1229,7 @@ def foo_function(): """ style_contents = u"""\ [style] -based_on_style = chromium +based_on_style = yapf USE_TABS = true INDENT_WIDTH=1 """ @@ -1257,7 +1253,7 @@ def f(): """ style_contents = u"""\ [style] -based_on_style = chromium +based_on_style = yapf USE_TABS = true INDENT_WIDTH=1 """ @@ -1282,7 +1278,7 @@ def foo_function(arg1, arg2, """ style_contents = u"""\ [style] -based_on_style = chromium +based_on_style = yapf USE_TABS = true COLUMN_LIMIT=32 INDENT_WIDTH=4 @@ -1310,7 +1306,7 @@ def foo_function(arg1, arg2, """ style_contents = u"""\ [style] -based_on_style = chromium +based_on_style = yapf USE_TABS = true COLUMN_LIMIT=32 INDENT_WIDTH=4 @@ -1407,7 +1403,7 @@ def testSpacingBeforeCommentsInDicts(self): self.assertYapfReformats( unformatted_code, expected_formatted_code, - extra_options=['--style', 'chromium', '--lines', '1-1']) + extra_options=['--style', 'yapf', '--lines', '1-1']) @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testNoSpacesAroundBinaryOperators(self): @@ -1457,7 +1453,7 @@ def testDisableWithLineRanges(self): self.assertYapfReformats( unformatted_code, expected_formatted_code, - extra_options=['--style', 'chromium', '--lines', '1-100']) + extra_options=['--style', 'yapf', '--lines', '1-100']) class BadInputTest(unittest.TestCase): From 3ad040a4f378579b3332a0770a9e4aa0451526d1 Mon Sep 17 00:00:00 2001 From: Yinyin Date: Fri, 24 Apr 2020 02:27:42 +0800 Subject: [PATCH 454/719] extend CONTINUATION_ALIGN_STYLE=FIXED for space indentation (#791) * let new line indent generation method in format decision be continuation align style aware * simplify tab replacement in format token * update documentation Co-authored-by: Bill Wendling <5993918+gwelymernans@users.noreply.github.com> --- CHANGELOG | 2 + README.rst | 11 ++--- yapf/yapflib/format_decision_state.py | 19 ++++++++- yapf/yapflib/format_token.py | 12 ++---- yapf/yapflib/style.py | 13 +++--- yapftests/format_token_test.py | 22 +++++----- yapftests/yapf_test.py | 58 ++++++++++++++++++++++++++- 7 files changed, 99 insertions(+), 38 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 06192982a..929b56001 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -15,6 +15,8 @@ slice operator. ### Changed - Renamed "chromium" style to "yapf". Chromium will now use PEP-8 directly. +- `CONTINUATION_ALIGN_STYLE` with `FIXED` or `VALIGN-RIGHT` now works with + space indentation. ### Fixed - Honor a disable directive at the end of a multiline comment. - Don't require splitting before comments in a list when diff --git a/README.rst b/README.rst index 316d8a0c6..e2db75128 100644 --- a/README.rst +++ b/README.rst @@ -434,15 +434,12 @@ Knobs - ``SPACE``: Use spaces for continuation alignment. This is default behavior. - ``FIXED``: Use fixed number (CONTINUATION_INDENT_WIDTH) of columns - (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs) for continuation - alignment. - - ``VALIGN-RIGHT``: Vertically align continuation lines with indent - characters. Slightly right (one more indent character) if cannot + (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs or CONTINUATION_INDENT_WIDTH + spaces) for continuation alignment. + - ``VALIGN-RIGHT``: Vertically align continuation lines to multiple of + INDENT_WIDTH columns. Slightly right (one tab or a few spaces) if cannot vertically align continuation lines with indent characters. - For options ``FIXED``, and ``VALIGN-RIGHT`` are only available when - ``USE_TABS`` is enabled. - ``CONTINUATION_INDENT_WIDTH`` Indent width used for line continuations. diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index e3057849c..577ae10d4 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -921,6 +921,18 @@ def _CalculateParameterListState(self, newline): return penalty + def _IndentWithContinuationAlignStyle(self, column): + if column == 0: + return column + align_style = style.Get('CONTINUATION_ALIGN_STYLE') + if align_style == 'FIXED': + return ((self.line.depth * style.Get('INDENT_WIDTH')) + + style.Get('CONTINUATION_INDENT_WIDTH')) + if align_style == 'VALIGN-RIGHT': + indent_width = style.Get('INDENT_WIDTH') + return indent_width * int((column + indent_width - 1) / indent_width) + return column + def _GetNewlineColumn(self): """Return the new column on the newline.""" current = self.next_token @@ -934,8 +946,11 @@ def _GetNewlineColumn(self): elif current.spaces_required_before > 2 or self.line.disable: return current.spaces_required_before + cont_aligned_indent = self._IndentWithContinuationAlignStyle( + top_of_stack.indent) + if current.OpensScope(): - return top_of_stack.indent if self.paren_level else self.first_indent + return cont_aligned_indent if self.paren_level else self.first_indent if current.ClosesScope(): if (previous.OpensScope() or @@ -973,7 +988,7 @@ def _GetNewlineColumn(self): format_token.Subtype.PARAMETER_START in previous.subtypes)): return top_of_stack.indent + style.Get('CONTINUATION_INDENT_WIDTH') - return top_of_stack.indent + return cont_aligned_indent def _FitsOnLine(self, start, end): """Determines if line between start and end can fit on the current line.""" diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index e6af9422f..0ed983fed 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -62,25 +62,21 @@ class Subtype(object): PARAMETER_STOP = 26 -def _TabbedContinuationAlignPadding(spaces, align_style, tab_width, - continuation_indent_width): +def _TabbedContinuationAlignPadding(spaces, align_style, tab_width): """Build padding string for continuation alignment in tabbed indentation. Arguments: spaces: (int) The number of spaces to place before the token for alignment. align_style: (str) The alignment style for continuation lines. tab_width: (int) Number of columns of each tab character. - continuation_indent_width: (int) Indent columns for line continuations. Returns: A padding string for alignment with style specified by align_style option. """ - if align_style == 'FIXED': + if align_style in ('FIXED', 'VALIGN-RIGHT'): if spaces > 0: - return '\t' * int(continuation_indent_width / tab_width) + return '\t' * int((spaces + tab_width - 1) / tab_width) return '' - elif align_style == 'VALIGN-RIGHT': - return '\t' * int((spaces + tab_width - 1) / tab_width) return ' ' * spaces @@ -171,7 +167,7 @@ def AddWhitespacePrefix(self, newlines_before, spaces=0, indent_level=0): if newlines_before > 0: indent_before = '\t' * indent_level + _TabbedContinuationAlignPadding( spaces, style.Get('CONTINUATION_ALIGN_STYLE'), - style.Get('INDENT_WIDTH'), style.Get('CONTINUATION_INDENT_WIDTH')) + style.Get('INDENT_WIDTH')) else: indent_before = '\t' * indent_level + ' ' * spaces else: diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 4e0836549..7cb31805a 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -128,14 +128,11 @@ def method(): - SPACE: Use spaces for continuation alignment. This is default behavior. - FIXED: Use fixed number (CONTINUATION_INDENT_WIDTH) of columns - (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs) for continuation - alignment. - - VALIGN-RIGHT: Vertically align continuation lines with indent - characters. Slightly right (one more indent character) if cannot - vertically align continuation lines with indent characters. - - Options FIXED and VALIGN-RIGHT are only available when USE_TABS is - enabled."""), + (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs or + CONTINUATION_INDENT_WIDTH spaces) for continuation alignment. + - VALIGN-RIGHT: Vertically align continuation lines to multiple of + INDENT_WIDTH columns. Slightly right (one tab or a few spaces) if + cannot vertically align continuation lines with indent characters."""), CONTINUATION_INDENT_WIDTH=textwrap.dedent("""\ Indent width used for line continuations."""), DEDENT_CLOSING_BRACKETS=textwrap.dedent("""\ diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index 2f6f973ba..b4c715107 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -26,40 +26,40 @@ class TabbedContinuationAlignPaddingTest(unittest.TestCase): def testSpace(self): align_style = 'SPACE' - pad = format_token._TabbedContinuationAlignPadding(0, align_style, 2, 4) + pad = format_token._TabbedContinuationAlignPadding(0, align_style, 2) self.assertEqual(pad, '') - pad = format_token._TabbedContinuationAlignPadding(2, align_style, 2, 4) + pad = format_token._TabbedContinuationAlignPadding(2, align_style, 2) self.assertEqual(pad, ' ' * 2) - pad = format_token._TabbedContinuationAlignPadding(5, align_style, 2, 4) + pad = format_token._TabbedContinuationAlignPadding(5, align_style, 2) self.assertEqual(pad, ' ' * 5) def testFixed(self): align_style = 'FIXED' - pad = format_token._TabbedContinuationAlignPadding(0, align_style, 4, 8) + pad = format_token._TabbedContinuationAlignPadding(0, align_style, 4) self.assertEqual(pad, '') - pad = format_token._TabbedContinuationAlignPadding(2, align_style, 4, 8) - self.assertEqual(pad, '\t' * 2) + pad = format_token._TabbedContinuationAlignPadding(2, align_style, 4) + self.assertEqual(pad, '\t') - pad = format_token._TabbedContinuationAlignPadding(5, align_style, 4, 8) + pad = format_token._TabbedContinuationAlignPadding(5, align_style, 4) self.assertEqual(pad, '\t' * 2) def testVAlignRight(self): align_style = 'VALIGN-RIGHT' - pad = format_token._TabbedContinuationAlignPadding(0, align_style, 4, 8) + pad = format_token._TabbedContinuationAlignPadding(0, align_style, 4) self.assertEqual(pad, '') - pad = format_token._TabbedContinuationAlignPadding(2, align_style, 4, 8) + pad = format_token._TabbedContinuationAlignPadding(2, align_style, 4) self.assertEqual(pad, '\t') - pad = format_token._TabbedContinuationAlignPadding(4, align_style, 4, 8) + pad = format_token._TabbedContinuationAlignPadding(4, align_style, 4) self.assertEqual(pad, '\t') - pad = format_token._TabbedContinuationAlignPadding(5, align_style, 4, 8) + pad = format_token._TabbedContinuationAlignPadding(5, align_style, 4) self.assertEqual(pad, '\t' * 2) diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 9bd09ac43..d68563397 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1269,8 +1269,8 @@ def foo_function(arg1, arg2, arg3): return ['hello', 'world',] """ expected_formatted_code = """\ -def foo_function(arg1, arg2, - arg3): +def foo_function( + arg1, arg2, arg3): return [ 'hello', 'world', @@ -1312,6 +1312,60 @@ def foo_function(arg1, arg2, INDENT_WIDTH=4 CONTINUATION_INDENT_WIDTH=8 CONTINUATION_ALIGN_STYLE = valign-right +""" + with utils.TempFileContents(self.test_tmpdir, style_contents) as stylepath: + self.assertYapfReformats( + unformatted_code, + expected_formatted_code, + extra_options=['--style={0}'.format(stylepath)]) + + def testUseSpacesContinuationAlignStyleFixed(self): + unformatted_code = """\ +def foo_function(arg1, arg2, arg3): + return ['hello', 'world',] +""" + expected_formatted_code = """\ +def foo_function( + arg1, arg2, arg3): + return [ + 'hello', + 'world', + ] +""" + style_contents = u"""\ +[style] +based_on_style = chromium +COLUMN_LIMIT=32 +INDENT_WIDTH=4 +CONTINUATION_INDENT_WIDTH=8 +CONTINUATION_ALIGN_STYLE = fixed +""" + with utils.TempFileContents(self.test_tmpdir, style_contents) as stylepath: + self.assertYapfReformats( + unformatted_code, + expected_formatted_code, + extra_options=['--style={0}'.format(stylepath)]) + + def testUseSpacesContinuationAlignStyleVAlignRight(self): + unformatted_code = """\ +def foo_function(arg1, arg2, arg3): + return ['hello', 'world',] +""" + expected_formatted_code = """\ +def foo_function(arg1, arg2, + arg3): + return [ + 'hello', + 'world', + ] +""" + style_contents = u"""\ +[style] +based_on_style = chromium +COLUMN_LIMIT=32 +INDENT_WIDTH=4 +CONTINUATION_INDENT_WIDTH=8 +CONTINUATION_ALIGN_STYLE = valign-right """ with utils.TempFileContents(self.test_tmpdir, style_contents) as stylepath: self.assertYapfReformats( From ef763e5ad1d29c69effda4ea402292b44a1e50dd Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 23 Apr 2020 11:29:55 -0700 Subject: [PATCH 455/719] Use "Yapf" style instead of "Chromium" --- yapftests/reformatter_basic_test.py | 4 ++-- yapftests/yapf_test.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 62d6e089b..50cfdbc56 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -3017,7 +3017,7 @@ def testForceMultilineDict_True(self): """) self.assertCodeEqual(expected, actual) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) def testForceMultilineDict_False(self): try: @@ -3031,7 +3031,7 @@ def testForceMultilineDict_False(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) finally: - style.SetGlobalStyle(style.CreateChromiumStyle()) + style.SetGlobalStyle(style.CreateYapfStyle()) if __name__ == '__main__': diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index d68563397..23c4fca41 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1334,7 +1334,7 @@ def foo_function( """ style_contents = u"""\ [style] -based_on_style = chromium +based_on_style = yapf COLUMN_LIMIT=32 INDENT_WIDTH=4 CONTINUATION_INDENT_WIDTH=8 @@ -1361,7 +1361,7 @@ def foo_function(arg1, arg2, """ style_contents = u"""\ [style] -based_on_style = chromium +based_on_style = yapf COLUMN_LIMIT=32 INDENT_WIDTH=4 CONTINUATION_INDENT_WIDTH=8 From b97bc5d2fa947aa43fcf9d794587c5ff325c6d77 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 23 Apr 2020 12:05:40 -0700 Subject: [PATCH 456/719] Bump version to 0.30.0 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 929b56001..007829673 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.30.0] UNRELEASED +## [0.30.0] 2020-04-23 ### Added - Added `SPACES_AROUND_LIST_DELIMITERS`, `SPACES_AROUND_DICT_DELIMITERS`, and `SPACES_AROUND_TUPLE_DELIMITERS` to add spaces after the opening- diff --git a/yapf/__init__.py b/yapf/__init__.py index f7d53d7b4..f03c93243 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -40,7 +40,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.29.0' +__version__ = '0.30.0' def main(argv): From 1995d2ce451804d4f942e6970f1d51f1d5b04877 Mon Sep 17 00:00:00 2001 From: Mauricio Herrera Cuadra Date: Wed, 19 Aug 2020 20:41:56 -0700 Subject: [PATCH 457/719] Support custom number of blank lines between top-level imports and variable definitions (#854) * Support custom number of blank lines after top-level imports * add test for non-default value * change wording of the knob --- CHANGELOG | 6 ++ CONTRIBUTORS | 1 + README.rst | 12 ++-- yapf/yapflib/reformatter.py | 8 +++ yapf/yapflib/style.py | 5 ++ yapftests/reformatter_basic_test.py | 93 ++++++++++++++++++++++++++++- 6 files changed, 119 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 007829673..d3169c0f7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,12 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.31.0] UNRELEASED +### Added +- Add 'BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES' to support setting + a custom number of blank lines between top-level imports and variable + definitions. + ## [0.30.0] 2020-04-23 ### Added - Added `SPACES_AROUND_LIST_DELIMITERS`, `SPACES_AROUND_DICT_DELIMITERS`, diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 284b13f3c..054ef2652 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -14,3 +14,4 @@ Eli Bendersky Sam Clegg Ɓukasz Langa Oleg Butuzov +Mauricio Herrera Cuadra diff --git a/README.rst b/README.rst index e2db75128..622232a7c 100644 --- a/README.rst +++ b/README.rst @@ -401,6 +401,10 @@ Knobs class Bar: pass +``BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES`` + Sets the number of desired blank lines between top-level imports and + variable definitions. Useful for compatibility with tools like isort. + ``COALESCE_BRACKETS`` Do not split consecutive brackets. Only relevant when ``DEDENT_CLOSING_BRACKETS`` or ``INDENT_CLOSING_BRACKETS`` @@ -567,7 +571,7 @@ Knobs [1, 2] will be formatted as: - + .. code-block:: python [ 1, 2 ] @@ -665,16 +669,16 @@ Knobs ``b`` in this code: .. code-block:: python - + abcdef( aReallyLongThing: int, b: [Int, Int]) - + With the new knob this is split as: .. code-block:: python - + abcdef( aReallyLongThing: int, b: [Int, Int]) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 7ec9888ad..4ca799bb8 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -650,6 +650,14 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, # The docstring shouldn't have a newline before it. return NO_BLANK_LINES + if first_token.is_name and not indent_depth: + if (prev_uwline.first.value == 'from' or + prev_uwline.first.value == 'import'): + # Support custom number of blank lines between top-level imports and + # variable definitions. + return 1 + style.Get( + 'BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES') + prev_last_token = prev_uwline.last if prev_last_token.is_docstring: if (not indent_depth and first_token.value in {'class', 'def', 'async'}): diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 7cb31805a..b01c2317a 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -104,6 +104,9 @@ def method(): BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=textwrap.dedent("""\ Number of blank lines surrounding top-level function and class definitions."""), + BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES=textwrap.dedent("""\ + Number of blank lines between top-level imports and variable + definitions."""), COALESCE_BRACKETS=textwrap.dedent("""\ Do not split consecutive brackets. Only relevant when dedent_closing_brackets is set. For example: @@ -419,6 +422,7 @@ def CreatePEP8Style(): BLANK_LINE_BEFORE_CLASS_DOCSTRING=False, BLANK_LINE_BEFORE_MODULE_DOCSTRING=False, BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=2, + BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES=1, COALESCE_BRACKETS=False, COLUMN_LIMIT=79, CONTINUATION_ALIGN_STYLE='SPACE', @@ -606,6 +610,7 @@ def _IntOrIntListConverter(s): BLANK_LINE_BEFORE_CLASS_DOCSTRING=_BoolConverter, BLANK_LINE_BEFORE_MODULE_DOCSTRING=_BoolConverter, BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=int, + BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES=int, COALESCE_BRACKETS=_BoolConverter, COLUMN_LIMIT=int, CONTINUATION_ALIGN_STYLE=_ContinuationAlignStyleStringConverter, diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 50cfdbc56..624b6f181 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -253,6 +253,95 @@ def f( # Intermediate comment uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testBlankLinesAfterTopLevelImports(self): + unformatted_code = textwrap.dedent("""\ + import foo as bar + VAR = 'baz' + """) + expected_formatted_code = textwrap.dedent("""\ + import foo as bar + + VAR = 'baz' + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + unformatted_code = textwrap.dedent("""\ + import foo as bar + + VAR = 'baz' + """) + expected_formatted_code = textwrap.dedent("""\ + import foo as bar + + + VAR = 'baz' + """) + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: yapf, blank_lines_between_top_level_imports_and_variables: 2}' + )) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(uwlines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) + + unformatted_code = textwrap.dedent("""\ + import foo as bar + # Some comment + """) + expected_formatted_code = textwrap.dedent("""\ + import foo as bar + # Some comment + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + unformatted_code = textwrap.dedent("""\ + import foo as bar + class Baz(): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + import foo as bar + + + class Baz(): + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + unformatted_code = textwrap.dedent("""\ + import foo as bar + def foobar(): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + import foo as bar + + + def foobar(): + pass + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + + unformatted_code = textwrap.dedent("""\ + def foobar(): + from foo import Bar + Bar.baz() + """) + expected_formatted_code = textwrap.dedent("""\ + def foobar(): + from foo import Bar + Bar.baz() + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + def testBlankLinesAtEndOfFile(self): unformatted_code = textwrap.dedent("""\ def foobar(): # foo @@ -421,8 +510,8 @@ def testSingleComment(self): def testCommentsWithTrailingSpaces(self): unformatted_code = textwrap.dedent("""\ - # Thing 1 - # Thing 2 + # Thing 1 + # Thing 2 """) expected_formatted_code = textwrap.dedent("""\ # Thing 1 From 93c9b98131ebc9ec95822026d13ca698d7430285 Mon Sep 17 00:00:00 2001 From: Mauricio Herrera Cuadra Date: Thu, 20 Aug 2020 13:26:08 -0700 Subject: [PATCH 458/719] Fix test name for proper context (#857) * Fix test name for proper context Tiny patch since this was missed in PR #854 * restore testCommentsWithTrailingSpaces --- yapftests/reformatter_basic_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 624b6f181..3e50b6a92 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -253,7 +253,7 @@ def f( # Intermediate comment uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - def testBlankLinesAfterTopLevelImports(self): + def testBlankLinesBetweenTopLevelImportsAndVariables(self): unformatted_code = textwrap.dedent("""\ import foo as bar VAR = 'baz' @@ -510,8 +510,8 @@ def testSingleComment(self): def testCommentsWithTrailingSpaces(self): unformatted_code = textwrap.dedent("""\ - # Thing 1 - # Thing 2 + # Thing 1 + # Thing 2 """) expected_formatted_code = textwrap.dedent("""\ # Thing 1 From c2021f2b17a76d507f0768a4e3e76585dc10c4f5 Mon Sep 17 00:00:00 2001 From: Matthew Suozzo Date: Sat, 19 Sep 2020 22:24:49 -0400 Subject: [PATCH 459/719] Allow `lines` parameter to fix whitespace between statements. (#864) * Fix split penalty for single-argument function calls with generators. The previous logic considered all components of the generator in a single-argument call such as 'f(a for a in x)' to be strongly connected like a normal single-argument call (e.g. 'f(a_var)'). This caused formatting irregularities in these cases. This change retains normal split penalties in the single-argument generator case. * Allow `lines` parameter to fix whitespace between statements. The previous logic largely ignored `lines` values that were not part of statements. This means that yapf required a statement to be formatted to make whitespace-only changes. This logic tweak allows `lines` to be taken into account even when the adjacent statements are disabled (i.e. not in `lines`). * Remove chromium style from test. --- yapf/yapflib/reformatter.py | 6 +----- yapftests/yapf_test.py | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 4ca799bb8..bfc712191 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -115,10 +115,6 @@ def _RetainHorizontalSpacing(uwline): def _RetainRequiredVerticalSpacing(cur_uwline, prev_uwline, lines): """Retain all vertical spacing between lines.""" - if cur_uwline.disable and (not prev_uwline or prev_uwline.disable): - # If both lines are disabled we aren't allowed to reformat anything. - lines = set() - prev_tok = None if prev_uwline is not None: prev_tok = prev_uwline.last @@ -160,7 +156,7 @@ def _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines): if cur_tok.is_comment and not prev_tok.is_comment: # Don't adjust between a comment and non-comment. pass - elif lines and (cur_lineno in lines or prev_lineno in lines): + elif lines and lines.intersection(range(prev_lineno, cur_lineno + 1)): desired_newlines = cur_tok.whitespace_prefix.count('\n') whitespace_lines = range(prev_lineno + 1, cur_lineno) deletable_lines = len(lines.intersection(whitespace_lines)) diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 23c4fca41..e3e3df38e 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1016,6 +1016,29 @@ def aaaaaaaaaaaaa(self): expected_formatted_code, extra_options=['--lines', '4-7']) + def testRetainVerticalFormattingBetweenDisabledLines(self): + unformatted_code = textwrap.dedent("""\ + class A(object): + def aaaaaaaaaaaaa(self): + pass + + + def bbbbbbbbbbbbb(self): # 5 + pass + """) + expected_formatted_code = textwrap.dedent("""\ + class A(object): + def aaaaaaaaaaaaa(self): + pass + + def bbbbbbbbbbbbb(self): # 5 + pass + """) + self.assertYapfReformats( + unformatted_code, + expected_formatted_code, + extra_options=['--lines', '4-4']) + def testFormatLinesSpecifiedInMiddleOfExpression(self): unformatted_code = textwrap.dedent("""\ class A(object): From 2b373cb5b8605f612e298683315bd02350de0509 Mon Sep 17 00:00:00 2001 From: Matthew Suozzo Date: Wed, 23 Sep 2020 00:12:43 -0400 Subject: [PATCH 460/719] Fix parser refactor in main (#865) * Fix parser refactor in main Parser construction was refactored to a separate function, however `main` still needs access to that instance to be able to use the ArgumentParser.error interface. * Update __init__.py --- yapf/__init__.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index f03c93243..3aca8bdc1 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -57,7 +57,8 @@ def main(argv): Raises: YapfError: if none of the supplied files were Python files. """ - args = _ParseArguments(argv) + parser = _BuildParser() + args = parser.parse_args(argv[1:]) if args.version: print('yapf {}'.format(__version__)) return 0 @@ -65,7 +66,7 @@ def main(argv): style_config = args.style if args.style_help: - print_help(args) + _PrintHelp(args) return 0 if args.lines and len(args.files) > 1: @@ -136,7 +137,7 @@ def main(argv): return 1 if changed and (args.diff or args.quiet) else 0 -def print_help(args): +def _PrintHelp(args): """Prints the help menu.""" if args.style is None and not args.no_local_style: @@ -268,15 +269,11 @@ def _GetLines(line_strings): return lines -def _ParseArguments(argv): - """Parse the command line arguments. - - Arguments: - argv: command-line arguments, such as sys.argv (including the program name - in argv[0]). +def _BuildParser(): + """Constructs the parser for the command line arguments. Returns: - An object containing the arguments used to invoke the program. + An ArgumentParser instance for the CLI. """ parser = argparse.ArgumentParser(description='Formatter for Python code.') parser.add_argument( @@ -357,7 +354,7 @@ def _ParseArguments(argv): parser.add_argument( 'files', nargs='*', help='reads from stdin when no files are specified.') - return parser.parse_args(argv[1:]) + return parser def run_main(): # pylint: disable=invalid-name From a0a3dbb38032bfb4dc00a78f73fa5aed90ecd77d Mon Sep 17 00:00:00 2001 From: Bouwe Andela Date: Mon, 9 Nov 2020 00:03:43 +0100 Subject: [PATCH 461/719] Add yapf-diff command (#870) * Add yapf-diff command Modified https://github.com/llvm/llvm-project/blob/master/clang/tools/clang-format/clang-format-diff.py to work with yapf * format with yapf 0.30.0 * Move script to third_party and add license --- README.rst | 36 ++++ setup.py | 5 +- yapf/third_party/__init__.py | 0 yapf/third_party/yapf_diff/LICENSE | 219 ++++++++++++++++++++++++ yapf/third_party/yapf_diff/__init__.py | 0 yapf/third_party/yapf_diff/yapf_diff.py | 146 ++++++++++++++++ 6 files changed, 405 insertions(+), 1 deletion(-) create mode 100644 yapf/third_party/__init__.py create mode 100644 yapf/third_party/yapf_diff/LICENSE create mode 100644 yapf/third_party/yapf_diff/__init__.py create mode 100644 yapf/third_party/yapf_diff/yapf_diff.py diff --git a/README.rst b/README.rst index 622232a7c..805e9c4f5 100644 --- a/README.rst +++ b/README.rst @@ -321,6 +321,42 @@ The ``in_place`` argument saves the reformatted code back to the file: >>> print(open("foo.py").read()) # contents of file (now fixed) a == b +Formatting diffs +================ + +Options:: + + usage: yapf-diff [-h] [-i] [-p NUM] [--regex PATTERN] [--iregex PATTERN][-v] + [--style STYLE] [--binary BINARY] + + This script reads input from a unified diff and reformats all the changed + lines. This is useful to reformat all the lines touched by a specific patch. + Example usage for git/svn users: + + git diff -U0 --no-color --relative HEAD^ | yapf-diff -i + svn diff --diff-cmd=diff -x-U0 | yapf-diff -p0 -i + + It should be noted that the filename contained in the diff is used + unmodified to determine the source file to update. Users calling this script + directly should be careful to ensure that the path in the diff is correct + relative to the current working directory. + + optional arguments: + -h, --help show this help message and exit + -i, --in-place apply edits to files instead of displaying a diff + -p NUM, --prefix NUM strip the smallest prefix containing P slashes + --regex PATTERN custom pattern selecting file paths to reformat + (case sensitive, overrides -iregex) + --iregex PATTERN custom pattern selecting file paths to reformat + (case insensitive, overridden by -regex) + -v, --verbose be more verbose, ineffective without -i + --style STYLE specify formatting style: either a style name (for + example "pep8" or "google"), or the name of a file + with style settings. The default is pep8 unless a + .style.yapf or setup.cfg file located in one of the + parent directories of the source file (or current + directory for stdin) + --binary BINARY location of binary to use for yapf Knobs ===== diff --git a/setup.py b/setup.py index 21e94707d..fe2a0469a 100644 --- a/setup.py +++ b/setup.py @@ -65,7 +65,10 @@ def run(self): 'Topic :: Software Development :: Quality Assurance', ], entry_points={ - 'console_scripts': ['yapf = yapf:run_main'], + 'console_scripts': [ + 'yapf = yapf:run_main', + 'yapf-diff = yapf.third_party.yapf_diff.yapf_diff:main', + ], }, cmdclass={ 'test': RunTests, diff --git a/yapf/third_party/__init__.py b/yapf/third_party/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/yapf/third_party/yapf_diff/LICENSE b/yapf/third_party/yapf_diff/LICENSE new file mode 100644 index 000000000..f9dc50615 --- /dev/null +++ b/yapf/third_party/yapf_diff/LICENSE @@ -0,0 +1,219 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + diff --git a/yapf/third_party/yapf_diff/__init__.py b/yapf/third_party/yapf_diff/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/yapf/third_party/yapf_diff/yapf_diff.py b/yapf/third_party/yapf_diff/yapf_diff.py new file mode 100644 index 000000000..337723166 --- /dev/null +++ b/yapf/third_party/yapf_diff/yapf_diff.py @@ -0,0 +1,146 @@ +# Modified copy of clang-format-diff.py that works with yapf. +# +# Licensed under the Apache License, Version 2.0 (the "License") with LLVM +# Exceptions; you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://llvm.org/LICENSE.txt +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +This script reads input from a unified diff and reformats all the changed +lines. This is useful to reformat all the lines touched by a specific patch. +Example usage for git/svn users: + + git diff -U0 --no-color --relative HEAD^ | yapf-diff -i + svn diff --diff-cmd=diff -x-U0 | yapf-diff -p0 -i + +It should be noted that the filename contained in the diff is used unmodified +to determine the source file to update. Users calling this script directly +should be careful to ensure that the path in the diff is correct relative to the +current working directory. +""" +from __future__ import absolute_import, division, print_function + +import argparse +import difflib +import re +import subprocess +import sys + +if sys.version_info.major >= 3: + from io import StringIO +else: + from io import BytesIO as StringIO + + +def main(): + parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument( + '-i', + '--in-place', + action='store_true', + default=False, + help='apply edits to files instead of displaying a diff') + parser.add_argument( + '-p', + '--prefix', + metavar='NUM', + default=1, + help='strip the smallest prefix containing P slashes') + parser.add_argument( + '--regex', + metavar='PATTERN', + default=None, + help='custom pattern selecting file paths to reformat ' + '(case sensitive, overrides -iregex)') + parser.add_argument( + '--iregex', + metavar='PATTERN', + default=r'.*\.(py)', + help='custom pattern selecting file paths to reformat ' + '(case insensitive, overridden by -regex)') + parser.add_argument( + '-v', + '--verbose', + action='store_true', + help='be more verbose, ineffective without -i') + parser.add_argument( + '--style', + help='specify formatting style: either a style name (for ' + 'example "pep8" or "google"), or the name of a file with ' + 'style settings. The default is pep8 unless a ' + '.style.yapf or setup.cfg file located in one of the ' + 'parent directories of the source file (or current ' + 'directory for stdin)') + parser.add_argument( + '--binary', default='yapf', help='location of binary to use for yapf') + args = parser.parse_args() + + # Extract changed lines for each file. + filename = None + lines_by_file = {} + for line in sys.stdin: + match = re.search(r'^\+\+\+\ (.*?/){%s}(\S*)' % args.prefix, line) + if match: + filename = match.group(2) + if filename is None: + continue + + if args.regex is not None: + if not re.match('^%s$' % args.regex, filename): + continue + else: + if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE): + continue + + match = re.search(r'^@@.*\+(\d+)(,(\d+))?', line) + if match: + start_line = int(match.group(1)) + line_count = 1 + if match.group(3): + line_count = int(match.group(3)) + if line_count == 0: + continue + end_line = start_line + line_count - 1 + lines_by_file.setdefault(filename, []).extend( + ['--lines', str(start_line) + '-' + str(end_line)]) + + # Reformat files containing changes in place. + for filename, lines in lines_by_file.items(): + if args.in_place and args.verbose: + print('Formatting {}'.format(filename)) + command = [args.binary, filename] + if args.in_place: + command.append('-i') + command.extend(lines) + if args.style: + command.extend(['--style', args.style]) + p = subprocess.Popen( + command, + stdout=subprocess.PIPE, + stderr=None, + stdin=subprocess.PIPE, + universal_newlines=True) + stdout, stderr = p.communicate() + if p.returncode != 0: + sys.exit(p.returncode) + + if not args.in_place: + with open(filename) as f: + code = f.readlines() + formatted_code = StringIO(stdout).readlines() + diff = difflib.unified_diff(code, formatted_code, filename, filename, + '(before formatting)', '(after formatting)') + diff_string = ''.join(diff) + if len(diff_string) > 0: + sys.stdout.write(diff_string) + + +if __name__ == '__main__': + main() From e0b3449cd3f3ba6732224d398a287e0711d5a4b6 Mon Sep 17 00:00:00 2001 From: Harkirat Singh Date: Tue, 24 Nov 2020 04:31:28 +0530 Subject: [PATCH 462/719] pre-commit config (#878) --- .pre-commit-config.yml | 30 ++++++++++++++++++++++++++++++ .pre-commit-hooks.yml | 9 +++++++++ 2 files changed, 39 insertions(+) create mode 100644 .pre-commit-config.yml create mode 100644 .pre-commit-hooks.yml diff --git a/.pre-commit-config.yml b/.pre-commit-config.yml new file mode 100644 index 000000000..3bd65c26f --- /dev/null +++ b/.pre-commit-config.yml @@ -0,0 +1,30 @@ +# File introduces automated checks triggered on git events +# to enable run `pip install pre-commit && pre-commit install` + +repos: + - repo: local + hooks: + - id: yapf + name: yapf + language: python + entry: yapf + args: [-i, -vv] + types: [python] + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.2.0 + hooks: + - id: trailing-whitespace + - id: check-docstring-first + - id: check-json + - id: check-added-large-files + - id: check-yaml + - id: debug-statements + - id: requirements-txt-fixer + - id: check-merge-conflict + - id: double-quote-string-fixer + - id: end-of-file-fixer + - id: sort-simple-yaml + - repo: meta + hooks: + - id: check-hooks-apply + - id: check-useless-excludes diff --git a/.pre-commit-hooks.yml b/.pre-commit-hooks.yml new file mode 100644 index 000000000..3eba1f2e7 --- /dev/null +++ b/.pre-commit-hooks.yml @@ -0,0 +1,9 @@ +# File configures YAPF to be used as a git hook with https://github.com/pre-commit/pre-commit + +- id: yapf + name: yapf + description: "A formatter for Python files." + entry: yapf + args: [-i] #inplace + language: python + types: [python] From b97ca956b7155acbf589fad1d669e6ec6fc8ea16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Br=C3=A9nainn=20Woodsend?= <30940778+bwoodsend@users.noreply.github.com> Date: Wed, 2 Dec 2020 19:53:38 +0000 Subject: [PATCH 463/719] Fix directory exclusion on Windows. (#881) * Fix `GetCommandLineFilesTest.tearDown()` on Windows Deleting a folder that is the working dir of any running process is a PermissionError on Windows. The above test should therefore `os.chdir()` out of a temp dir before trying to delete it. * Strip trailing path separators from `exlcude` paths * Fix excluding folders on Windows Folder exlusion had no effect on Windows because `os.walk()` output uses backslash path separators but `IsIgnored()` was hardcoded to use forward slash. Replace hardcoded '/'s with `os.path.sep`. --- CHANGELOG | 2 ++ yapf/yapflib/file_resources.py | 7 ++++--- yapftests/file_resources_test.py | 10 ++++++---- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d3169c0f7..e512fef6c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,8 @@ - Add 'BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES' to support setting a custom number of blank lines between top-level imports and variable definitions. +### Fixed +- Exclude directories on Windows. ## [0.30.0] 2020-04-23 ### Added diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 50b4687f4..4c6bf38e8 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -154,6 +154,7 @@ def _FindPythonFiles(filenames, recursive, exclude): """Find all Python files.""" if exclude and any(e.startswith('./') for e in exclude): raise errors.YapfError("path in '--exclude' should not start with ./") + exclude = exclude and [e.rstrip("/" + os.path.sep) for e in exclude] python_files = [] for filename in filenames: @@ -186,10 +187,10 @@ def _FindPythonFiles(filenames, recursive, exclude): def IsIgnored(path, exclude): """Return True if filename matches any patterns in exclude.""" - path = path.lstrip('/') - while path.startswith('./'): + path = path.lstrip(os.path.sep) + while path.startswith('.' + os.path.sep): path = path[2:] - return any(fnmatch.fnmatch(path, e.rstrip('/')) for e in exclude) + return any(fnmatch.fnmatch(path, e.rstrip(os.path.sep)) for e in exclude) def IsPythonFile(filename): diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index c91d93cf8..2bf68ab1c 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -152,8 +152,8 @@ def setUp(self): # pylint: disable=g-missing-super-call self.old_dir = os.getcwd() def tearDown(self): # pylint: disable=g-missing-super-call - shutil.rmtree(self.test_tmpdir) os.chdir(self.old_dir) + shutil.rmtree(self.test_tmpdir) def _make_test_dir(self, name): fullpath = os.path.normpath(os.path.join(self.test_tmpdir, name)) @@ -313,7 +313,8 @@ def test_find_with_excluded_dirs(self): 'test2/testinner/', ])) - self.assertEqual(found, ['test3/foo/bar/bas/xxx/testfile3.py']) + self.assertEqual( + found, ['test3/foo/bar/bas/xxx/testfile3.py'.replace("/", os.path.sep)]) found = sorted( file_resources.GetCommandLineFiles(['.'], @@ -323,7 +324,8 @@ def test_find_with_excluded_dirs(self): 'test3', ])) - self.assertEqual(found, ['./test2/testinner/testfile2.py']) + self.assertEqual( + found, ['./test2/testinner/testfile2.py'.replace("/", os.path.sep)]) def test_find_with_excluded_current_dir(self): with self.assertRaises(errors.YapfError): @@ -386,7 +388,7 @@ def test_sub_path(self): def test_trailing_slash(self): self.assertTrue(file_resources.IsIgnored('z', ['z'])) - self.assertTrue(file_resources.IsIgnored('z', ['z/'])) + self.assertTrue(file_resources.IsIgnored('z', ['z' + os.path.sep])) class BufferedByteStream(object): From cb235892b3df90ba4f3de11dbfb05e76c19ccc2a Mon Sep 17 00:00:00 2001 From: Harkirat Singh Date: Fri, 11 Dec 2020 02:31:03 +0530 Subject: [PATCH 464/719] Resolves #882 (#884) * pre-commit config * Resolves #882; pull upstream --- .pre-commit-config.yaml | 30 ++++++++++++++++++++++++++++++ .pre-commit-hooks.yaml | 9 +++++++++ 2 files changed, 39 insertions(+) create mode 100644 .pre-commit-config.yaml create mode 100644 .pre-commit-hooks.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..3bd65c26f --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,30 @@ +# File introduces automated checks triggered on git events +# to enable run `pip install pre-commit && pre-commit install` + +repos: + - repo: local + hooks: + - id: yapf + name: yapf + language: python + entry: yapf + args: [-i, -vv] + types: [python] + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.2.0 + hooks: + - id: trailing-whitespace + - id: check-docstring-first + - id: check-json + - id: check-added-large-files + - id: check-yaml + - id: debug-statements + - id: requirements-txt-fixer + - id: check-merge-conflict + - id: double-quote-string-fixer + - id: end-of-file-fixer + - id: sort-simple-yaml + - repo: meta + hooks: + - id: check-hooks-apply + - id: check-useless-excludes diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml new file mode 100644 index 000000000..3eba1f2e7 --- /dev/null +++ b/.pre-commit-hooks.yaml @@ -0,0 +1,9 @@ +# File configures YAPF to be used as a git hook with https://github.com/pre-commit/pre-commit + +- id: yapf + name: yapf + description: "A formatter for Python files." + entry: yapf + args: [-i] #inplace + language: python + types: [python] From a911d95415e4e38bdef72a1373e6c734a1558a04 Mon Sep 17 00:00:00 2001 From: bwac <40532058+bwac2517@users.noreply.github.com> Date: Sat, 12 Dec 2020 07:41:06 +1100 Subject: [PATCH 465/719] Removed since link wont be fixed #869 (#885) --- README.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.rst b/README.rst index 805e9c4f5..e013c5263 100644 --- a/README.rst +++ b/README.rst @@ -37,8 +37,6 @@ The ultimate goal is that the code YAPF produces is as good as the code that a programmer would write if they were following the style guide. It takes away some of the drudgery of maintaining your code. -Try out YAPF with this `online demo `_. - .. footer:: YAPF is not an official Google product (experimental or otherwise), it is From 589d97902faeb194c851789c8caff5f6ac9495fb Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Sun, 20 Dec 2020 17:58:11 -0800 Subject: [PATCH 466/719] Ignore end of line `# copybara:` directives. (#886) * Ignore end of line `# copybara:` directives. pylint and pytype end of line comments adjusting their behavior are already handled specially. This does the same for copybara. I don't like that this is turning into a chain of property calls, refactoring this into a single question of "is this end of line comment special" would be better if we gain any more of these. A usual internal comment this will ignore is `# copybara:strip` placed on a long import line for something being excluded by copybara when pushing internally maintained code to upstream to keep internal google-isms from escaping. * Add a changelog entry. --- CHANGELOG | 1 + yapf/yapflib/format_decision_state.py | 4 ++-- yapf/yapflib/format_token.py | 5 +++++ yapf/yapflib/reformatter.py | 3 ++- yapftests/reformatter_buganizer_test.py | 5 ++++- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e512fef6c..6b1038286 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,7 @@ - Add 'BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES' to support setting a custom number of blank lines between top-level imports and variable definitions. +- Ignore end of line `# copybara:` directives when checking line length. ### Fixed - Exclude directories on Windows. diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 577ae10d4..dbe3d819a 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -741,8 +741,8 @@ def MoveStateToNextToken(self): # Calculate the penalty for overflowing the column limit. penalty = 0 - if (not current.is_pylint_comment and not current.is_pytype_comment and - self.column > self.column_limit): + if (not current.is_pylint_comment and not current.is_pytype_comment + and not current.is_copybara_comment and self.column > self.column_limit): excess_characters = self.column - self.column_limit penalty += style.Get('SPLIT_PENALTY_EXCESS_CHARACTER') * excess_characters diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 0ed983fed..92c26ee57 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -378,3 +378,8 @@ def is_pylint_comment(self): def is_pytype_comment(self): return self.is_comment and re.match(r'#.*\bpytype:\s*(disable|enable)=', self.value) + + @property + def is_copybara_comment(self): + return self.is_comment and re.match(r'#.*\bcopybara:(strip|insert|replace)', + self.value) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index bfc712191..cd940bb13 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -259,7 +259,8 @@ def _CanPlaceOnSingleLine(uwline): indent_amt = style.Get('INDENT_WIDTH') * uwline.depth last = uwline.last last_index = -1 - if last.is_pylint_comment or last.is_pytype_comment: + if (last.is_pylint_comment or last.is_pytype_comment + or last.is_copybara_comment): last = last.previous_token last_index = -2 if last is None: diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 653e88557..e96f6da74 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -166,7 +166,10 @@ class _(): def _(): X = ( _ares_label_prefix + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') # pylint: disable=line-too-long + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' # pylint: disable=line-too-long + 'PyTypePyTypePyTypePyTypePyTypePyTypePyTypePyTypePyTypePyTypePyTypePyTypePyType' # pytype: disable=attribute-error + 'CopybaraCopybaraCopybaraCopybaraCopybaraCopybaraCopybaraCopybaraCopybara' # copybara:strip + ) """ uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) From 65fd3c8bf9985574101ee3458b829f4d553c81b2 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Sun, 20 Dec 2020 18:59:01 -0700 Subject: [PATCH 467/719] chore: replace blacklist with block_list (#863) --- yapf/yapflib/unwrapped_line.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 38501c0d0..475bd6e0e 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -366,9 +366,9 @@ def _SpaceRequiredBetween(left, right, is_line_disabled): if lval == '**' or rval == '**': # Space around the "power" operator. return style.Get('SPACES_AROUND_POWER_OPERATOR') - # Enforce spaces around binary operators except the blacklisted ones. - blacklist = style.Get('NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS') - if lval in blacklist or rval in blacklist: + # Enforce spaces around binary operators except the blocked ones. + block_list = style.Get('NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS') + if lval in block_list or rval in block_list: return False if style.Get('ARITHMETIC_PRECEDENCE_INDICATION'): if _PriorityIndicatingNoSpace(left) or _PriorityIndicatingNoSpace(right): From 9a4adf4dc3bdac375a92ffd2ae7ad06935adb5b8 Mon Sep 17 00:00:00 2001 From: Brian Mego Date: Sun, 20 Dec 2020 20:00:07 -0600 Subject: [PATCH 468/719] Adds walrus test and python 3.7/3.8 tox definitions (#851) --- tox.ini | 2 +- yapf/yapflib/py3compat.py | 2 ++ yapftests/reformatter_basic_test.py | 13 +++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index dca30d2b3..f42b884f0 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist=py27,py34,py35,py36 +envlist=py27,py34,py35,py36,py37,py38 [testenv] commands= diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py index 5373b013a..7c9052374 100644 --- a/yapf/yapflib/py3compat.py +++ b/yapf/yapflib/py3compat.py @@ -20,6 +20,8 @@ PY3 = sys.version_info[0] >= 3 PY36 = sys.version_info[0] >= 3 and sys.version_info[1] >= 6 +PY37 = sys.version_info[0] >= 3 and sys.version_info[1] >= 7 +PY38 = sys.version_info[0] >= 3 and sys.version_info[1] >= 8 if PY3: StringIO = io.StringIO diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 3e50b6a92..a67e4c47b 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -3122,6 +3122,19 @@ def testForceMultilineDict_False(self): finally: style.SetGlobalStyle(style.CreateYapfStyle()) + @unittest.skipUnless(py3compat.PY38, 'Requires Python 3.8') + def testWalrus(self): + unformatted_code = textwrap.dedent("""\ + if (x := len([1]*1000)>100): + print(f'{x} is pretty big' ) + """) + expected = textwrap.dedent("""\ + if (x := len([1] * 1000) > 100): + print(f'{x} is pretty big') + """) + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected, reformatter.Reformat(uwlines)) + if __name__ == '__main__': unittest.main() From a569f39192f137ded1ed68020102154f66df6c06 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 22 Jan 2021 22:13:47 -0800 Subject: [PATCH 469/719] Reformat --- yapf/yapflib/format_decision_state.py | 4 ++-- yapf/yapflib/reformatter.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index dbe3d819a..164818e91 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -741,8 +741,8 @@ def MoveStateToNextToken(self): # Calculate the penalty for overflowing the column limit. penalty = 0 - if (not current.is_pylint_comment and not current.is_pytype_comment - and not current.is_copybara_comment and self.column > self.column_limit): + if (not current.is_pylint_comment and not current.is_pytype_comment and + not current.is_copybara_comment and self.column > self.column_limit): excess_characters = self.column - self.column_limit penalty += style.Get('SPLIT_PENALTY_EXCESS_CHARACTER') * excess_characters diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index cd940bb13..60386e51d 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -259,8 +259,8 @@ def _CanPlaceOnSingleLine(uwline): indent_amt = style.Get('INDENT_WIDTH') * uwline.depth last = uwline.last last_index = -1 - if (last.is_pylint_comment or last.is_pytype_comment - or last.is_copybara_comment): + if (last.is_pylint_comment or last.is_pytype_comment or + last.is_copybara_comment): last = last.previous_token last_index = -2 if last is None: From 765b583ca12d6a66f4a35c17dd77bbc19f75a309 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 22 Jan 2021 22:15:02 -0800 Subject: [PATCH 470/719] Rename master branch to main --- CHANGELOG | 1 + README.rst | 8 ++++---- plugins/README.rst | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6b1038286..b8906d10c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ ## [0.31.0] UNRELEASED ### Added +- Renamed 'master' brannch to 'main'. - Add 'BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES' to support setting a custom number of blank lines between top-level imports and variable definitions. diff --git a/README.rst b/README.rst index e013c5263..ac07aee62 100644 --- a/README.rst +++ b/README.rst @@ -6,12 +6,12 @@ YAPF :target: https://badge.fury.io/py/yapf :alt: PyPI version -.. image:: https://travis-ci.org/google/yapf.svg?branch=master +.. image:: https://travis-ci.org/google/yapf.svg?branch=main :target: https://travis-ci.org/google/yapf :alt: Build status -.. image:: https://coveralls.io/repos/google/yapf/badge.svg?branch=master - :target: https://coveralls.io/r/google/yapf?branch=master +.. image:: https://coveralls.io/repos/google/yapf/badge.svg?branch=main + :target: https://coveralls.io/r/google/yapf?branch=main :alt: Coverage status @@ -179,7 +179,7 @@ custom style is based on (think of it like subclassing). Four styles are predefined: ``pep8`` (default), ``google``, ``yapf``, and ``facebook`` (see ``_STYLE_NAME_TO_FACTORY`` in style.py_). -.. _style.py: https://github.com/google/yapf/blob/master/yapf/yapflib/style.py#L445 +.. _style.py: https://github.com/google/yapf/blob/main/yapf/yapflib/style.py#L445 It's also possible to do the same on the command line with a dictionary. For example: diff --git a/plugins/README.rst b/plugins/README.rst index f7657cc8a..b87bb2d76 100644 --- a/plugins/README.rst +++ b/plugins/README.rst @@ -65,7 +65,7 @@ directory: .. code-block:: bash # From the root of your git project. - curl -o pre-commit.sh https://raw.githubusercontent.com/google/yapf/master/plugins/pre-commit.sh + curl -o pre-commit.sh https://raw.githubusercontent.com/google/yapf/main/plugins/pre-commit.sh chmod a+x pre-commit.sh mv pre-commit.sh .git/hooks/pre-commit From e948446838afff4a9b1d24a30814f952f1a7c0c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Br=C3=A9nainn=20Woodsend?= <30940778+bwoodsend@users.noreply.github.com> Date: Fri, 5 Feb 2021 20:54:31 +0000 Subject: [PATCH 471/719] Prevent os.walk() scanning excluded dirs. (#898) --- CHANGELOG | 4 ++++ yapf/yapflib/file_resources.py | 17 ++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index b8906d10c..a681c6b42 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,10 @@ a custom number of blank lines between top-level imports and variable definitions. - Ignore end of line `# copybara:` directives when checking line length. +### Changed +- Do not scan exlcuded directories. Prior versions would scan an exluded + folder then exclude its contents on a file by file basis. Preventing the + folder being scanned is faster. ### Fixed - Exclude directories on Windows. diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 4c6bf38e8..c524c5070 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -167,7 +167,7 @@ def _FindPythonFiles(filenames, recursive, exclude): # TODO(morbo): Look into a version of os.walk that can handle recursion. excluded_dirs = [] - for dirpath, _, filelist in os.walk(filename): + for dirpath, dirnames, filelist in os.walk(filename): if dirpath != '.' and exclude and IsIgnored(dirpath, exclude): excluded_dirs.append(dirpath) continue @@ -179,6 +179,19 @@ def _FindPythonFiles(filenames, recursive, exclude): continue if IsPythonFile(filepath): python_files.append(filepath) + # To prevent it from scanning the contents excluded folders, os.walk() + # lets you amend its list of child dirs `dirnames`. These edits must be + # made in-place instead of creating a modified copy of `dirnames`. + # list.remove() is slow and list.pop() is a headache. Instead clear + # `dirnames` then repopulate it. + dirnames_ = [dirnames.pop(0) for i in range(len(dirnames))] + for dirname in dirnames_: + dir_ = os.path.join(dirpath, dirname) + if IsIgnored(dir_, exclude): + excluded_dirs.append(dir_) + else: + dirnames.append(dirname) + elif os.path.isfile(filename): python_files.append(filename) @@ -187,6 +200,8 @@ def _FindPythonFiles(filenames, recursive, exclude): def IsIgnored(path, exclude): """Return True if filename matches any patterns in exclude.""" + if exclude is None: + return False path = path.lstrip(os.path.sep) while path.startswith('.' + os.path.sep): path = path[2:] From 54e1aaf3ce957bc4da70a2772a9cd352044f4e62 Mon Sep 17 00:00:00 2001 From: hirosassa Date: Sat, 13 Mar 2021 06:31:58 +0900 Subject: [PATCH 472/719] pyproject.toml support (#893) * pyproject.toml support * small refactoring * add error handling * fix document and add CHANGELOG entry * add test for pyproject.toml as config file * add install_requires on setup.cfg * fix test function * import toml conditionally * raise import error --- CHANGELOG | 2 ++ README.rst | 19 +++++++++-------- yapf/__init__.py | 4 ++-- yapf/yapflib/file_resources.py | 22 +++++++++++++++++++- yapf/yapflib/style.py | 35 +++++++++++++++++++++++++++----- yapftests/file_resources_test.py | 15 ++++++++++++++ yapftests/style_test.py | 21 +++++++++++++++++++ 7 files changed, 102 insertions(+), 16 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a681c6b42..79d69ec2b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,8 @@ a custom number of blank lines between top-level imports and variable definitions. - Ignore end of line `# copybara:` directives when checking line length. +- Look at the 'pyproject.toml' file to see if it contains style information for + YAPF. ### Changed - Do not scan exlcuded directories. Prior versions would scan an exluded folder then exclude its contents on a file by file basis. Preventing the diff --git a/README.rst b/README.rst index ac07aee62..5723b150e 100644 --- a/README.rst +++ b/README.rst @@ -113,10 +113,10 @@ Options:: --style STYLE specify formatting style: either a style name (for example "pep8" or "google"), or the name of a file with style settings. The default is pep8 unless a - .style.yapf or setup.cfg file located in the same - directory as the source or one of its parent - directories (for stdin, the current directory is - used). + .style.yapf or setup.cfg or pyproject.toml file + located in the same directory as the source or one of + its parent directories (for stdin, the current + directory is used). --style-help show style settings and exit; this output can be saved to .style.yapf to make your settings permanent --no-local-style don't search for local style definition @@ -198,7 +198,9 @@ YAPF will search for the formatting style in the following manner: directory or one of its parent directories. 3. In the ``[yapf]`` section of a ``setup.cfg`` file in either the current directory or one of its parent directories. -4. In the ``[style]`` section of a ``~/.config/yapf/style`` file in your home +4. In the ``[tool.yapf]`` section of a ``pyproject.toml`` file in either the current + directory or one of its parent directories. +5. In the ``[style]`` section of a ``~/.config/yapf/style`` file in your home directory. If none of those files are found, the default style is used (PEP8). @@ -351,9 +353,10 @@ Options:: --style STYLE specify formatting style: either a style name (for example "pep8" or "google"), or the name of a file with style settings. The default is pep8 unless a - .style.yapf or setup.cfg file located in one of the - parent directories of the source file (or current - directory for stdin) + .style.yapf or setup.cfg or pyproject.toml file + located in the same directory as the source or one of + its parent directories (for stdin, the current + directory is used). --binary BINARY location of binary to use for yapf Knobs diff --git a/yapf/__init__.py b/yapf/__init__.py index 3aca8bdc1..dc5e3919e 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -325,10 +325,10 @@ def _BuildParser(): action='store', help=('specify formatting style: either a style name (for example "pep8" ' 'or "google"), or the name of a file with style settings. The ' - 'default is pep8 unless a %s or %s file located in the same ' + 'default is pep8 unless a %s or %s or %s file located in the same ' 'directory as the source or one of its parent directories ' '(for stdin, the current directory is used).' % - (style.LOCAL_STYLE, style.SETUP_CONFIG))) + (style.LOCAL_STYLE, style.SETUP_CONFIG, style.PYPROJECT_TOML))) parser.add_argument( '--style-help', action='store_true', diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index c524c5070..84a8a5427 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -67,7 +67,7 @@ def GetExcludePatternsForDir(dirname): def GetDefaultStyleForDir(dirname, default_style=style.DEFAULT_STYLE): """Return default style name for a given directory. - Looks for .style.yapf or setup.cfg in the parent directories. + Looks for .style.yapf or setup.cfg or pyproject.toml in the parent directories. Arguments: dirname: (unicode) The name of the directory. @@ -97,6 +97,26 @@ def GetDefaultStyleForDir(dirname, default_style=style.DEFAULT_STYLE): if config.has_section('yapf'): return config_file + # See if we have a pyproject.toml file with a '[tool.yapf]' section. + config_file = os.path.join(dirname, style.PYPROJECT_TOML) + try: + fd = open(config_file) + except IOError: + pass # It's okay if it's not there. + else: + with fd: + try: + import toml + except ImportError: + raise errors.YapfError( + "toml package is needed for using pyproject.toml as a configuration file" + ) + + pyproject_toml = toml.load(config_file) + style_dict = pyproject_toml.get('tool', {}).get('yapf', None) + if style_dict is not None: + return config_file + if (not dirname or not os.path.basename(dirname) or dirname == os.path.abspath(os.path.sep)): break diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index b01c2317a..6bd2372f7 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -742,19 +742,40 @@ def _CreateConfigParserFromConfigFile(config_filename): '"{0}" is not a valid style or file path'.format(config_filename)) with open(config_filename) as style_file: config = py3compat.ConfigParser() + if config_filename.endswith(PYPROJECT_TOML): + try: + import toml + except ImportError: + raise errors.YapfError( + "toml package is needed for using pyproject.toml as a configuration file" + ) + + pyproject_toml = toml.load(style_file) + style_dict = pyproject_toml.get("tool", {}).get("yapf", None) + if style_dict is None: + raise StyleConfigError( + 'Unable to find section [tool.yapf] in {0}'.format(config_filename)) + config.add_section('style') + for k, v in style_dict.items(): + config.set('style', k, str(v)) + return config + config.read_file(style_file) if config_filename.endswith(SETUP_CONFIG): if not config.has_section('yapf'): raise StyleConfigError( 'Unable to find section [yapf] in {0}'.format(config_filename)) - elif config_filename.endswith(LOCAL_STYLE): - if not config.has_section('style'): - raise StyleConfigError( - 'Unable to find section [style] in {0}'.format(config_filename)) - else: + return config + + if config_filename.endswith(LOCAL_STYLE): if not config.has_section('style'): raise StyleConfigError( 'Unable to find section [style] in {0}'.format(config_filename)) + return config + + if not config.has_section('style'): + raise StyleConfigError( + 'Unable to find section [style] in {0}'.format(config_filename)) return config @@ -817,6 +838,10 @@ def _CreateStyleFromConfigParser(config): # specified in the '[yapf]' section. SETUP_CONFIG = 'setup.cfg' +# Style definition by local pyproject.toml file. Style should be specified +# in the '[tool.yapf]' section. +PYPROJECT_TOML = 'pyproject.toml' + # TODO(eliben): For now we're preserving the global presence of a style dict. # Refactor this so that the style is passed around through yapf rather than # being global. diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 2bf68ab1c..ba528844a 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -117,6 +117,21 @@ def test_setup_config(self): self.assertEqual(setup_config, file_resources.GetDefaultStyleForDir(test_dir)) + def test_pyproject_toml(self): + # An empty pyproject.toml file should not be used + pyproject_toml = os.path.join(self.test_tmpdir, 'pyproject.toml') + open(pyproject_toml, 'w').close() + + test_dir = os.path.join(self.test_tmpdir, 'dir1') + style_name = file_resources.GetDefaultStyleForDir(test_dir) + self.assertEqual(style_name, 'pep8') + + # One with a '[tool.yapf]' section should be used + with open(pyproject_toml, 'w') as f: + f.write('[tool.yapf]\n') + self.assertEqual(pyproject_toml, + file_resources.GetDefaultStyleForDir(test_dir)) + def test_local_style_at_root(self): # Test behavior of files located on the root, and under root. rootdir = os.path.abspath(os.path.sep) diff --git a/yapftests/style_test.py b/yapftests/style_test.py index a9c478daa..11da92559 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -14,6 +14,7 @@ # limitations under the License. """Tests for yapf.style.""" +import os import shutil import tempfile import textwrap @@ -226,6 +227,26 @@ def testErrorUnknownStyleOption(self): 'Unknown style option'): style.CreateStyleFromConfig(filepath) + def testPyprojectTomlNoYapfSection(self): + filepath = os.path.join(self.test_tmpdir, 'pyproject.toml') + _ = open(filepath, 'w') + with self.assertRaisesRegexp(style.StyleConfigError, + 'Unable to find section'): + style.CreateStyleFromConfig(filepath) + + def testPyprojectTomlParseYapfSection(self): + cfg = textwrap.dedent(u'''\ + [tool.yapf] + based_on_style = "pep8" + continuation_indent_width = 40 + ''') + filepath = os.path.join(self.test_tmpdir, 'pyproject.toml') + with open(filepath, 'w') as f: + f.write(cfg) + cfg = style.CreateStyleFromConfig(filepath) + self.assertTrue(_LooksLikePEP8Style(cfg)) + self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 40) + class StyleFromDict(unittest.TestCase): From d670905df6fbc23a6905254d37589bd85708993f Mon Sep 17 00:00:00 2001 From: Phoenix Meadowlark Date: Fri, 12 Mar 2021 13:33:37 -0800 Subject: [PATCH 473/719] Elaborate on based_on_style origins and use cases. (#896) Several Google OSS projects I have contributed to have mistakenly assumed that they should use the `"google"` style with `indent_width` manually set to `2`. Since Google does not follow the (public) Google Python Style Guide however, this creates numerous diffs between the internal formatter and `yapf --style=google`. `yapf --style=yapf` does not perfectly match the internal formatter (e.g. for docstrings), but it is much closer than `yapf --style={based_on_style: google, indent_width: 2}`, particularly since it sets `SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=True`. --- README.rst | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 5723b150e..e441317e6 100644 --- a/README.rst +++ b/README.rst @@ -176,10 +176,18 @@ with a ``[yapf]`` heading. For example: The ``based_on_style`` setting determines which of the predefined styles this custom style is based on (think of it like subclassing). Four -styles are predefined: ``pep8`` (default), ``google``, ``yapf``, and ``facebook`` -(see ``_STYLE_NAME_TO_FACTORY`` in style.py_). +styles are predefined: -.. _style.py: https://github.com/google/yapf/blob/main/yapf/yapflib/style.py#L445 +- ``pep8`` (default) +- ``google`` (based off of the `Google Python Style Guide`_) +- ``yapf`` (for use with Google open source projects) +- ``facebook`` + +.. _`Google Python Style Guide`: https://github.com/google/styleguide/blob/gh-pages/pyguide.md + +See ``_STYLE_NAME_TO_FACTORY`` in style.py_ for details. + +.. _style.py: https://github.com/google/yapf/blob/main/yapf/yapflib/style.py It's also possible to do the same on the command line with a dictionary. For example: From 5c34d5f6d3efe17e869b71bdeca1278c0e5ca953 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 12 Mar 2021 13:35:26 -0800 Subject: [PATCH 474/719] Reformat --- yapftests/style_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 11da92559..2b17b44bf 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -242,7 +242,7 @@ def testPyprojectTomlParseYapfSection(self): ''') filepath = os.path.join(self.test_tmpdir, 'pyproject.toml') with open(filepath, 'w') as f: - f.write(cfg) + f.write(cfg) cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikePEP8Style(cfg)) self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 40) From 3af4e89ec02ee55c0bffab4d04ee62076c14cb4d Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 12 Mar 2021 13:40:09 -0800 Subject: [PATCH 475/719] Don't fail if we don't have "toml". --- yapftests/file_resources_test.py | 5 +++++ yapftests/style_test.py | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index ba528844a..a4b123054 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -119,6 +119,11 @@ def test_setup_config(self): def test_pyproject_toml(self): # An empty pyproject.toml file should not be used + try: + import toml + except ImportError: + return + pyproject_toml = os.path.join(self.test_tmpdir, 'pyproject.toml') open(pyproject_toml, 'w').close() diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 2b17b44bf..2fd3f2d0e 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -228,6 +228,11 @@ def testErrorUnknownStyleOption(self): style.CreateStyleFromConfig(filepath) def testPyprojectTomlNoYapfSection(self): + try: + import toml + except ImportError: + return + filepath = os.path.join(self.test_tmpdir, 'pyproject.toml') _ = open(filepath, 'w') with self.assertRaisesRegexp(style.StyleConfigError, @@ -235,6 +240,11 @@ def testPyprojectTomlNoYapfSection(self): style.CreateStyleFromConfig(filepath) def testPyprojectTomlParseYapfSection(self): + try: + import toml + except ImportError: + return + cfg = textwrap.dedent(u'''\ [tool.yapf] based_on_style = "pep8" From 87452ca59b6a2e167bb45b796010d6607c3fbcf5 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 12 Mar 2021 13:42:14 -0800 Subject: [PATCH 476/719] Bump version to 0.31.0 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 79d69ec2b..afe87185b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.31.0] UNRELEASED +## [0.31.0] 2021-03-14 ### Added - Renamed 'master' brannch to 'main'. - Add 'BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES' to support setting diff --git a/yapf/__init__.py b/yapf/__init__.py index dc5e3919e..a70db8487 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -40,7 +40,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.30.0' +__version__ = '0.31.0' def main(argv): From 14800c83373845551b22233fbbf93debc501428b Mon Sep 17 00:00:00 2001 From: Misha Wolfson Date: Mon, 26 Apr 2021 13:57:19 -0400 Subject: [PATCH 477/719] Automatically find valid python packages for installation (#921) Fixes #920 --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index fe2a0469a..70e57da68 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ import sys import unittest -from setuptools import setup, Command +from setuptools import find_packages, setup, Command import yapf @@ -49,7 +49,7 @@ def run(self): author='Google Inc.', maintainer='Bill Wendling', maintainer_email='morbo@google.com', - packages=['yapf', 'yapf.yapflib', 'yapftests'], + packages=find_packages('.'), classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Console', From 2cfc7b9626e1ad52103099aa0b3364fe69b054dd Mon Sep 17 00:00:00 2001 From: Matthew Suozzo Date: Tue, 4 May 2021 13:59:56 -0600 Subject: [PATCH 478/719] Avoid expensive duplicate __hash__ call. (#923) Before: https://pasteboard.co/K0m3X1s.png After: https://pasteboard.co/K0m47fR.png --- yapf/yapflib/reformatter.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 60386e51d..c1d51f3c7 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -491,10 +491,13 @@ def _AnalyzeSolutionSpace(initial_state): if count > 10000: node.state.ignore_stack_for_comparison = True - if node.state in seen: - continue - + # Unconditionally add the state and check if it was present to avoid having to + # hash it twice in the common case (state hashing is expensive). + before_seen_count = len(seen) seen.add(node.state) + # If seen didn't change size, the state was already present. + if before_seen_count == len(seen): + continue # FIXME(morbo): Add a 'decision' element? From d2d88e1fd2918d1477ab32016632ebdfa7cb5791 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 29 May 2021 21:41:42 -0700 Subject: [PATCH 479/719] Don't modify blank lines if they're marked as disabled. Closes #913 --- yapf/yapflib/reformatter.py | 10 ++++---- yapf/yapflib/yapf_api.py | 7 +++--- yapftests/blank_line_calculator_test.py | 6 ++--- yapftests/yapf_test.py | 32 ++++++++++++++++++++----- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index c1d51f3c7..d07be842f 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -119,14 +119,14 @@ def _RetainRequiredVerticalSpacing(cur_uwline, prev_uwline, lines): if prev_uwline is not None: prev_tok = prev_uwline.last + if cur_uwline.disable: + # After the first token we are acting on a single line. So if it is + # disabled we must not reformat. + lines = set() + for cur_tok in cur_uwline.tokens: _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines) - prev_tok = cur_tok - if cur_uwline.disable: - # After the first token we are acting on a single line. So if it is - # disabled we must not reformat. - lines = set() def _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines): diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index dde1df931..fdcce3069 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -269,10 +269,9 @@ def _MarkLinesToFormat(uwlines, lines): index += 1 while index < len(uwlines): uwline = uwlines[index] - if uwline.is_comment and _EnableYAPF(uwline.first.value.strip()): - if not re.search(DISABLE_PATTERN, - uwline.first.value.strip().split('\n')[-1].strip(), - re.IGNORECASE): + line = uwline.first.value.strip() + if uwline.is_comment and _EnableYAPF(line): + if not _DisableYAPF(line): break uwline.disable = True index += 1 diff --git a/yapftests/blank_line_calculator_test.py b/yapftests/blank_line_calculator_test.py index 1ec0a5e59..193f41930 100644 --- a/yapftests/blank_line_calculator_test.py +++ b/yapftests/blank_line_calculator_test.py @@ -300,15 +300,12 @@ def A(): def B(): # 4 pass # 5 - def C(): pass def D(): # 9 pass # 10 - - def E(): pass """) @@ -375,6 +372,8 @@ def B(): # 6 pass # 7 + + def C(): pass """) @@ -410,6 +409,7 @@ def B(): # 7 + def C(): pass """) diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index e3e3df38e..dc0d0a5e6 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -881,8 +881,6 @@ def f(): """) expected_formatted_code = textwrap.dedent("""\ a = line_to_format - - def f(): x = y + 42; z = n * 42 if True: a += 1 ; b += 1 ; c += 1 @@ -905,8 +903,6 @@ def f(): ''') expected_formatted_code = textwrap.dedent('''\ foo = 42 - - def f(): email_text += """This is a really long docstring that goes over the column limit and is multi-line.

Czar: """+despot["Nicholas"]+"""
@@ -1031,6 +1027,7 @@ class A(object): def aaaaaaaaaaaaa(self): pass + def bbbbbbbbbbbbb(self): # 5 pass """) @@ -1170,13 +1167,12 @@ def testCoalesceBrackets(self): def testPseudoParenSpaces(self): unformatted_code = textwrap.dedent("""\ - def foo(): + def foo(): def bar(): return {msg_id: author for author, msg_id in reader} """) expected_formatted_code = textwrap.dedent("""\ def foo(): - def bar(): return {msg_id: author for author, msg_id in reader} """) @@ -1482,6 +1478,30 @@ def testSpacingBeforeCommentsInDicts(self): expected_formatted_code, extra_options=['--style', 'yapf', '--lines', '1-1']) + def testDisableWithLinesOption(self): + unformatted_code = textwrap.dedent("""\ + # yapf_lines_bug.py + # yapf: disable + def outer_func(): + def inner_func(): + return + return + # yapf: enable + """) + expected_formatted_code = textwrap.dedent("""\ + # yapf_lines_bug.py + # yapf: disable + def outer_func(): + def inner_func(): + return + return + # yapf: enable + """) + self.assertYapfReformats( + unformatted_code, + expected_formatted_code, + extra_options=['--lines', '1-8']) + @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testNoSpacesAroundBinaryOperators(self): unformatted_code = """\ From 78a3c9dfd889210c571797bc2018dbc4c6721312 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 29 May 2021 22:53:14 -0700 Subject: [PATCH 480/719] Enforce space between colon and elipses Closes #897 --- yapf/yapflib/unwrapped_line.py | 3 +++ yapftests/reformatter_pep8_test.py | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 475bd6e0e..09863147c 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -323,6 +323,9 @@ def _SpaceRequiredBetween(left, right, is_line_disabled): format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN not in left.subtypes): # Space between equal and '.' as in "X = ...". return True + if lval == ':' and rval == '.': + # Space between : and ... + return True if ((right.is_keyword or right.is_name) and (left.is_keyword or left.is_name)): # Don't merge two keywords/identifiers. diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index bdd074a7f..a5301f1fc 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -698,6 +698,17 @@ def _(): reformatted_code = reformatter.Reformat(uwlines) self.assertCodeEqual(expected_formatted_code, reformatted_code) + @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') + def testSpaceBetweenColonAndElipses(self): + style.SetGlobalStyle(style.CreatePEP8Style()) + code = textwrap.dedent("""\ + class MyClass(ABC): + + place: ... + """) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines, verify=False)) + class TestsForSpacesInsideBrackets(yapf_test_helper.YAPFTest): """Test the SPACE_INSIDE_BRACKETS style option.""" From ed6b56933d822c56326fe58b3564e68e8da56154 Mon Sep 17 00:00:00 2001 From: Keshav <56075233+keshavgbpecdelhi@users.noreply.github.com> Date: Tue, 13 Jul 2021 06:28:19 +0530 Subject: [PATCH 481/719] Reformatted source (#837) --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index e441317e6..5a099cbb3 100644 --- a/README.rst +++ b/README.rst @@ -293,7 +293,7 @@ than a whole file. 'def g():\n a = 1\n b = 2\n return a==b\n' A ``print_diff`` (bool): Instead of returning the reformatted source, return a -diff that turns the formatted source into reformatter source. +diff that turns the formatted source into reformatted source. .. code-block:: python From 1acfa73cb06544e08eabc99b04d47c31a5cd6511 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 12 Jul 2021 17:59:08 -0700 Subject: [PATCH 482/719] Fix README to match the API for FormatCode() and FormatFile() (#918) Closes #916 --- README.rst | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index 5a099cbb3..56fb9d632 100644 --- a/README.rst +++ b/README.rst @@ -270,8 +270,11 @@ share several arguments which are described below: >>> from yapf.yapflib.yapf_api import FormatCode # reformat a string of code - >>> FormatCode("f ( a = 1, b = 2 )") + >>> formatted_code, changed = FormatCode("f ( a = 1, b = 2 )") + >>> formatted_code 'f(a=1, b=2)\n' + >>> changed + True A ``style_config`` argument: Either a style name or a path to a file that contains formatting style settings. If None is specified, use the default style @@ -279,7 +282,7 @@ as set in ``style.DEFAULT_STYLE_FACTORY``. .. code-block:: python - >>> FormatCode("def g():\n return True", style_config='pep8') + >>> FormatCode("def g():\n return True", style_config='pep8')[0] 'def g():\n return True\n' A ``lines`` argument: A list of tuples of lines (ints), [start, end], @@ -289,7 +292,7 @@ than a whole file. .. code-block:: python - >>> FormatCode("def g( ):\n a=1\n b = 2\n return a==b", lines=[(1, 1), (2, 3)]) + >>> FormatCode("def g( ):\n a=1\n b = 2\n return a==b", lines=[(1, 1), (2, 3)])[0] 'def g():\n a = 1\n b = 2\n return a==b\n' A ``print_diff`` (bool): Instead of returning the reformatted source, return a @@ -297,7 +300,7 @@ diff that turns the formatted source into reformatted source. .. code-block:: python - >>> print(FormatCode("a==b", filename="foo.py", print_diff=True)) + >>> print(FormatCode("a==b", filename="foo.py", print_diff=True)[0]) --- foo.py (original) +++ foo.py (reformatted) @@ -1 +1 @@ @@ -316,14 +319,19 @@ the diff, the default is ````. >>> print(open("foo.py").read()) # contents of file a==b - >>> FormatFile("foo.py") - ('a == b\n', 'utf-8') + >>> reformatted_code, encoding, changed = FormatFile("foo.py") + >>> formatted_code + 'a == b\n' + >>> encoding + 'utf-8' + >>> changed + True The ``in_place`` argument saves the reformatted code back to the file: .. code-block:: python - >>> FormatFile("foo.py", in_place=True) + >>> FormatFile("foo.py", in_place=True)[:2] (None, 'utf-8') >>> print(open("foo.py").read()) # contents of file (now fixed) From 4f615ba3aff69bd04ecee125fec1830539137bf3 Mon Sep 17 00:00:00 2001 From: "James D. Lin" Date: Mon, 12 Jul 2021 17:59:53 -0700 Subject: [PATCH 483/719] Try to clarify the SPLIT_ALL_COMMA_SEPARATED_VALUES knob (#926) "... split such that all elements are on a single line." could be interpreted to mean that all elements will be combined into a single line, but the knob really means that each element will appear on a separate line. --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 56fb9d632..1bc7b58bc 100644 --- a/README.rst +++ b/README.rst @@ -712,8 +712,8 @@ Knobs ``SPLIT_ALL_COMMA_SEPARATED_VALUES`` If a comma separated list (``dict``, ``list``, ``tuple``, or function - ``def``) is on a line that is too long, split such that all elements - are on a single line. + ``def``) is on a line that is too long, split such that each element + is on a separate line. ``SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES`` Variation on ``SPLIT_ALL_COMMA_SEPARATED_VALUES`` in which, if a From 418df8d2214651b76b5f1129c1c70b7842c4183c Mon Sep 17 00:00:00 2001 From: hirosassa Date: Tue, 13 Jul 2021 10:00:32 +0900 Subject: [PATCH 484/719] support ignore config in pyproject.toml (#937) * support ignore config in pyproject.toml * add doc in readme * add tests * changelog --- CHANGELOG | 5 ++ README.rst | 15 ++++-- yapf/yapflib/file_resources.py | 44 +++++++++++++++-- yapftests/file_resources_test.py | 81 ++++++++++++++++++++++++++++++-- 4 files changed, 132 insertions(+), 13 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index afe87185b..a35ce689a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,11 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.32.0] UNRELEASED +### Added +- Look at the 'pyproject.toml' file to see if it contains ignore file information + for YAPF. + ## [0.31.0] 2021-03-14 ### Added - Renamed 'master' brannch to 'main'. diff --git a/README.rst b/README.rst index 1bc7b58bc..b381c4de0 100644 --- a/README.rst +++ b/README.rst @@ -136,12 +136,12 @@ otherwise (including program error). You can use this in a CI workflow to test t has been YAPF-formatted. --------------------------------------------- -Excluding files from formatting (.yapfignore) +Excluding files from formatting (.yapfignore or pyproject.toml) --------------------------------------------- In addition to exclude patterns provided on commandline, YAPF looks for additional -patterns specified in a file named ``.yapfignore`` located in the working directory from -which YAPF is invoked. +patterns specified in a file named ``.yapfignore`` or ``pyproject.toml`` located in the +working directory from which YAPF is invoked. ``.yapfignore``'s syntax is similar to UNIX's filename pattern matching:: @@ -152,6 +152,15 @@ which YAPF is invoked. Note that no entry should begin with `./`. +If you use ``pyproject.toml``, exclude patterns are specified by ``ignore_pattens`` key +in ``[tool.yapfignore]`` section. For example: + +.. code-block:: ini + [tool.yapfignore] + ignore_patterns=""" + temp/**/*.py + temp2/*.py + """ Formatting style ================ diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 84a8a5427..4c0fbf250 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -32,10 +32,9 @@ CRLF = '\r\n' -def _GetExcludePatternsFromFile(filename): - """Get a list of file patterns to ignore.""" +def _GetExcludePatternsFromYapfIgnore(filename): + """Get a list of file patterns to ignore from .yapfignore.""" ignore_patterns = [] - # See if we have a .yapfignore file. if os.path.isfile(filename) and os.access(filename, os.R_OK): with open(filename, 'r') as fd: for line in fd: @@ -48,6 +47,33 @@ def _GetExcludePatternsFromFile(filename): return ignore_patterns +def _GetExcludePatternsFromPyprojectToml(filename): + """Get a list of file patterns to ignore from pyproject.toml.""" + ignore_patterns = [] + try: + import toml + except ImportError: + raise errors.YapfError( + "toml package is needed for using pyproject.toml as a configuration file" + ) + + pyproject_toml = toml.load(filename) + if os.path.isfile(filename) and os.access(filename, os.R_OK): + excludes = pyproject_toml.get('tool', + {}).get('yapfignore', + {}).get('ignore_patterns', None) + if excludes is None: + return [] + + for line in excludes.split('\n'): + if line.strip() and not line.startswith('#'): + ignore_patterns.append(line.strip()) + if any(e.startswith('./') for e in ignore_patterns): + raise errors.YapfError('path in pyproject.toml should not start with ./') + + return ignore_patterns + + def GetExcludePatternsForDir(dirname): """Return patterns of files to exclude from ignorefile in a given directory. @@ -60,8 +86,16 @@ def GetExcludePatternsForDir(dirname): A List of file patterns to exclude if ignore file is found, otherwise empty List. """ - ignore_file = os.path.join(dirname, '.yapfignore') - return _GetExcludePatternsFromFile(ignore_file) + ignore_patterns = [] + + yapfignore_file = os.path.join(dirname, '.yapfignore') + if os.path.exists(yapfignore_file): + ignore_patterns += _GetExcludePatternsFromYapfIgnore(yapfignore_file) + + pyproject_toml_file = os.path.join(dirname, 'pyproject.toml') + if os.path.exists(pyproject_toml_file): + ignore_patterns += _GetExcludePatternsFromPyprojectToml(pyproject_toml_file) + return ignore_patterns def GetDefaultStyleForDir(dirname, default_style=style.DEFAULT_STYLE): diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index a4b123054..6afd8a443 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -54,16 +54,87 @@ def setUp(self): # pylint: disable=g-missing-super-call def tearDown(self): # pylint: disable=g-missing-super-call shutil.rmtree(self.test_tmpdir) - def _make_test_dir(self, name): - fullpath = os.path.normpath(os.path.join(self.test_tmpdir, name)) - os.makedirs(fullpath) - return fullpath + def test_get_exclude_file_patterns_from_yapfignore(self): + local_ignore_file = os.path.join(self.test_tmpdir, '.yapfignore') + ignore_patterns = ['temp/**/*.py', 'temp2/*.py'] + with open(local_ignore_file, 'w') as f: + f.writelines('\n'.join(ignore_patterns)) - def test_get_exclude_file_patterns(self): + self.assertEqual( + sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)), + sorted(ignore_patterns)) + + def test_get_exclude_file_patterns_from_yapfignore_with_wrong_syntax(self): local_ignore_file = os.path.join(self.test_tmpdir, '.yapfignore') + ignore_patterns = ['temp/**/*.py', './wrong/syntax/*.py'] + with open(local_ignore_file, 'w') as f: + f.writelines('\n'.join(ignore_patterns)) + + with self.assertRaises(errors.YapfError): + file_resources.GetExcludePatternsForDir(self.test_tmpdir) + + def test_get_exclude_file_patterns_from_pyproject(self): + try: + import toml + except ImportError: + return + local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') ignore_patterns = ['temp/**/*.py', 'temp2/*.py'] with open(local_ignore_file, 'w') as f: + f.write('[tool.yapfignore]\n') + f.write('ignore_patterns="""') + f.writelines('\n'.join(ignore_patterns)) + f.write('"""') + + self.assertEqual( + sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)), + sorted(ignore_patterns)) + + def test_get_exclude_file_patterns_from_pyproject_with_wrong_syntax(self): + try: + import toml + except ImportError: + return + local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') + ignore_patterns = ['temp/**/*.py', './wrong/syntax/*.py'] + with open(local_ignore_file, 'w') as f: + f.write('[tool.yapfignore]\n') + f.write('ignore_patterns="""') f.writelines('\n'.join(ignore_patterns)) + f.write('"""') + + with self.assertRaises(errors.YapfError): + file_resources.GetExcludePatternsForDir(self.test_tmpdir) + + def test_get_exclude_file_patterns_from_pyproject_no_ignore_section(self): + try: + import toml + except ImportError: + return + local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') + ignore_patterns = [] + open(local_ignore_file, 'w').close() + + self.assertEqual( + sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)), + sorted(ignore_patterns)) + + def test_get_exclude_file_patterns_from_pyproject_ignore_section_empty(self): + try: + import toml + except ImportError: + return + local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') + ignore_patterns = [] + with open(local_ignore_file, 'w') as f: + f.write('[tool.yapfignore]\n') + + self.assertEqual( + sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)), + sorted(ignore_patterns)) + + def test_get_exclude_file_patterns_with_no_config_files(self): + ignore_patterns = [] self.assertEqual( sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)), From f8903965002cd02756981ad8eff5f77798356a28 Mon Sep 17 00:00:00 2001 From: Almaz Date: Tue, 13 Jul 2021 04:00:56 +0300 Subject: [PATCH 485/719] Merge isinstance calls (#938) --- yapf/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index a70db8487..22adc306d 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -148,7 +148,7 @@ def _PrintHelp(args): for line in docstring.splitlines(): print('#', line and ' ' or '', line, sep='') option_value = style.Get(option) - if isinstance(option_value, set) or isinstance(option_value, list): + if isinstance(option_value, (set, list)): option_value = ', '.join(map(str, option_value)) print(option.lower(), '=', option_value, sep='') print() From 2ca3517934b19459f9a77b0f38e31df5ac682c7a Mon Sep 17 00:00:00 2001 From: Almaz Date: Tue, 13 Jul 2021 04:01:34 +0300 Subject: [PATCH 486/719] Replace if statement with if expression (#939) Replace if statement with if expression --- yapf/yapflib/format_decision_state.py | 10 ++-------- yapf/yapflib/object_state.py | 5 +---- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 164818e91..59f62014c 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -1184,10 +1184,7 @@ def _IsSingleElementTuple(token): while token != close: if token.value == ',': num_commas += 1 - if token.OpensScope(): - token = token.matching_bracket - else: - token = token.next_token + token = token.matching_bracket if token.OpensScope() else token.next_token return num_commas == 1 @@ -1198,10 +1195,7 @@ def _ScopeHasNoCommas(token): while token != close: if token.value == ',': return False - if token.OpensScope(): - token = token.matching_bracket - else: - token = token.next_token + token = token.matching_bracket if token.OpensScope() else token.next_token return True diff --git a/yapf/yapflib/object_state.py b/yapf/yapflib/object_state.py index 4ae8eaeb6..f640db5eb 100644 --- a/yapf/yapflib/object_state.py +++ b/yapf/yapflib/object_state.py @@ -212,10 +212,7 @@ def has_default_value(self): while tok != self.last_token: if format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in tok.subtypes: return True - if tok.OpensScope(): - tok = tok.matching_bracket - else: - tok = tok.next_token + tok = tok.matching_bracket if tok.OpensScope() else tok.next_token return False def Clone(self): From 836890d7cff75ad681afdb214064d908d72ef411 Mon Sep 17 00:00:00 2001 From: Almaz Date: Tue, 13 Jul 2021 04:02:49 +0300 Subject: [PATCH 487/719] Replace while with for (#940) --- yapf/yapflib/reformatter.py | 5 +---- yapf/yapflib/subtype_assigner.py | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index d07be842f..ff84de930 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -224,13 +224,10 @@ def _LineContainsI18n(uwline): if style.Get('I18N_FUNCTION_CALL'): length = len(uwline.tokens) - index = 0 - while index < length - 1: + for index in range(length - 1): if (uwline.tokens[index + 1].value == '(' and uwline.tokens[index].value in style.Get('I18N_FUNCTION_CALL')): return True - index += 1 - return False diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 0fa2d9663..1a54522e9 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -307,13 +307,10 @@ def Visit_typedargslist(self, node): # pylint: disable=invalid-name _AppendLastLeafTokenSubtype(node.children[-1], format_token.Subtype.PARAMETER_STOP) - i = 1 tname = pytree_utils.NodeName(node.children[0]) == 'tname' - while i < len(node.children): + for i in range(1, len(node.children)): prev_child = node.children[i - 1] child = node.children[i] - i += 1 - if pytree_utils.NodeName(prev_child) == 'COMMA': _AppendFirstLeafTokenSubtype(child, format_token.Subtype.PARAMETER_START) From 7cd934a5b7abd10b2857b57b59e08cfb8c8b0513 Mon Sep 17 00:00:00 2001 From: Almaz Date: Tue, 13 Jul 2021 04:03:15 +0300 Subject: [PATCH 488/719] Replace multiple comparisons with in operator (#941) Replace multiple comparisons with in operator --- yapf/yapflib/reformatter.py | 3 +-- yapf/yapflib/unwrapped_line.py | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index ff84de930..c5282b1ae 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -648,8 +648,7 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, return NO_BLANK_LINES if first_token.is_name and not indent_depth: - if (prev_uwline.first.value == 'from' or - prev_uwline.first.value == 'import'): + if prev_uwline.first.value in {'from', 'import'}: # Support custom number of blank lines between top-level imports and # variable definitions. return 1 + style.Get( diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 09863147c..0bc537c3d 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -405,10 +405,10 @@ def _SpaceRequiredBetween(left, right, is_line_disabled): return False if left.is_keyword and rval == '.': # Add space between keywords and dots. - return lval != 'None' and lval != 'print' + return lval not in {'None', 'print'} if lval == '.' and right.is_keyword: # Add space between keywords and dots. - return rval != 'None' and rval != 'print' + return rval not in {'None', 'print'} if lval == '.' or rval == '.': # Don't place spaces between dots. return False From 27de2d8eaec023d0efebd6d7b0ce6e4854cd662f Mon Sep 17 00:00:00 2001 From: Almaz Date: Tue, 13 Jul 2021 04:04:00 +0300 Subject: [PATCH 489/719] Merge else clause's nested if statement into elif (#942) --- yapf/third_party/yapf_diff/yapf_diff.py | 5 ++--- yapf/yapflib/reformatter.py | 26 ++++++++++++------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/yapf/third_party/yapf_diff/yapf_diff.py b/yapf/third_party/yapf_diff/yapf_diff.py index 337723166..810a6a2d4 100644 --- a/yapf/third_party/yapf_diff/yapf_diff.py +++ b/yapf/third_party/yapf_diff/yapf_diff.py @@ -95,9 +95,8 @@ def main(): if args.regex is not None: if not re.match('^%s$' % args.regex, filename): continue - else: - if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE): - continue + elif not re.match('^%s$' % args.iregex, filename, re.IGNORECASE): + continue match = re.search(r'^@@.*\+(\d+)(,(\d+))?', line) if match: diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index c5282b1ae..5695ed917 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -90,15 +90,14 @@ def Reformat(uwlines, verify=False, lines=None): while state.next_token: state.AddTokenToState(newline=False, dry_run=False) - else: - if not _AnalyzeSolutionSpace(state): - # Failsafe mode. If there isn't a solution to the line, then just emit - # it as is. - state = format_decision_state.FormatDecisionState(uwline, indent_amt) - state.MoveStateToNextToken() - _RetainHorizontalSpacing(uwline) - _RetainRequiredVerticalSpacing(uwline, prev_uwline, None) - _EmitLineUnformatted(state) + elif not _AnalyzeSolutionSpace(state): + # Failsafe mode. If there isn't a solution to the line, then just emit + # it as is. + state = format_decision_state.FormatDecisionState(uwline, indent_amt) + state.MoveStateToNextToken() + _RetainHorizontalSpacing(uwline) + _RetainRequiredVerticalSpacing(uwline, prev_uwline, None) + _EmitLineUnformatted(state) final_lines.append(uwline) prev_uwline = uwline @@ -404,12 +403,11 @@ def _FormatFinalLines(final_lines, verify): if not tok.is_pseudo_paren: formatted_line.append(tok.formatted_whitespace_prefix) formatted_line.append(tok.value) - else: - if (not tok.next_token.whitespace_prefix.startswith('\n') and + elif (not tok.next_token.whitespace_prefix.startswith('\n') and not tok.next_token.whitespace_prefix.startswith(' ')): - if (tok.previous_token.value == ':' or - tok.next_token.value not in ',}])'): - formatted_line.append(' ') + if (tok.previous_token.value == ':' or + tok.next_token.value not in ',}])'): + formatted_line.append(' ') formatted_code.append(''.join(formatted_line)) if verify: From 66106da7c1912123d5588c8b5e27a5fcba73cf08 Mon Sep 17 00:00:00 2001 From: Almaz Date: Tue, 13 Jul 2021 04:04:41 +0300 Subject: [PATCH 490/719] Improve comprehensions (#943) --- yapf/yapflib/style.py | 2 +- yapf/yapflib/unwrapped_line.py | 2 +- yapf/yapflib/yapf_api.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 6bd2372f7..3d2710923 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -568,7 +568,7 @@ def _StringSetConverter(s): """Option value converter for a comma-separated set of strings.""" if len(s) > 2 and s[0] in '"\'': s = s[1:-1] - return set(part.strip() for part in s.split(',')) + return {part.strip() for part in s.split(',')} def _BoolConverter(s): diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 0bc537c3d..b49fefeae 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -184,7 +184,7 @@ def __str__(self): # pragma: no cover def __repr__(self): # pragma: no cover tokens_repr = ','.join( - ['{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens]) + '{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens) return 'UnwrappedLine(depth={0}, tokens=[{1}])'.format( self.depth, tokens_repr) diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index fdcce3069..efa1a7918 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -100,7 +100,7 @@ def FormatFile(filename, verify=verify) if reformatted_source.rstrip('\n'): lines = reformatted_source.rstrip('\n').split('\n') - reformatted_source = newline.join(line for line in lines) + newline + reformatted_source = newline.join(iter(lines)) + newline if in_place: if original_source and original_source != reformatted_source: file_resources.WriteReformattedCode(filename, reformatted_source, From e4663fd05a95c2e89a3b59a3a02f13e0a436f053 Mon Sep 17 00:00:00 2001 From: hirosassa Date: Mon, 19 Jul 2021 10:17:12 +0900 Subject: [PATCH 491/719] change ignore config format for pyproject.toml (#946) --- README.rst | 9 +++++---- yapf/yapflib/file_resources.py | 18 ++++++------------ yapftests/file_resources_test.py | 12 ++++++------ 3 files changed, 17 insertions(+), 22 deletions(-) diff --git a/README.rst b/README.rst index b381c4de0..0b8a83e46 100644 --- a/README.rst +++ b/README.rst @@ -156,11 +156,12 @@ If you use ``pyproject.toml``, exclude patterns are specified by ``ignore_patten in ``[tool.yapfignore]`` section. For example: .. code-block:: ini + [tool.yapfignore] - ignore_patterns=""" - temp/**/*.py - temp2/*.py - """ + ignore_patterns = [ + "temp/**/*.py", + "temp2/*.py" + ] Formatting style ================ diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 4c0fbf250..1c405a2a1 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -57,19 +57,13 @@ def _GetExcludePatternsFromPyprojectToml(filename): "toml package is needed for using pyproject.toml as a configuration file" ) - pyproject_toml = toml.load(filename) if os.path.isfile(filename) and os.access(filename, os.R_OK): - excludes = pyproject_toml.get('tool', - {}).get('yapfignore', - {}).get('ignore_patterns', None) - if excludes is None: - return [] - - for line in excludes.split('\n'): - if line.strip() and not line.startswith('#'): - ignore_patterns.append(line.strip()) - if any(e.startswith('./') for e in ignore_patterns): - raise errors.YapfError('path in pyproject.toml should not start with ./') + pyproject_toml = toml.load(filename) + ignore_patterns = pyproject_toml.get('tool', + {}).get('yapfignore', + {}).get('ignore_patterns', []) + if any(e.startswith('./') for e in ignore_patterns): + raise errors.YapfError('path in pyproject.toml should not start with ./') return ignore_patterns diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 6afd8a443..5ccacb84c 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -82,9 +82,9 @@ def test_get_exclude_file_patterns_from_pyproject(self): ignore_patterns = ['temp/**/*.py', 'temp2/*.py'] with open(local_ignore_file, 'w') as f: f.write('[tool.yapfignore]\n') - f.write('ignore_patterns="""') - f.writelines('\n'.join(ignore_patterns)) - f.write('"""') + f.write('ignore_patterns=[') + f.writelines('\n,'.join([f'"{p}"' for p in ignore_patterns])) + f.write(']') self.assertEqual( sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)), @@ -99,9 +99,9 @@ def test_get_exclude_file_patterns_from_pyproject_with_wrong_syntax(self): ignore_patterns = ['temp/**/*.py', './wrong/syntax/*.py'] with open(local_ignore_file, 'w') as f: f.write('[tool.yapfignore]\n') - f.write('ignore_patterns="""') - f.writelines('\n'.join(ignore_patterns)) - f.write('"""') + f.write('ignore_patterns=[') + f.writelines('\n,'.join([f'"{p}"' for p in ignore_patterns])) + f.write(']') with self.assertRaises(errors.YapfError): file_resources.GetExcludePatternsForDir(self.test_tmpdir) From 548550908cff5ee5d09dc11c618c7b62bd667685 Mon Sep 17 00:00:00 2001 From: Bouwe Andela Date: Mon, 23 Aug 2021 21:38:15 +0200 Subject: [PATCH 492/719] Follow PEP8: Method definitions inside a class are surrounded by a single blank line (#954) * PEP8: Method definitions inside a class are surrounded by a single blank line. * Add changelog entry for "pep8" style update --- CHANGELOG | 4 ++++ yapf/yapflib/style.py | 4 ++-- yapftests/reformatter_basic_test.py | 1 + yapftests/reformatter_pep8_test.py | 12 +++++++++--- yapftests/reformatter_python3_test.py | 2 ++ yapftests/yapf_test.py | 2 ++ 6 files changed, 20 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a35ce689a..4cecbd3e2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,10 @@ ### Added - Look at the 'pyproject.toml' file to see if it contains ignore file information for YAPF. +### Fixed +- Enable `BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF` knob for "pep8" style, so + method definitions inside a class are surrounded by a single blank line as + prescribed by PEP8. ## [0.31.0] 2021-03-14 ### Added diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 3d2710923..a1e6940bf 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -418,7 +418,7 @@ def CreatePEP8Style(): ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=True, ALLOW_SPLIT_BEFORE_DICT_VALUE=True, ARITHMETIC_PRECEDENCE_INDICATION=False, - BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=False, + BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=True, BLANK_LINE_BEFORE_CLASS_DOCSTRING=False, BLANK_LINE_BEFORE_MODULE_DOCSTRING=False, BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=2, @@ -479,7 +479,6 @@ def CreateGoogleStyle(): """Create the Google formatting style.""" style = CreatePEP8Style() style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False - style['BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'] = True style['COLUMN_LIMIT'] = 80 style['INDENT_DICTIONARY_VALUE'] = True style['INDENT_WIDTH'] = 4 @@ -511,6 +510,7 @@ def CreateFacebookStyle(): """Create the Facebook formatting style.""" style = CreatePEP8Style() style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False + style['BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'] = False style['COLUMN_LIMIT'] = 80 style['DEDENT_CLOSING_BRACKETS'] = True style['INDENT_CLOSING_BRACKETS'] = False diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index a67e4c47b..8dce567dd 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1982,6 +1982,7 @@ def testMultilineDictionaryKeys(self): def testStableDictionaryFormatting(self): code = textwrap.dedent("""\ class A(object): + def method(self): filters = { 'expressions': [{ diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index a5301f1fc..e1202c2a2 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -50,22 +50,22 @@ def testSingleLineIfStatements(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) - def testNoBlankBetweenClassAndDef(self): + def testBlankBetweenClassAndDef(self): unformatted_code = textwrap.dedent("""\ class Foo: - def joe(): pass """) expected_formatted_code = textwrap.dedent("""\ class Foo: + def joe(): pass """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) - def testNoBlankBetweenDefsInClass(self): + def testBlankBetweenDefsInClass(self): unformatted_code = textwrap.dedent('''\ class TestClass: def __init__(self): @@ -77,6 +77,7 @@ def is_running(self): ''') expected_formatted_code = textwrap.dedent('''\ class TestClass: + def __init__(self): self.running = False @@ -174,6 +175,7 @@ def g(): """) expected_formatted_code = textwrap.dedent("""\ def f(): + def g(): while (xxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz]) == 'aaaaaaaaaaa' and xxxxxxxxxxxxxxxxxxxx( @@ -341,11 +343,13 @@ def testSplitListsAndDictSetMakersIfCommaTerminated(self): def testSplitAroundNamedAssigns(self): unformatted_code = textwrap.dedent("""\ class a(): + def a(): return a( aaaaaaaaaa=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) """) expected_formatted_code = textwrap.dedent("""\ class a(): + def a(): return a( aaaaaaaaaa=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -501,6 +505,7 @@ class Demo: """ Demo docs """ + def foo(self): """ foo docs @@ -602,6 +607,7 @@ def __init__(self, title: Optional[str], diffs: Collection[BinaryDiff] = (), cha """) expected_formatted_code = textwrap.dedent("""\ class _(): + def __init__( self, title: Optional[str], diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index d06e40623..ae557552c 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -238,6 +238,7 @@ def testAsyncFunctionsNested(self): return code = textwrap.dedent("""\ async def outer(): + async def inner(): pass """) @@ -365,6 +366,7 @@ def foo(self): """ expected_formatted_code = """\ class Foo: + def foo(self): foofoofoofoofoofoofoofoo('foofoofoofoofoo', { 'foo': 'foo', diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index dc0d0a5e6..4e062cf36 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -735,12 +735,14 @@ def testDisableWholeDataStructure(self): def testDisableButAdjustIndentations(self): unformatted_code = textwrap.dedent("""\ class SplitPenaltyTest(unittest.TestCase): + def testUnbreakable(self): self._CheckPenalties(tree, [ ]) # yapf: disable """) expected_formatted_code = textwrap.dedent("""\ class SplitPenaltyTest(unittest.TestCase): + def testUnbreakable(self): self._CheckPenalties(tree, [ ]) # yapf: disable From 4f4196836d4efa570d661eb20ae80351e325d7ce Mon Sep 17 00:00:00 2001 From: Sergei Lebedev <185856+superbobry@users.noreply.github.com> Date: Thu, 2 Sep 2021 17:49:34 +0000 Subject: [PATCH 493/719] Added yapf_api.FormatTree (#952) * [RFC] Added yapf_api.FormatTree The new entry point allows to avoid re-parsing when a lib2to3 pytree has already been constructed. Closes #951. * Updated CHANGELOG * Fix spacing Co-authored-by: Bill Wendling <5993918+gwelymernans@users.noreply.github.com> --- CHANGELOG | 2 ++ yapf/yapflib/yapf_api.py | 62 ++++++++++++++++++++++++++++------------ 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4cecbd3e2..c528381c9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,8 @@ ### Added - Look at the 'pyproject.toml' file to see if it contains ignore file information for YAPF. +- New entry point `yapf_api.FormatTree` for formatting lib2to3 concrete + syntax trees. ### Fixed - Enable `BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF` knob for "pep8" style, so method definitions inside a class are surrounded by a single blank line as diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index efa1a7918..91cc01a0d 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -110,6 +110,45 @@ def FormatFile(filename, return reformatted_source, encoding, changed +def FormatTree(tree, style_config=None, lines=None, verify=False): + """Format a parsed lib2to3 pytree. + + This provides an alternative entry point to YAPF. + + Arguments: + tree: (pytree.Node) The root of the pytree to format. + style_config: (string) Either a style name or a path to a file that contains + formatting style settings. If None is specified, use the default style + as set in style.DEFAULT_STYLE_FACTORY + lines: (list of tuples of integers) A list of tuples of lines, [start, end], + that we want to format. The lines are 1-based indexed. It can be used by + third-party code (e.g., IDEs) when reformatting a snippet of code rather + than a whole file. + verify: (bool) True if reformatted code should be verified for syntax. + + Returns: + The source formatted according to the given formatting style. + """ + _CheckPythonVersion() + style.SetGlobalStyle(style.CreateStyleFromConfig(style_config)) + + # Run passes on the tree, modifying it in place. + comment_splicer.SpliceComments(tree) + continuation_splicer.SpliceContinuations(tree) + subtype_assigner.AssignSubtypes(tree) + identify_container.IdentifyContainers(tree) + split_penalty.ComputeSplitPenalties(tree) + blank_line_calculator.CalculateBlankLines(tree) + + uwlines = pytree_unwrapper.UnwrapPyTree(tree) + for uwl in uwlines: + uwl.CalculateFormattingInformation() + + lines = _LineRangesToSet(lines) + _MarkLinesToFormat(uwlines, lines) + return reformatter.Reformat(_SplitSemicolons(uwlines), verify, lines) + + def FormatCode(unformatted_source, filename='', style_config=None, @@ -138,8 +177,6 @@ def FormatCode(unformatted_source, Tuple of (reformatted_source, changed). reformatted_source conforms to the desired formatting style. changed is True if the source changed. """ - _CheckPythonVersion() - style.SetGlobalStyle(style.CreateStyleFromConfig(style_config)) if not unformatted_source.endswith('\n'): unformatted_source += '\n' @@ -149,22 +186,11 @@ def FormatCode(unformatted_source, e.msg = filename + ': ' + e.msg raise - # Run passes on the tree, modifying it in place. - comment_splicer.SpliceComments(tree) - continuation_splicer.SpliceContinuations(tree) - subtype_assigner.AssignSubtypes(tree) - identify_container.IdentifyContainers(tree) - split_penalty.ComputeSplitPenalties(tree) - blank_line_calculator.CalculateBlankLines(tree) - - uwlines = pytree_unwrapper.UnwrapPyTree(tree) - for uwl in uwlines: - uwl.CalculateFormattingInformation() - - lines = _LineRangesToSet(lines) - _MarkLinesToFormat(uwlines, lines) - reformatted_source = reformatter.Reformat( - _SplitSemicolons(uwlines), verify, lines) + reformatted_source = FormatTree( + tree, + style_config=style_config, + lines=lines, + verify=verify) if unformatted_source == reformatted_source: return '' if print_diff else reformatted_source, False From 23573d02c1cb9b696459873364e8820714cb4ffc Mon Sep 17 00:00:00 2001 From: Sergei Lebedev <185856+superbobry@users.noreply.github.com> Date: Thu, 16 Sep 2021 18:03:29 +0000 Subject: [PATCH 494/719] ``pytree_utils.ParseCodeToTree`` now adds a trailing EOL if needed (#962) This was previously done by ``yapf_api.FormatCode``, but I think it makes more sense to have it in ``pytree_utils.ParseCodeToTree``, because the grammar requires a trailing EOL. --- yapf/yapflib/pytree_utils.py | 4 ++++ yapf/yapflib/yapf_api.py | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/yapf/yapflib/pytree_utils.py b/yapf/yapflib/pytree_utils.py index 75d4ca208..876203208 100644 --- a/yapf/yapflib/pytree_utils.py +++ b/yapf/yapflib/pytree_utils.py @@ -25,6 +25,7 @@ """ import ast +import os from lib2to3 import pygram from lib2to3 import pytree @@ -108,6 +109,9 @@ def ParseCodeToTree(code): """ # This function is tiny, but the incantation for invoking the parser correctly # is sufficiently magical to be worth abstracting away. + if not code.endswith(os.linesep): + code += os.linesep + try: # Try to parse using a Python 3 grammar, which is more permissive (print and # exec are not keywords). diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 91cc01a0d..19776922b 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -177,9 +177,6 @@ def FormatCode(unformatted_source, Tuple of (reformatted_source, changed). reformatted_source conforms to the desired formatting style. changed is True if the source changed. """ - if not unformatted_source.endswith('\n'): - unformatted_source += '\n' - try: tree = pytree_utils.ParseCodeToTree(unformatted_source) except parse.ParseError as e: From 00c95bc4be11964e84ab05935046e28c2eabde71 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Thu, 16 Sep 2021 20:04:21 +0200 Subject: [PATCH 495/719] Fix typos discovered by codespell (#950) --- CHANGELOG | 8 ++++---- pylintrc | 2 +- yapf/yapflib/format_decision_state.py | 2 +- yapf/yapflib/pytree_visitor.py | 2 +- yapftests/reformatter_basic_test.py | 2 +- yapftests/reformatter_buganizer_test.py | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c528381c9..8bc75aaa8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -23,7 +23,7 @@ - Look at the 'pyproject.toml' file to see if it contains style information for YAPF. ### Changed -- Do not scan exlcuded directories. Prior versions would scan an exluded +- Do not scan excluded directories. Prior versions would scan an excluded folder then exclude its contents on a file by file basis. Preventing the folder being scanned is faster. ### Fixed @@ -252,7 +252,7 @@ ### Fixed - Use tabs when constructing a continuation line when `USE_TABS` is enabled. - A dictionary entry may not end in a colon, but may be an "unpacking" - operation: `**foo`. Take that into accound and don't split after the + operation: `**foo`. Take that into account and don't split after the unpacking operator. ## [0.20.1] 2018-01-13 @@ -675,7 +675,7 @@ - Retain proper vertical spacing before comments in a data literal. - Make sure that continuations from a compound statement are distinguished from the succeeding line. -- Ignore preceding comments when calculating what is a "dictonary maker". +- Ignore preceding comments when calculating what is a "dictionary maker". - Add a small penalty for splitting before a closing bracket. - Ensure that a space is enforced after we remove a pseudo-paren that's between two names, keywords, numbers, etc. @@ -703,7 +703,7 @@ - Improve splitting heuristic when the first argument to a function call is itself a function call with arguments. In cases like this, the remaining arguments to the function call would look badly aligned, even though they are - techincally correct (the best kind of correct!). + technically correct (the best kind of correct!). - Improve splitting heuristic more so that if the first argument to a function call is a data literal that will go over the column limit, then we want to split before it. diff --git a/pylintrc b/pylintrc index 9e8a554b2..0008df24a 100644 --- a/pylintrc +++ b/pylintrc @@ -55,7 +55,7 @@ confidence= # can either give multiple identifiers separated by comma (,) or put this # option multiple times (only on the command line, not in the configuration # file where it should appear only once).You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if +# disable everything first and then re-enable specific checks. For example, if # you want to run only the similarities checker, you can use "--disable=all # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use"--disable=all --enable=classes diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 59f62014c..3c0db37ab 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -446,7 +446,7 @@ def SurroundedByParens(token): # A function call with a dictionary as its first argument may result in # unreadable formatting if the dictionary spans multiple lines. The - # dictionary itself is formatted just fine, but the remaning arguments are + # dictionary itself is formatted just fine, but the remaining arguments are # indented too far: # # function_call({ diff --git a/yapf/yapflib/pytree_visitor.py b/yapf/yapflib/pytree_visitor.py index 49da05660..a39331cc3 100644 --- a/yapf/yapflib/pytree_visitor.py +++ b/yapf/yapflib/pytree_visitor.py @@ -19,7 +19,7 @@ It also exports a basic "dumping" visitor that dumps a textual representation of a pytree into a stream. - PyTreeVisitor: a generic visitor pattern fo pytrees. + PyTreeVisitor: a generic visitor pattern for pytrees. PyTreeDumper: a configurable "dumper" for displaying pytrees. DumpPyTree(): a convenience function to dump a pytree. """ diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 8dce567dd..7e0765190 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2433,7 +2433,7 @@ def _(): AAAAAAAAAAAAAAAAAAAAAAAA = { Environment.XXXXXXXXXX: 'some text more text even more tex', Environment.YYYYYYY: 'some text more text even more text yet ag', - Environment.ZZZZZZZZZZZ: 'some text more text even mor etext yet again tex', + Environment.ZZZZZZZZZZZ: 'some text more text even more text yet again tex', } """) uwlines = yapf_test_helper.ParseAndUnwrap(code) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index e96f6da74..e95c96c1b 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -2151,7 +2151,7 @@ def main(unused_argv): ok = an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A] bad_slice = map(math.sqrt, an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A]) a_long_name_slicing = an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A] - bad_slice = ("I am a crazy, no good, string whats too long, etc." + " no really ")[:ARBITRARY_CONSTANT_A] + bad_slice = ("I am a crazy, no good, string what's too long, etc." + " no really ")[:ARBITRARY_CONSTANT_A] """) expected_formatted_code = textwrap.dedent("""\ def main(unused_argv): @@ -2162,7 +2162,7 @@ def main(unused_argv): an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A]) a_long_name_slicing = an_array_with_an_exceedingly_long_name[: ARBITRARY_CONSTANT_A] - bad_slice = ("I am a crazy, no good, string whats too long, etc." + + bad_slice = ("I am a crazy, no good, string what's too long, etc." + " no really ")[:ARBITRARY_CONSTANT_A] """) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) From 98c814657d8b7dd37b2d7818246011ee2870e6b2 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 3 Nov 2021 02:46:33 -0700 Subject: [PATCH 496/719] Enforce a space between a colon and the ... token Closes #973 --- CHANGELOG | 1 + yapf/yapflib/unwrapped_line.py | 4 ++-- yapftests/reformatter_pep8_test.py | 13 +++++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8bc75aaa8..19d59f8e0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,7 @@ - Enable `BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF` knob for "pep8" style, so method definitions inside a class are surrounded by a single blank line as prescribed by PEP8. +- Fixed the '...' token to be spaced after a colon. ## [0.31.0] 2021-03-14 ### Added diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index b49fefeae..ddd50e0dc 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -319,11 +319,11 @@ def _SpaceRequiredBetween(left, right, is_line_disabled): if lval == '.' and rval == 'import': # Space after the '.' in an import statement. return True - if (lval == '=' and rval == '.' and + if (lval == '=' and rval in {'.', ',,,'} and format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN not in left.subtypes): # Space between equal and '.' as in "X = ...". return True - if lval == ':' and rval == '.': + if lval == ':' and rval in {'.', '...'}: # Space between : and ... return True if ((right.is_keyword or right.is_name) and diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index e1202c2a2..e5ed2faa8 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -715,6 +715,19 @@ class MyClass(ABC): uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines, verify=False)) + @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') + def testSpaceBetweenDictColonAndElipses(self): + style.SetGlobalStyle(style.CreatePEP8Style()) + unformatted_code = textwrap.dedent("""\ + {0:"...", 1:...} + """) + expected_formatted_code = textwrap.dedent("""\ + {0: "...", 1: ...} + """) + + uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + class TestsForSpacesInsideBrackets(yapf_test_helper.YAPFTest): """Test the SPACE_INSIDE_BRACKETS style option.""" From c2ce67f7cc678d7f9c02d9c5ba446ecd564c18b5 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 4 Nov 2021 00:36:39 -0700 Subject: [PATCH 497/719] Use '[style]' in the example, as that's the most common style section Closes #961 --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 0b8a83e46..e0e23165d 100644 --- a/README.rst +++ b/README.rst @@ -175,11 +175,11 @@ the predefined styles (e.g., ``pep8`` or ``google``), a path to a configuration file that specifies the desired style, or a dictionary of key/value pairs. The config file is a simple listing of (case-insensitive) ``key = value`` pairs -with a ``[yapf]`` heading. For example: +with a ``[style]`` heading. For example: .. code-block:: ini - [yapf] + [style] based_on_style = pep8 spaces_before_comment = 4 split_before_logical_operator = true From f1ee23864b644b420d2613612279a944df9d390d Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 4 Nov 2021 00:38:32 -0700 Subject: [PATCH 498/719] Reformatting the source code. --- yapf/yapflib/yapf_api.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 19776922b..479c8cae3 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -184,10 +184,7 @@ def FormatCode(unformatted_source, raise reformatted_source = FormatTree( - tree, - style_config=style_config, - lines=lines, - verify=verify) + tree, style_config=style_config, lines=lines, verify=verify) if unformatted_source == reformatted_source: return '' if print_diff else reformatted_source, False From 99ace8ee48c5132d05864ec0c75a787b0940e7b1 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 4 Nov 2021 00:47:25 -0700 Subject: [PATCH 499/719] Correct testcases for Python 2.7 and PEP8 changes. --- yapftests/file_resources_test.py | 5 +++-- yapftests/reformatter_basic_test.py | 1 + yapftests/reformatter_pep8_test.py | 1 + yapftests/reformatter_verify_test.py | 14 +++----------- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 5ccacb84c..f12f214d8 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -83,13 +83,14 @@ def test_get_exclude_file_patterns_from_pyproject(self): with open(local_ignore_file, 'w') as f: f.write('[tool.yapfignore]\n') f.write('ignore_patterns=[') - f.writelines('\n,'.join([f'"{p}"' for p in ignore_patterns])) + f.writelines('\n,'.join([str(p) for p in ignore_patterns])) f.write(']') self.assertEqual( sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)), sorted(ignore_patterns)) + @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def test_get_exclude_file_patterns_from_pyproject_with_wrong_syntax(self): try: import toml @@ -100,7 +101,7 @@ def test_get_exclude_file_patterns_from_pyproject_with_wrong_syntax(self): with open(local_ignore_file, 'w') as f: f.write('[tool.yapfignore]\n') f.write('ignore_patterns=[') - f.writelines('\n,'.join([f'"{p}"' for p in ignore_patterns])) + f.writelines('\n,'.join([str(p) for p in ignore_patterns])) f.write(']') with self.assertRaises(errors.YapfError): diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 7e0765190..8b48c487b 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2801,6 +2801,7 @@ def testAsyncAsNonKeyword(self): class A(object): + def foo(self): async.run() """) diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index e5ed2faa8..c70ec49dc 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -672,6 +672,7 @@ def testAsyncAsNonKeyword(self): class A(object): + def foo(self): async.run() diff --git a/yapftests/reformatter_verify_test.py b/yapftests/reformatter_verify_test.py index 1b3d5b080..c10cb8692 100644 --- a/yapftests/reformatter_verify_test.py +++ b/yapftests/reformatter_verify_test.py @@ -84,7 +84,7 @@ def call_my_function(the_function): reformatter.Reformat(uwlines, verify=False)) def testContinuationLineShouldBeDistinguished(self): - unformatted_code = textwrap.dedent("""\ + code = textwrap.dedent("""\ class Foo(object): def bar(self): @@ -92,16 +92,8 @@ def bar(self): self.generators + self.next_batch) == 1: pass """) - expected_formatted_code = textwrap.dedent("""\ - class Foo(object): - def bar(self): - if self.solo_generator_that_is_long is None and len( - self.generators + self.next_batch) == 1: - pass - """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines, verify=False)) + uwlines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(uwlines, verify=False)) if __name__ == '__main__': From 8fa5d821011f208dc8e46ac4867d9396dae5d040 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 4 Nov 2021 03:09:01 -0700 Subject: [PATCH 500/719] Change tests to support "pytest". --- CHANGELOG | 2 ++ yapf/__init__.py | 4 ++- yapftests/file_resources_test.py | 4 +-- yapftests/main_test.py | 14 ++++---- yapftests/style_test.py | 57 ++++++++++++++++---------------- yapftests/yapf_test_helper.py | 6 ++++ 6 files changed, 50 insertions(+), 37 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 19d59f8e0..1cc69bb89 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,8 @@ for YAPF. - New entry point `yapf_api.FormatTree` for formatting lib2to3 concrete syntax trees. +### Changes +- Change tests to support "pytest". ### Fixed - Enable `BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF` knob for "pep8" style, so method definitions inside a class are surrounded by a single blank line as diff --git a/yapf/__init__.py b/yapf/__init__.py index 22adc306d..4fe2ddfaa 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -81,7 +81,9 @@ def main(argv): original_source = [] while True: - if sys.stdin.closed: + # Test that sys.stdin has the "closed" attribute. When using pytest, it + # co-opts sys.stdin, which makes the "main_tests.py" fail. This is gross. + if hasattr(sys.stdin, "closed") and sys.stdin.closed: break try: # Use 'raw_input' instead of 'sys.stdin.read', because otherwise the diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index f12f214d8..01efece61 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -83,7 +83,7 @@ def test_get_exclude_file_patterns_from_pyproject(self): with open(local_ignore_file, 'w') as f: f.write('[tool.yapfignore]\n') f.write('ignore_patterns=[') - f.writelines('\n,'.join([str(p) for p in ignore_patterns])) + f.writelines('\n,'.join(['"{}"'.format(p) for p in ignore_patterns])) f.write(']') self.assertEqual( @@ -101,7 +101,7 @@ def test_get_exclude_file_patterns_from_pyproject_with_wrong_syntax(self): with open(local_ignore_file, 'w') as f: f.write('[tool.yapfignore]\n') f.write('ignore_patterns=[') - f.writelines('\n,'.join([str(p) for p in ignore_patterns])) + f.writelines('\n,'.join(['"{}"'.format(p) for p in ignore_patterns])) f.write(']') with self.assertRaises(errors.YapfError): diff --git a/yapftests/main_test.py b/yapftests/main_test.py index 94daaaa94..a9069b082 100644 --- a/yapftests/main_test.py +++ b/yapftests/main_test.py @@ -21,6 +21,8 @@ from yapf.yapflib import py3compat +from yapftests import yapf_test_helper + class IO(object): """IO is a thin wrapper around StringIO. @@ -83,7 +85,7 @@ def patch_raw_input(lines=lines()): yapf.py3compat.raw_input = orig_raw_import -class RunMainTest(unittest.TestCase): +class RunMainTest(yapf_test_helper.YAPFTest): def testShouldHandleYapfError(self): """run_main should handle YapfError and sys.exit(1).""" @@ -96,11 +98,11 @@ def testShouldHandleYapfError(self): self.assertEqual(err.getvalue(), expected_message) -class MainTest(unittest.TestCase): +class MainTest(yapf_test_helper.YAPFTest): def testNoPythonFilesMatched(self): - with self.assertRaisesRegexp(yapf.errors.YapfError, - 'did not match any python files'): + with self.assertRaisesRegex(yapf.errors.YapfError, + 'did not match any python files'): yapf.main(['yapf', 'foo.c']) def testEchoInput(self): @@ -112,7 +114,7 @@ def testEchoInput(self): self.assertEqual(out.getvalue(), code) def testEchoInputWithStyle(self): - code = 'def f(a = 1):\n return 2*a\n' + code = 'def f(a = 1\n\n):\n return 2*a\n' yapf_code = 'def f(a=1):\n return 2 * a\n' with patched_input(code): with captured_output() as (out, _): @@ -124,7 +126,7 @@ def testEchoBadInput(self): bad_syntax = ' a = 1\n' with patched_input(bad_syntax): with captured_output() as (_, _): - with self.assertRaisesRegexp(SyntaxError, 'unexpected indent'): + with self.assertRaisesRegex(SyntaxError, 'unexpected indent'): yapf.main([]) def testHelp(self): diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 2fd3f2d0e..a9512f1b2 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -23,9 +23,10 @@ from yapf.yapflib import style from yapftests import utils +from yapftests import yapf_test_helper -class UtilsTest(unittest.TestCase): +class UtilsTest(yapf_test_helper.YAPFTest): def testContinuationAlignStyleStringConverter(self): for cont_align_space in ('', 'space', '"space"', '\'space\''): @@ -91,7 +92,7 @@ def _LooksLikeYapfStyle(cfg): return cfg['SPLIT_BEFORE_DOT'] -class PredefinedStylesByNameTest(unittest.TestCase): +class PredefinedStylesByNameTest(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): # pylint: disable=g-missing-super-call @@ -123,7 +124,7 @@ def testFacebookByName(self): self.assertTrue(_LooksLikeFacebookStyle(cfg)) -class StyleFromFileTest(unittest.TestCase): +class StyleFromFileTest(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): # pylint: disable=g-missing-super-call @@ -202,8 +203,8 @@ def testStringListOptionValue(self): self.assertEqual(cfg['I18N_FUNCTION_CALL'], ['N_', 'V_', 'T_']) def testErrorNoStyleFile(self): - with self.assertRaisesRegexp(style.StyleConfigError, - 'is not a valid style or file path'): + with self.assertRaisesRegex(style.StyleConfigError, + 'is not a valid style or file path'): style.CreateStyleFromConfig('/8822/xyznosuchfile') def testErrorNoStyleSection(self): @@ -212,8 +213,8 @@ def testErrorNoStyleSection(self): indent_width=2 ''') with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: - with self.assertRaisesRegexp(style.StyleConfigError, - 'Unable to find section'): + with self.assertRaisesRegex(style.StyleConfigError, + 'Unable to find section'): style.CreateStyleFromConfig(filepath) def testErrorUnknownStyleOption(self): @@ -223,8 +224,8 @@ def testErrorUnknownStyleOption(self): hummus=2 ''') with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: - with self.assertRaisesRegexp(style.StyleConfigError, - 'Unknown style option'): + with self.assertRaisesRegex(style.StyleConfigError, + 'Unknown style option'): style.CreateStyleFromConfig(filepath) def testPyprojectTomlNoYapfSection(self): @@ -235,8 +236,8 @@ def testPyprojectTomlNoYapfSection(self): filepath = os.path.join(self.test_tmpdir, 'pyproject.toml') _ = open(filepath, 'w') - with self.assertRaisesRegexp(style.StyleConfigError, - 'Unable to find section'): + with self.assertRaisesRegex(style.StyleConfigError, + 'Unable to find section'): style.CreateStyleFromConfig(filepath) def testPyprojectTomlParseYapfSection(self): @@ -258,7 +259,7 @@ def testPyprojectTomlParseYapfSection(self): self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 40) -class StyleFromDict(unittest.TestCase): +class StyleFromDict(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): # pylint: disable=g-missing-super-call @@ -275,15 +276,15 @@ def testDefaultBasedOnStyle(self): self.assertEqual(cfg['INDENT_WIDTH'], 2) def testDefaultBasedOnStyleBadDict(self): - self.assertRaisesRegexp(style.StyleConfigError, 'Unknown style option', - style.CreateStyleFromConfig, - {'based_on_styl': 'pep8'}) - self.assertRaisesRegexp(style.StyleConfigError, 'not a valid', - style.CreateStyleFromConfig, - {'INDENT_WIDTH': 'FOUR'}) + self.assertRaisesRegex(style.StyleConfigError, 'Unknown style option', + style.CreateStyleFromConfig, + {'based_on_styl': 'pep8'}) + self.assertRaisesRegex(style.StyleConfigError, 'not a valid', + style.CreateStyleFromConfig, + {'INDENT_WIDTH': 'FOUR'}) -class StyleFromCommandLine(unittest.TestCase): +class StyleFromCommandLine(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): # pylint: disable=g-missing-super-call @@ -314,17 +315,17 @@ def testDefaultBasedOnDetaultTypeString(self): self.assertIsInstance(cfg, dict) def testDefaultBasedOnStyleBadString(self): - self.assertRaisesRegexp(style.StyleConfigError, 'Unknown style option', - style.CreateStyleFromConfig, - '{based_on_styl: pep8}') - self.assertRaisesRegexp(style.StyleConfigError, 'not a valid', - style.CreateStyleFromConfig, '{INDENT_WIDTH: FOUR}') - self.assertRaisesRegexp(style.StyleConfigError, 'Invalid style dict', - style.CreateStyleFromConfig, - '{based_on_style: pep8') + self.assertRaisesRegex(style.StyleConfigError, 'Unknown style option', + style.CreateStyleFromConfig, + '{based_on_styl: pep8}') + self.assertRaisesRegex(style.StyleConfigError, 'not a valid', + style.CreateStyleFromConfig, '{INDENT_WIDTH: FOUR}') + self.assertRaisesRegex(style.StyleConfigError, 'Invalid style dict', + style.CreateStyleFromConfig, + '{based_on_style: pep8') -class StyleHelp(unittest.TestCase): +class StyleHelp(yapf_test_helper.YAPFTest): def testHelpKeys(self): settings = sorted(style.Help()) diff --git a/yapftests/yapf_test_helper.py b/yapftests/yapf_test_helper.py index 1f21b363a..f6a2b66b2 100644 --- a/yapftests/yapf_test_helper.py +++ b/yapftests/yapf_test_helper.py @@ -21,6 +21,7 @@ from yapf.yapflib import comment_splicer from yapf.yapflib import continuation_splicer from yapf.yapflib import identify_container +from yapf.yapflib import py3compat from yapf.yapflib import pytree_unwrapper from yapf.yapflib import pytree_utils from yapf.yapflib import pytree_visitor @@ -31,6 +32,11 @@ class YAPFTest(unittest.TestCase): + def __init__(self, *args): + super(YAPFTest, self).__init__(*args) + if not py3compat.PY3: + self.assertRaisesRegex = self.assertRaisesRegexp + def assertCodeEqual(self, expected_code, code): if code != expected_code: msg = ['Code format mismatch:', 'Expected:'] From d3d69827339fe0337e6c923085af2783057b09eb Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 4 Nov 2021 03:32:37 -0700 Subject: [PATCH 501/719] Reformat so that flake8 is happy. --- .flake8 | 15 +++++++++++---- CHANGELOG | 1 + yapf/yapflib/blank_line_calculator.py | 4 ++-- yapf/yapflib/comment_splicer.py | 4 ++-- yapf/yapflib/file_resources.py | 9 ++++++--- yapf/yapflib/format_decision_state.py | 4 ++-- yapf/yapflib/reformatter.py | 6 +++--- yapf/yapflib/style.py | 27 +++++++++++++++++---------- yapf/yapflib/yapf_api.py | 2 +- 9 files changed, 45 insertions(+), 27 deletions(-) diff --git a/.flake8 b/.flake8 index 06d70e9bd..3ac8c3fda 100644 --- a/.flake8 +++ b/.flake8 @@ -1,8 +1,15 @@ [flake8] ignore = - # indentation is not a multiple of four, - E111,E114, + # continuation line over-indented for hanging indent + E126, # visually indented line with same indent as next logical line, - E129 + E129, + # line break after binary operator + W504 -max-line-length=80 +exclude = + yapf/yapflib/py3compat.py + +disable-noqa +indent-size = 2 +max-line-length = 80 diff --git a/CHANGELOG b/CHANGELOG index 1cc69bb89..c3f03c42c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,7 @@ syntax trees. ### Changes - Change tests to support "pytest". +- Reformat so that "flake8" is happy. ### Fixed - Enable `BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF` knob for "pep8" style, so method definitions inside a class are surrounded by a single blank line as diff --git a/yapf/yapflib/blank_line_calculator.py b/yapf/yapflib/blank_line_calculator.py index 374134853..f3f14da45 100644 --- a/yapf/yapflib/blank_line_calculator.py +++ b/yapf/yapflib/blank_line_calculator.py @@ -139,8 +139,8 @@ def _SetBlankLinesBetweenCommentAndClassFunc(self, node): if not self.last_was_decorator: _SetNumNewlines(node.children[index].children[0], _ONE_BLANK_LINE) index += 1 - if (index and node.children[index].lineno - 1 - == node.children[index - 1].children[0].lineno): + if (index and node.children[index].lineno - 1 == + node.children[index - 1].children[0].lineno): _SetNumNewlines(node.children[index], _NO_BLANK_LINES) else: if self.last_comment_lineno + 1 == node.children[index].lineno: diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index 8d646849f..535711b21 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -120,9 +120,9 @@ def _VisitNodeRec(node): for comment_column, comment_indent, comment_group in comment_groups: ancestor_at_indent = _FindAncestorAtIndent(child, comment_indent) if ancestor_at_indent.type == token.DEDENT: - InsertNodes = pytree_utils.InsertNodesBefore # pylint: disable=invalid-name + InsertNodes = pytree_utils.InsertNodesBefore # pylint: disable=invalid-name # noqa else: - InsertNodes = pytree_utils.InsertNodesAfter # pylint: disable=invalid-name + InsertNodes = pytree_utils.InsertNodesAfter # pylint: disable=invalid-name # noqa InsertNodes( _CreateCommentsFromPrefix( '\n'.join(comment_group) + '\n', diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 1c405a2a1..0c88fc194 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -54,7 +54,8 @@ def _GetExcludePatternsFromPyprojectToml(filename): import toml except ImportError: raise errors.YapfError( - "toml package is needed for using pyproject.toml as a configuration file" + "toml package is needed for using pyproject.toml as a " + "configuration file" ) if os.path.isfile(filename) and os.access(filename, os.R_OK): @@ -95,7 +96,8 @@ def GetExcludePatternsForDir(dirname): def GetDefaultStyleForDir(dirname, default_style=style.DEFAULT_STYLE): """Return default style name for a given directory. - Looks for .style.yapf or setup.cfg or pyproject.toml in the parent directories. + Looks for .style.yapf or setup.cfg or pyproject.toml in the parent + directories. Arguments: dirname: (unicode) The name of the directory. @@ -137,7 +139,8 @@ def GetDefaultStyleForDir(dirname, default_style=style.DEFAULT_STYLE): import toml except ImportError: raise errors.YapfError( - "toml package is needed for using pyproject.toml as a configuration file" + "toml package is needed for using pyproject.toml as a " + "configuration file" ) pyproject_toml = toml.load(config_file) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 3c0db37ab..f6fb07ff8 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -981,8 +981,8 @@ def _GetNewlineColumn(self): if (self.param_list_stack and not self.param_list_stack[-1].SplitBeforeClosingBracket( - top_of_stack.indent) and top_of_stack.indent - == ((self.line.depth + 1) * style.Get('INDENT_WIDTH'))): + top_of_stack.indent) and top_of_stack.indent == + ((self.line.depth + 1) * style.Get('INDENT_WIDTH'))): if (format_token.Subtype.PARAMETER_START in current.subtypes or (previous.is_comment and format_token.Subtype.PARAMETER_START in previous.subtypes)): diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 5695ed917..8af27c846 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -298,7 +298,7 @@ def _AlignTrailingComments(final_lines): assert this_line.tokens if (all_pc_line_lengths and this_line.tokens[0].formatted_whitespace_prefix.startswith('\n\n') - ): + ): break if this_line.disable: @@ -486,8 +486,8 @@ def _AnalyzeSolutionSpace(initial_state): if count > 10000: node.state.ignore_stack_for_comparison = True - # Unconditionally add the state and check if it was present to avoid having to - # hash it twice in the common case (state hashing is expensive). + # Unconditionally add the state and check if it was present to avoid having + # to hash it twice in the common case (state hashing is expensive). before_seen_count = len(seen) seen.add(node.state) # If seen didn't change size, the state was already present. diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index a1e6940bf..85bb08cfb 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -235,7 +235,8 @@ def method(): SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=textwrap.dedent("""\ Use spaces around default or named assigns."""), SPACES_AROUND_DICT_DELIMITERS=textwrap.dedent("""\ - Adds a space after the opening '{' and before the ending '}' dict delimiters. + Adds a space after the opening '{' and before the ending '}' dict + delimiters. {1: 2} @@ -244,7 +245,8 @@ def method(): { 1: 2 } """), SPACES_AROUND_LIST_DELIMITERS=textwrap.dedent("""\ - Adds a space after the opening '[' and before the ending ']' list delimiters. + Adds a space after the opening '[' and before the ending ']' list + delimiters. [1, 2] @@ -258,7 +260,8 @@ def method(): my_list[1 : 10 : 2] """), SPACES_AROUND_TUPLE_DELIMITERS=textwrap.dedent("""\ - Adds a space after the opening '(' and before the ending ')' tuple delimiters. + Adds a space after the opening '(' and before the ending ')' tuple + delimiters. (1, 2, 3) @@ -280,7 +283,8 @@ def method(): will be formatted as: - 1 + 1 # Adding values <-- 5 spaces between the end of the statement and comment + 1 + 1 # Adding values <-- 5 spaces between the end of the + # statement and comment With spaces_before_comment=15, 20: @@ -295,16 +299,18 @@ def method(): will be formatted as: - 1 + 1 # Adding values <-- end of line comments in block aligned to col 15 + 1 + 1 # Adding values <-- end of line comments in block + # aligned to col 15 two + two # More adding - longer_statement # This is a longer statement <-- end of line comments in block aligned to col 20 + longer_statement # This is a longer statement <-- end of line + # comments in block aligned to col 20 short # This is a shorter statement a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length short # This is a shorter statement - """), + """), # noqa SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=textwrap.dedent("""\ Split before arguments if the argument list is terminated by a comma."""), @@ -339,7 +345,7 @@ def method(): foo = ('This is a really long string: {}, {}, {}, {}' .format(a, b, c, d)) - """), + """), # noqa SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=textwrap.dedent("""\ Split after the opening paren which surrounds an expression if it doesn't fit on a single line. @@ -399,7 +405,7 @@ def method(): from a_very_long_or_indented_module_name_yada_yad import ( long_argument_1, long_argument_2, long_argument_3) - """), + """), # noqa SPLIT_PENALTY_LOGICAL_OPERATOR=textwrap.dedent("""\ The penalty of splitting the line around the 'and' and 'or' operators."""), @@ -747,7 +753,8 @@ def _CreateConfigParserFromConfigFile(config_filename): import toml except ImportError: raise errors.YapfError( - "toml package is needed for using pyproject.toml as a configuration file" + "toml package is needed for using pyproject.toml as a " + "configuration file" ) pyproject_toml = toml.load(style_file) diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 479c8cae3..0ef2a1eb9 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -193,7 +193,7 @@ def FormatCode(unformatted_source, unformatted_source, reformatted_source, filename=filename) if print_diff: - return code_diff, code_diff.strip() != '' # pylint: disable=g-explicit-bool-comparison + return code_diff, code_diff.strip() != '' # pylint: disable=g-explicit-bool-comparison # noqa return reformatted_source, True From 101dbb80083f0b19f0e00d883cd85a18cae6bdd1 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 4 Nov 2021 03:35:43 -0700 Subject: [PATCH 502/719] Reformat --- .flake8 | 4 ++++ yapf/yapflib/blank_line_calculator.py | 4 ++-- yapf/yapflib/file_resources.py | 6 ++---- yapf/yapflib/format_decision_state.py | 4 ++-- yapf/yapflib/reformatter.py | 2 +- yapf/yapflib/style.py | 9 ++++----- yapftests/style_test.py | 6 ++---- 7 files changed, 17 insertions(+), 18 deletions(-) diff --git a/.flake8 b/.flake8 index 3ac8c3fda..40a9fdbce 100644 --- a/.flake8 +++ b/.flake8 @@ -1,9 +1,13 @@ [flake8] ignore = + # closing bracket does not match visual indentation + E124, # continuation line over-indented for hanging indent E126, # visually indented line with same indent as next logical line, E129, + # line break before binary operator + W503, # line break after binary operator W504 diff --git a/yapf/yapflib/blank_line_calculator.py b/yapf/yapflib/blank_line_calculator.py index f3f14da45..374134853 100644 --- a/yapf/yapflib/blank_line_calculator.py +++ b/yapf/yapflib/blank_line_calculator.py @@ -139,8 +139,8 @@ def _SetBlankLinesBetweenCommentAndClassFunc(self, node): if not self.last_was_decorator: _SetNumNewlines(node.children[index].children[0], _ONE_BLANK_LINE) index += 1 - if (index and node.children[index].lineno - 1 == - node.children[index - 1].children[0].lineno): + if (index and node.children[index].lineno - 1 + == node.children[index - 1].children[0].lineno): _SetNumNewlines(node.children[index], _NO_BLANK_LINES) else: if self.last_comment_lineno + 1 == node.children[index].lineno: diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 0c88fc194..972f48381 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -55,8 +55,7 @@ def _GetExcludePatternsFromPyprojectToml(filename): except ImportError: raise errors.YapfError( "toml package is needed for using pyproject.toml as a " - "configuration file" - ) + "configuration file") if os.path.isfile(filename) and os.access(filename, os.R_OK): pyproject_toml = toml.load(filename) @@ -140,8 +139,7 @@ def GetDefaultStyleForDir(dirname, default_style=style.DEFAULT_STYLE): except ImportError: raise errors.YapfError( "toml package is needed for using pyproject.toml as a " - "configuration file" - ) + "configuration file") pyproject_toml = toml.load(config_file) style_dict = pyproject_toml.get('tool', {}).get('yapf', None) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index f6fb07ff8..3c0db37ab 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -981,8 +981,8 @@ def _GetNewlineColumn(self): if (self.param_list_stack and not self.param_list_stack[-1].SplitBeforeClosingBracket( - top_of_stack.indent) and top_of_stack.indent == - ((self.line.depth + 1) * style.Get('INDENT_WIDTH'))): + top_of_stack.indent) and top_of_stack.indent + == ((self.line.depth + 1) * style.Get('INDENT_WIDTH'))): if (format_token.Subtype.PARAMETER_START in current.subtypes or (previous.is_comment and format_token.Subtype.PARAMETER_START in previous.subtypes)): diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 8af27c846..6857b107d 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -298,7 +298,7 @@ def _AlignTrailingComments(final_lines): assert this_line.tokens if (all_pc_line_lengths and this_line.tokens[0].formatted_whitespace_prefix.startswith('\n\n') - ): + ): break if this_line.disable: diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 85bb08cfb..40b23c4de 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -310,7 +310,7 @@ def method(): a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length short # This is a shorter statement - """), # noqa + """), # noqa SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=textwrap.dedent("""\ Split before arguments if the argument list is terminated by a comma."""), @@ -345,7 +345,7 @@ def method(): foo = ('This is a really long string: {}, {}, {}, {}' .format(a, b, c, d)) - """), # noqa + """), # noqa SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=textwrap.dedent("""\ Split after the opening paren which surrounds an expression if it doesn't fit on a single line. @@ -405,7 +405,7 @@ def method(): from a_very_long_or_indented_module_name_yada_yad import ( long_argument_1, long_argument_2, long_argument_3) - """), # noqa + """), # noqa SPLIT_PENALTY_LOGICAL_OPERATOR=textwrap.dedent("""\ The penalty of splitting the line around the 'and' and 'or' operators."""), @@ -754,8 +754,7 @@ def _CreateConfigParserFromConfigFile(config_filename): except ImportError: raise errors.YapfError( "toml package is needed for using pyproject.toml as a " - "configuration file" - ) + "configuration file") pyproject_toml = toml.load(style_file) style_dict = pyproject_toml.get("tool", {}).get("yapf", None) diff --git a/yapftests/style_test.py b/yapftests/style_test.py index a9512f1b2..8a37f9535 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -316,13 +316,11 @@ def testDefaultBasedOnDetaultTypeString(self): def testDefaultBasedOnStyleBadString(self): self.assertRaisesRegex(style.StyleConfigError, 'Unknown style option', - style.CreateStyleFromConfig, - '{based_on_styl: pep8}') + style.CreateStyleFromConfig, '{based_on_styl: pep8}') self.assertRaisesRegex(style.StyleConfigError, 'not a valid', style.CreateStyleFromConfig, '{INDENT_WIDTH: FOUR}') self.assertRaisesRegex(style.StyleConfigError, 'Invalid style dict', - style.CreateStyleFromConfig, - '{based_on_style: pep8') + style.CreateStyleFromConfig, '{based_on_style: pep8') class StyleHelp(yapf_test_helper.YAPFTest): From 63f0e4322123a4fb7e2033084c701eb41dd4eb68 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 4 Nov 2021 03:39:00 -0700 Subject: [PATCH 503/719] Add CI via GitHub Actions. --- .github/workflows/ci.yml | 34 ++++++++++++++++++++++++++++++++++ CHANGELOG | 1 + 2 files changed, 35 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..949722001 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,34 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: YAPF + +on: [push] + +jobs: + build: + + runs-on: ${{ matrix.os }} + strategy: + matrix: + python-version: [2.7, 3.7, 3.8, 3.9] + os: [ubuntu-latest, macos-latest, windows-latest] + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + - name: Lint with flake8 + run: | + python -m pip install toml flake8 + flake8 . --statistics + - name: Test with pytest + run: | + pip install pytest + pip install pytest-cov + pytest diff --git a/CHANGELOG b/CHANGELOG index c3f03c42c..58b337ae6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,7 @@ for YAPF. - New entry point `yapf_api.FormatTree` for formatting lib2to3 concrete syntax trees. +- Add CI via GitHub Actions. ### Changes - Change tests to support "pytest". - Reformat so that "flake8" is happy. From f04dbf5e17b6c8819a189230caa40086c5ebe728 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 4 Nov 2021 03:44:16 -0700 Subject: [PATCH 504/719] Add GitHub Actions badge. --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index e0e23165d..9522974b9 100644 --- a/README.rst +++ b/README.rst @@ -6,8 +6,8 @@ YAPF :target: https://badge.fury.io/py/yapf :alt: PyPI version -.. image:: https://travis-ci.org/google/yapf.svg?branch=main - :target: https://travis-ci.org/google/yapf +.. image:: https://github.com/google/yapf/actions/workflows/ci.yml/badge.svg + :target: https://github.com/google/yapf :alt: Build status .. image:: https://coveralls.io/repos/google/yapf/badge.svg?branch=main From 3499b2e50fc461c7940b80badccb60dcc72bb3b4 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 4 Nov 2021 03:51:11 -0700 Subject: [PATCH 505/719] Update URL and ignore yapftests --- .flake8 | 1 + README.rst | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.flake8 b/.flake8 index 40a9fdbce..4fdb0fb53 100644 --- a/.flake8 +++ b/.flake8 @@ -13,6 +13,7 @@ ignore = exclude = yapf/yapflib/py3compat.py + yapftests/* disable-noqa indent-size = 2 diff --git a/README.rst b/README.rst index 9522974b9..739acbd0e 100644 --- a/README.rst +++ b/README.rst @@ -7,7 +7,7 @@ YAPF :alt: PyPI version .. image:: https://github.com/google/yapf/actions/workflows/ci.yml/badge.svg - :target: https://github.com/google/yapf + :target: https://github.com/google/yapf/actions :alt: Build status .. image:: https://coveralls.io/repos/google/yapf/badge.svg?branch=main From 470a099d1261bb9923e66051644257f3524f28f7 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 4 Nov 2021 04:05:44 -0700 Subject: [PATCH 506/719] Turn off hash randomization in test. --- yapftests/yapf_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 4e062cf36..446b256fd 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1528,7 +1528,7 @@ def testCP936Encoding(self): self.assertYapfReformats( unformatted_code, expected_formatted_code, - env={'PYTHONIOENCODING': 'cp936'}) + env={'PYTHONIOENCODING': 'cp936', 'PYTHONHASHSEED': 0}) def testDisableWithLineRanges(self): unformatted_code = """\ From a4d72cd28be57d3fdeec8ba425702b1e95be7332 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 4 Nov 2021 04:08:06 -0700 Subject: [PATCH 507/719] Don't run on Windows --- .github/workflows/ci.yml | 2 +- yapftests/yapf_test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 949722001..280af4335 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: python-version: [2.7, 3.7, 3.8, 3.9] - os: [ubuntu-latest, macos-latest, windows-latest] + os: [ubuntu-latest, macos-latest] steps: - uses: actions/checkout@v2 diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 446b256fd..4e062cf36 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1528,7 +1528,7 @@ def testCP936Encoding(self): self.assertYapfReformats( unformatted_code, expected_formatted_code, - env={'PYTHONIOENCODING': 'cp936', 'PYTHONHASHSEED': 0}) + env={'PYTHONIOENCODING': 'cp936'}) def testDisableWithLineRanges(self): unformatted_code = """\ From 60d5c846e2a8b6c23e4fa32e6daa4a64aff6f6a2 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 4 Nov 2021 04:11:03 -0700 Subject: [PATCH 508/719] We're no longer using Travis CI. --- .travis.yml | 36 ------------------------------------ CHANGELOG | 1 + 2 files changed, 1 insertion(+), 36 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4f9a91d87..000000000 --- a/.travis.yml +++ /dev/null @@ -1,36 +0,0 @@ -language: python - -python: - - 2.7 - - 3.4 - - 3.5 - - 3.6 - - nightly - -matrix: - allow_failures: - - python: nightly - - python: 3.7 - include: - - python: 2.7 - env: SCA=true - - python: 3.5 - env: SCA=true - - python: 3.7 - dist: xenial # required for Python 3.7 (travis-ci/travis-ci#9069) - sudo: required # required for Python 3.7 (travis-ci/travis-ci#9069) - - python: 3.7 - dist: xenial # required for Python 3.7 (travis-ci/travis-ci#9069) - sudo: required # required for Python 3.7 (travis-ci/travis-ci#9069) - env: SCA=true - -install: - - if [ -z "$SCA" ]; then pip install --quiet coveralls; else echo skip; fi - - if [ -n "$SCA" ]; then python setup.py develop; else echo skip; fi - -script: - - if [ -n "$SCA" ]; then yapf --diff --recursive . || exit; else echo skip; fi - - if [ -z "$SCA" ]; then nosetests --with-coverage --cover-package=yapf; else echo skip; fi - -after_success: - - coveralls diff --git a/CHANGELOG b/CHANGELOG index 58b337ae6..ecbda460c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,7 @@ ### Changes - Change tests to support "pytest". - Reformat so that "flake8" is happy. +- Use GitHub Actions instead of Travis for CI. ### Fixed - Enable `BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF` knob for "pep8" style, so method definitions inside a class are surrounded by a single blank line as From 0221e0da19c56559bc9bab2114a44373ba0260d5 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 4 Nov 2021 04:52:22 -0700 Subject: [PATCH 509/719] Add more files to flake8 run. --- .flake8 | 6 +- yapf/yapflib/py3compat.py | 8 +- yapftests/blank_line_calculator_test.py | 2 +- yapftests/file_resources_test.py | 2 +- yapftests/line_joiner_test.py | 2 +- yapftests/reformatter_basic_test.py | 147 ++++++++++---------- yapftests/reformatter_buganizer_test.py | 154 ++++++++++----------- yapftests/reformatter_facebook_test.py | 28 ++-- yapftests/reformatter_pep8_test.py | 46 +++--- yapftests/reformatter_python3_test.py | 12 +- yapftests/reformatter_style_config_test.py | 2 +- yapftests/yapf_test.py | 82 +++++------ yapftests/yapf_test_helper.py | 16 +-- 13 files changed, 253 insertions(+), 254 deletions(-) diff --git a/.flake8 b/.flake8 index 4fdb0fb53..bb1ce94e7 100644 --- a/.flake8 +++ b/.flake8 @@ -1,5 +1,7 @@ [flake8] ignore = + # 'toml' imported but unused + F401, # closing bracket does not match visual indentation E124, # continuation line over-indented for hanging indent @@ -11,10 +13,6 @@ ignore = # line break after binary operator W504 -exclude = - yapf/yapflib/py3compat.py - yapftests/* - disable-noqa indent-size = 2 max-line-length = 80 diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py index 7c9052374..8f1547696 100644 --- a/yapf/yapflib/py3compat.py +++ b/yapf/yapflib/py3compat.py @@ -27,9 +27,9 @@ StringIO = io.StringIO BytesIO = io.BytesIO - import codecs + import codecs # noqa: F811 - def open_with_encoding(filename, mode, encoding, newline=''): # pylint: disable=unused-argument + def open_with_encoding(filename, mode, encoding, newline=''): # pylint: disable=unused-argument # noqa return codecs.open(filename, mode=mode, encoding=encoding) import functools @@ -62,13 +62,13 @@ def fake_wrapper(user_function): return fake_wrapper - range = xrange + range = xrange # noqa: F821 from itertools import ifilter raw_input = raw_input import ConfigParser as configparser - CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser._boolean_states # pylint: disable=protected-access + CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser._boolean_states # pylint: disable=protected-access # noqa def EncodeAndWriteToStdout(s, encoding='utf-8'): diff --git a/yapftests/blank_line_calculator_test.py b/yapftests/blank_line_calculator_test.py index 193f41930..80dc55c21 100644 --- a/yapftests/blank_line_calculator_test.py +++ b/yapftests/blank_line_calculator_test.py @@ -249,7 +249,7 @@ def _(): # reason="https://github.com/pypa/setuptools/issues/706") def test_unicode_filename_in_sdist(self, sdist_unicode, tmpdir, monkeypatch): pass - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 01efece61..31184c4a3 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -525,7 +525,7 @@ def test_write_to_stdout(self): self.assertEqual(stream.getvalue(), s) def test_write_encoded_to_stdout(self): - s = '\ufeff# -*- coding: utf-8 -*-\nresult = "passed"\n' # pylint: disable=anomalous-unicode-escape-in-string + s = '\ufeff# -*- coding: utf-8 -*-\nresult = "passed"\n' # pylint: disable=anomalous-unicode-escape-in-string # noqa stream = BufferedByteStream() if py3compat.PY3 else py3compat.StringIO() with utils.stdout_redirector(stream): file_resources.WriteReformattedCode( diff --git a/yapftests/line_joiner_test.py b/yapftests/line_joiner_test.py index 6501bc883..67252a23c 100644 --- a/yapftests/line_joiner_test.py +++ b/yapftests/line_joiner_test.py @@ -74,7 +74,7 @@ def testSimpleMultipleLineStatementWithLargeIndent(self): def testOverColumnLimit(self): code = textwrap.dedent(u"""\ if instance(bbbbbbbbbbbbbbbbbbbbbbbbb, int): cccccccccccccccccccccccccc = ddddddddddddddddddddd - """) + """) # noqa self._CheckLineJoining(code, join_lines=False) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 8b48c487b..185d068c3 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -35,7 +35,7 @@ def testSplittingAllArgs(self): '{split_all_comma_separated_values: true, column_limit: 40}')) unformatted_code = textwrap.dedent("""\ responseDict = {"timestamp": timestamp, "someValue": value, "whatever": 120} - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ responseDict = { "timestamp": timestamp, @@ -60,7 +60,7 @@ def testSplittingAllArgs(self): unformatted_code = textwrap.dedent("""\ def foo(long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args): pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def foo(long_arg, really_long_arg, @@ -72,7 +72,7 @@ def foo(long_arg, self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) unformatted_code = textwrap.dedent("""\ foo_tuple = [long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args] - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ foo_tuple = [ long_arg, @@ -109,12 +109,13 @@ def foo(long_arg, def testSplittingTopLevelAllArgs(self): style.SetGlobalStyle( style.CreateStyleFromConfig( - '{split_all_top_level_comma_separated_values: true, column_limit: 40}' + '{split_all_top_level_comma_separated_values: true, ' + 'column_limit: 40}' )) # Works the same way as split_all_comma_separated_values unformatted_code = textwrap.dedent("""\ responseDict = {"timestamp": timestamp, "someValue": value, "whatever": 120} - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ responseDict = { "timestamp": timestamp, @@ -128,7 +129,7 @@ def testSplittingTopLevelAllArgs(self): unformatted_code = textwrap.dedent("""\ def foo(long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args): pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def foo(long_arg, really_long_arg, @@ -141,7 +142,7 @@ def foo(long_arg, # Works the same way as split_all_comma_separated_values unformatted_code = textwrap.dedent("""\ foo_tuple = [long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args] - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ foo_tuple = [ long_arg, @@ -280,7 +281,8 @@ def testBlankLinesBetweenTopLevelImportsAndVariables(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig( - '{based_on_style: yapf, blank_lines_between_top_level_imports_and_variables: 2}' + '{based_on_style: yapf, ' + 'blank_lines_between_top_level_imports_and_variables: 2}' )) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, @@ -390,7 +392,7 @@ def bar(): """) expected_formatted_code = """\ class foo(object):\n \n def foobar(self):\n \n pass\n \n def barfoo(self, x, y): # bar\n \n if x:\n \n return y\n\n\ndef bar():\n \n return 0 -""" +""" # noqa try: style.SetGlobalStyle( @@ -510,9 +512,7 @@ def testSingleComment(self): def testCommentsWithTrailingSpaces(self): unformatted_code = textwrap.dedent("""\ - # Thing 1 - # Thing 2 - """) + # Thing 1 \n# Thing 2 \n""") expected_formatted_code = textwrap.dedent("""\ # Thing 1 # Thing 2 @@ -694,7 +694,7 @@ def f(): def f(): assert port >= minimum, 'Unexpected port %d when minimum was %d.' % (port, minimum) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -772,7 +772,7 @@ def testListComprehensionPreferOneLineOverArithmeticSplit(self): def given(used_identifiers): return (sum(len(identifier) for identifier in used_identifiers) / len(used_identifiers)) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def given(used_identifiers): return (sum(len(identifier) for identifier in used_identifiers) / @@ -853,7 +853,7 @@ def testNoQueueSeletionInMiddleOfLine(self): # one are then splatted at the end of the line with no formatting. unformatted_code = """\ find_symbol(node.type) + "< " + " ".join(find_pattern(n) for n in node.child) + " >" -""" +""" # noqa expected_formatted_code = """\ find_symbol(node.type) + "< " + " ".join( find_pattern(n) for n in node.child) + " >" @@ -918,7 +918,7 @@ def testDictionaryMakerFormatting(self): 'yield_stmt': 'import_stmt', lambda: 'global_stmt': 'exec_stmt', 'assert_stmt': 'if_stmt', 'while_stmt': 'for_stmt', }) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ _PYTHON_STATEMENTS = frozenset({ lambda x, y: 'simple_stmt': 'small_stmt', @@ -949,7 +949,7 @@ def testSimpleMultilineCode(self): vvvvvvvvv) aaaaaaaaaaaaaa.bbbbbbbbbbbbbb.ccccccc(zzzzzzzzzzzz, xxxxxxxxxxx, yyyyyyyyyyyy, vvvvvvvvv) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -996,7 +996,7 @@ def f(): Residence: """+palace["Winter"]+"""
""" - ''') + ''') # noqa expected_formatted_code = textwrap.dedent('''\ def f(): email_text += """This is a really long docstring that goes over the column limit and is multi-line.

@@ -1005,7 +1005,7 @@ def f(): Residence: """ + palace["Winter"] + """
""" - ''') + ''') # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1057,7 +1057,7 @@ def _ProcessArgLists(self, node): child, subtype=_ARGLIST_TOKEN_TO_SUBTYPE.get(child.value, format_token.Subtype.NONE)) - ''') + ''') # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1082,13 +1082,13 @@ def testTrailingCommaAndBracket(self): def testI18n(self): code = textwrap.dedent("""\ N_('Some years ago - never mind how long precisely - having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world.') # A comment is here. - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) code = textwrap.dedent("""\ foo('Fake function call') #. Some years ago - never mind how long precisely - having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1115,7 +1115,7 @@ def g(): xxxxxxxxxxxxxxxxxxxxx( yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): pass - ''') + ''') # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1186,7 +1186,7 @@ def __init__(self, fieldname, #. Error message indicating an invalid e-mail address. message=N_('Please check your email address.'), **kwargs): pass - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1356,7 +1356,7 @@ def testSingleLineList(self): expected_formatted_code = textwrap.dedent("""\ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = aaaaaaaaaaa( ("...", "."), "..", "..............................................") - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1390,7 +1390,7 @@ def timeout(seconds=1): pass except: pass - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1436,14 +1436,14 @@ def testContinuationMarkers(self): "ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis "\\ "sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. "\\ "Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet" - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) code = textwrap.dedent("""\ from __future__ import nested_scopes, generators, division, absolute_import, with_statement, \\ print_function, unicode_literals - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1490,14 +1490,14 @@ def testEmptyContainers(self): 'output_dirs', [], 'Lorem ipsum dolor sit amet, consetetur adipiscing elit. Donec a diam lectus. ' 'Sed sit amet ipsum mauris. Maecenas congue.') - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testSplitStringsIfSurroundedByParens(self): unformatted_code = textwrap.dedent("""\ a = foo.bar({'xxxxxxxxxxxxxxxxxxxxxxx' 'yyyyyyyyyyyyyyyyyyyyyyyyyy': baz[42]} + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbb' 'cccccccccccccccccccccccccccccccc' 'ddddddddddddddddddddddddddddd') - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ a = foo.bar({'xxxxxxxxxxxxxxxxxxxxxxx' 'yyyyyyyyyyyyyyyyyyyyyyyyyy': baz[42]} + @@ -1563,7 +1563,7 @@ def bar(self): self.write(s=[ '%s%s %s' % ('many of really', 'long strings', '+ just makes up 81') ]) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1573,7 +1573,7 @@ def _(): if True: if contract == allow_contract and attr_dict.get(if_attribute) == has_value: return True - """) + """) # noqa expected_code = textwrap.dedent("""\ def _(): if True: @@ -1615,7 +1615,7 @@ def testUnaryNotOperator(self): if True: remote_checksum = self.get_checksum(conn, tmp, dest, inject, not directory_prepended, source) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1650,7 +1650,7 @@ def testUnbreakableNot(self): def test(): if not "Foooooooooooooooooooooooooooooo" or "Foooooooooooooooooooooooooooooo" == "Foooooooooooooooooooooooooooooo": pass - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1675,7 +1675,7 @@ def testSomething(self): ('aaaaaaaaaaaaa', 'bbbb'): 'ccccccccccccccccccccccccccccccccccccccccccc', ('aaaaaaaaaaaaa', 'bbbb'): 'ccccccccccccccccccccccccccccccccccccccccccc', } - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ class Test: @@ -1698,7 +1698,7 @@ def testEndingComment(self): a="something", b="something requiring comment which is quite long", # comment about b (pushes line over 79) c="something else, about which comment doesn't make sense") - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1752,7 +1752,7 @@ def testNoSplittingBeforeEndingSubscriptBracket(self): if True: if True: status = cf.describe_stacks(StackName=stackname)[u'Stacks'][0][u'StackStatus'] - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ if True: if True: @@ -1780,7 +1780,7 @@ def testNoSplittingOnSingleArgument(self): xxxxxxxxxxxxxx = ( re.search(r'(\\d+\\.\\d+\\.\\d+\\.)\\d+', aaaaaaa.bbbbbbbbbbbb).group(a.b) + re.search(r'\\d+\\.\\d+\\.\\d+\\.(\\d+)', ccccccc).group(c.d)) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1790,7 +1790,7 @@ def testSplittingArraysSensibly(self): while True: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list['bbbbbbbbbbbbbbbbbbbbbbbbb'].split(',') aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list('bbbbbbbbbbbbbbbbbbbbbbbbb').split(',') - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ while True: while True: @@ -1808,14 +1808,14 @@ class f: def __repr__(self): tokens_repr = ','.join(['{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens]) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ class f: def __repr__(self): tokens_repr = ','.join( ['{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens]) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1840,7 +1840,7 @@ def f(): pytree_utils.InsertNodesBefore( _CreateCommentsFromPrefix( comment_prefix, comment_lineno, comment_column, standalone=True)) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1872,7 +1872,7 @@ def testContiguousList(self): code = textwrap.dedent("""\ [retval1, retval2] = a_very_long_function(argument_1, argument2, argument_3, argument_4) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1922,7 +1922,7 @@ def succeeded(self, dddddddddddddd): if self.do_something: d.addCallback(lambda _: self.aaaaaa.bbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccccccc(dddddddddddddd)) return d - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ class SomeClass(object): do_something = True @@ -1956,7 +1956,7 @@ def testMultilineDictionaryKeys(self): ('vehicula convallis nulla. Vestibulum dictum nisl in malesuada finibus.',): 3 } - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ MAP_WITH_LONG_KEYS = { ('lorem ipsum', 'dolor sit amet'): @@ -1967,7 +1967,7 @@ def testMultilineDictionaryKeys(self): ('vehicula convallis nulla. Vestibulum dictum nisl in malesuada finibus.',): 3 } - """) + """) # noqa try: style.SetGlobalStyle( @@ -1993,13 +1993,14 @@ def method(self): } }] } - """) + """) # noqa try: style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: pep8, indent_width: 2, ' - 'continuation_indent_width: 4, indent_dictionary_value: True}')) + 'continuation_indent_width: 4, ' + 'indent_dictionary_value: True}')) uwlines = yapf_test_helper.ParseAndUnwrap(code) reformatted_code = reformatter.Reformat(uwlines) @@ -2018,7 +2019,7 @@ def testStableInlinedDictionaryFormatting(self): def _(): url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( value, urllib.urlencode({'action': 'update', 'parameter': value})) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def _(): url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( @@ -2072,7 +2073,7 @@ def a(): x for x, y in self._heap_this_is_very_long if x.route[0] == choice ] self._heap = [x for x in self._heap if x.route and x.route[0] == choice] - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -2089,7 +2090,7 @@ def testNoSplittingWhenBinPacking(self): long_argument_name_1=1, long_argument_name_2=2, long_argument_name_3=3, long_argument_name_4=4 ) - """) + """) # noqa try: style.SetGlobalStyle( @@ -2132,7 +2133,7 @@ def _(): if True: if True: boxes[id_] = np.concatenate((points.min(axis=0), qoints.max(axis=0))) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def _(): if True: @@ -2159,7 +2160,7 @@ def _pack_results_for_constraint_or(cls, combination, constraints): clue for clue in combination if not clue == Verifier.UNMATCHED ), constraints, InvestigationResult.OR ) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ class _(): @@ -2171,7 +2172,7 @@ def _pack_results_for_constraint_or(cls, combination, constraints): return cls._create_investigation_result( (clue for clue in combination if not clue == Verifier.UNMATCHED), constraints, InvestigationResult.OR) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2186,7 +2187,7 @@ def testSplittingArgumentsTerminatedByComma(self): a_very_long_function_name(long_argument_name_1, long_argument_name_2, long_argument_name_3, long_argument_name_4,) r =f0 (1, 2,3,) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3) @@ -2289,7 +2290,7 @@ def testDictionaryValuesOnOwnLines(self): 'jjjjjjjjjjjjjjjjjjjjjjjjjj': Check('QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ', '=', False), } - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2303,7 +2304,7 @@ def testDictionaryOnOwnLine(self): expected_formatted_code = textwrap.dedent("""\ doc = test_utils.CreateTestDocumentViaController( content={'a': 'b'}, branch_key=branch.key, collection_key=collection.key) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2353,7 +2354,7 @@ def testNestedListsInDictionary(self): 'cccccccccc': ('^21109', # PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP. ), } - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ _A = { 'cccccccccc': ('^^1',), @@ -2415,7 +2416,7 @@ def _(): }, ] breadcrumbs = [{'name': 'Admin', 'url': url_for(".home")}, {'title': title}] - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2435,18 +2436,18 @@ def _(): Environment.YYYYYYY: 'some text more text even more text yet ag', Environment.ZZZZZZZZZZZ: 'some text more text even more text yet again tex', } - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) def testNotInParams(self): unformatted_code = textwrap.dedent("""\ list("a long line to break the line. a long line to break the brk a long lin", not True) - """) + """) # noqa expected_code = textwrap.dedent("""\ list("a long line to break the line. a long line to break the brk a long lin", not True) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) @@ -2834,7 +2835,7 @@ def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def function( first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None @@ -2846,7 +2847,7 @@ def function( first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None ) -> None: pass - """) + """) # noqa try: style.SetGlobalStyle( @@ -2867,7 +2868,7 @@ def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def function( first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None @@ -2879,7 +2880,7 @@ def function( first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None ) -> None: pass - """) + """) # noqa try: style.SetGlobalStyle( @@ -2900,7 +2901,7 @@ def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None, third_a def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_and_last_argument=None): pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def function( first_argument_xxxxxxxxxxxxxxxx=(0,), @@ -2914,7 +2915,7 @@ def function( first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_and_last_argument=None ): pass - """) + """) # noqa try: style.SetGlobalStyle( @@ -2936,7 +2937,7 @@ def function(): def function(): some_var = ('a couple', 'small', 'elemens') return False - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def function(): some_var = ( @@ -2949,7 +2950,7 @@ def function(): def function(): some_var = ('a couple', 'small', 'elemens') return False - """) + """) # noqa try: style.SetGlobalStyle( @@ -2971,7 +2972,7 @@ def function(): def function(): some_var = ['a couple', 'small', 'elemens'] return False - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def function(): some_var = [ @@ -3006,7 +3007,7 @@ def function(): def function(): some_var = {1: 'a couple', 2: 'small', 3: 'elemens'} return False - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def function(): some_var = { @@ -3025,7 +3026,7 @@ def function(): def function(): some_var = {1: 'a couple', 2: 'small', 3: 'elemens'} return False - """) + """) # noqa try: style.SetGlobalStyle( diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index e95c96c1b..a3244443c 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -170,7 +170,7 @@ def _(): 'PyTypePyTypePyTypePyTypePyTypePyTypePyTypePyTypePyTypePyTypePyTypePyTypePyType' # pytype: disable=attribute-error 'CopybaraCopybaraCopybaraCopybaraCopybaraCopybaraCopybaraCopybaraCopybara' # copybara:strip ) -""" +""" # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -203,7 +203,7 @@ def testB120245013(self): class Foo(object): def testNoAlertForShortPeriod(self, rutabaga): self.targets[:][streamz_path,self._fillInOtherFields(streamz_path, {streamz_field_of_interest:True})] = series.Counter('1s', '+ 500x10000') -""" +""" # noqa expected_formatted_code = """\ class Foo(object): @@ -236,7 +236,7 @@ def xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( def testB111764402(self): unformatted_code = """\ x = self.stubs.stub(video_classification_map, 'read_video_classifications', (lambda external_ids, **unused_kwargs: {external_id: self._get_serving_classification('video') for external_id in external_ids})) -""" +""" # noqa expected_formatted_code = """\ x = self.stubs.stub(video_classification_map, 'read_video_classifications', (lambda external_ids, **unused_kwargs: { @@ -293,7 +293,7 @@ def potato(feeditems, browse_use_case=None): if kumquat: if not feeds_variants.variants['FEEDS_LOAD_PLAYLIST_VIDEOS_FOR_ALL_ITEMS'] and item.video: continue -""" +""" # noqa expected_formatted_code = """\ def potato(feeditems, browse_use_case=None): for item in turnip: @@ -403,13 +403,13 @@ def _(): aaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccc(\ eeeeeeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffffffffffffffffffffff.\ ggggggggggggggggggggggggggggggggg.hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh()) -""" +""" # noqa expected_formatted_code = """\ def _(): aaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccc( eeeeeeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffffffffffffffffffffff .ggggggggggggggggggggggggggggggggg.hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh()) -""" +""" # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -419,7 +419,7 @@ def f(): if (aaaaaaaaaaaaaa.bbbbbbbbbbbb.ccccc <= 0 and # pytype: disable=attribute-error ddddddddddd.eeeeeeeee == constants.FFFFFFFFFFFFFF): raise "yo" -""" +""" # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -493,7 +493,7 @@ def testB30500455(self): ] * [(name, 'type#' + name) for name in INITIAL_TYPES] + [ (name, 'function#' + name) for name in INITIAL_FUNCTIONS ] + [(name, 'const#' + name) for name in INITIAL_CONSTS]) -""" +""" # noqa expected_formatted_code = """\ INITIAL_SYMTAB = dict( [(name, 'exception#' + name) for name in INITIAL_EXCEPTIONS] * @@ -523,7 +523,7 @@ def testB37099651(self): lambda: function.call.mem.clients(FLAGS.some_flag_thingy, default_namespace=_LAZY_MEM_NAMESPACE, allow_pickle=True) # pylint: enable=g-long-lambda ) -""" +""" # noqa expected_formatted_code = """\ _MEMCACHE = lazy.MakeLazy( # pylint: disable=g-long-lambda @@ -551,7 +551,7 @@ def _(): | m.Window(m.Delta('1h')) | m.Join('successes', 'total') | m.Point(m.VAL['successes'] / m.VAL['total'])))) -""" +""" # noqa expected_formatted_code = """\ def _(): success_rate_stream_table = module.Precompute( @@ -684,7 +684,7 @@ def testB66011084(self): def testB67455376(self): unformatted_code = """\ sponge_ids.extend(invocation.id() for invocation in self._client.GetInvocationsByLabels(labels)) -""" +""" # noqa expected_formatted_code = """\ sponge_ids.extend(invocation.id() for invocation in self._client.GetInvocationsByLabels(labels)) @@ -764,7 +764,7 @@ def _(): query = ( m.Fetch(n.Raw('monarch.BorgTask', '/proc/container/memory/usage'), { 'borg_user': borguser, 'borg_job': jobname }) | o.Window(m.Align('5m')) | p.GroupBy(['borg_user', 'borg_job', 'borg_cell'], q.Mean())) -""" +""" # noqa expected_formatted_code = """\ def _(): query = ( @@ -815,7 +815,7 @@ def _(): region=region, forwardingRule=rule_name, body={'fingerprint': base64.urlsafe_b64encode('invalid_fingerprint')}).execute() -""" +""" # noqa expected_formatted_code = """\ def _(): with self.assertRaisesRegexp(errors.HttpError, 'Invalid'): @@ -843,7 +843,7 @@ def _(): def testB65241516(self): unformatted_code = """\ checkpoint_files = gfile.Glob(os.path.join(TrainTraceDir(unit_key, "*", "*"), embedding_model.CHECKPOINT_FILENAME + "-*")) -""" +""" # noqa expected_formatted_code = """\ checkpoint_files = gfile.Glob( os.path.join( @@ -903,7 +903,7 @@ def _(): ('/some/path/to/a/file/that/is/needed/by/this/process') } } - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def _(): X = { @@ -912,7 +912,7 @@ def _(): ('/some/path/to/a/file/that/is/needed/by/this/process') } } - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -921,7 +921,7 @@ def testB31063453(self): def _(): while ((not mpede_proc) or ((time_time() - last_modified) < FLAGS_boot_idle_timeout)): pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def _(): while ((not mpede_proc) or @@ -942,7 +942,7 @@ def _(): 'read': 'name/some-type-of-very-long-name-for-reading-perms', 'modify': 'name/some-other-type-of-very-long-name-for-modifying' }) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def _(): labelacl = Env( @@ -954,14 +954,14 @@ def _(): 'read': 'name/some-type-of-very-long-name-for-reading-perms', 'modify': 'name/some-other-type-of-very-long-name-for-modifying' }) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) def testB34682902(self): unformatted_code = textwrap.dedent("""\ logging.info("Mean angular velocity norm: %.3f", np.linalg.norm(np.mean(ang_vel_arr, axis=0))) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ logging.info("Mean angular velocity norm: %.3f", np.linalg.norm(np.mean(ang_vel_arr, axis=0))) @@ -1016,7 +1016,7 @@ def testB32931780(self): 'this is an entry', } } - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ environments = { 'prod': { @@ -1043,7 +1043,7 @@ def testB32931780(self): '.....': 'this is an entry', } } - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1125,7 +1125,7 @@ class _(): def __init__(self, metric, fields_cb=None): self._fields_cb = fields_cb or (lambda *unused_args, **unused_kwargs: {}) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1154,7 +1154,7 @@ def aaaaa(self, bbbbb, cccccccccccccc=None): # TODO(who): pylint: disable=unuse def xxxxx(self, yyyyy, zzzzzzzzzzzzzz=None): # A normal comment that runs over the column limit. return 1 - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ class _(): @@ -1166,7 +1166,7 @@ def xxxxx( yyyyy, zzzzzzzzzzzzzz=None): # A normal comment that runs over the column limit. return 1 - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1174,13 +1174,13 @@ def testB30760569(self): unformatted_code = textwrap.dedent("""\ {'1234567890123456789012345678901234567890123456789012345678901234567890': '1234567890123456789012345678901234567890'} - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ { '1234567890123456789012345678901234567890123456789012345678901234567890': '1234567890123456789012345678901234567890' } - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1190,7 +1190,7 @@ class Thing: def Function(self): thing.Scrape('/aaaaaaaaa/bbbbbbbbbb/ccccc/dddd/eeeeeeeeeeeeee/ffffffffffffff').AndReturn(42) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ class Thing: @@ -1233,7 +1233,7 @@ def lulz(): def lulz(): return (some_long_module_name.SomeLongClassName.some_long_attribute_name .some_long_method_name()) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1252,7 +1252,7 @@ def _(): 'lllllllllllll': None, # use the default } } - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def _(): xxxxxxxxxxxxxxxxxxx = { @@ -1280,7 +1280,7 @@ class _(): def _(): self.assertFalse( evaluation_runner.get_larps_in_eval_set('these_arent_the_larps')) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1291,7 +1291,7 @@ class _(): def __repr__(self): return '' % ( self._id, self._stub._stub.rpc_channel().target()) # pylint:disable=protected-access - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1325,14 +1325,14 @@ def testB29093579(self): def _(): _xxxxxxxxxxxxxxx(aaaaaaaa, bbbbbbbbbbbbbb.cccccccccc[ dddddddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffff]) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def _(): _xxxxxxxxxxxxxxx( aaaaaaaa, bbbbbbbbbbbbbb.cccccccccc[dddddddddddddddddddddddddddd .eeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffff]) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1381,7 +1381,7 @@ def testB27590179(self): False: self.bbb.cccccccccc(ddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee) }) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ if True: if True: @@ -1391,7 +1391,7 @@ def testB27590179(self): False: self.bbb.cccccccccc(ddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee) }) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1399,7 +1399,7 @@ def testB27266946(self): unformatted_code = textwrap.dedent("""\ def _(): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = (self.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccccccccccc) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def _(): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = ( @@ -1449,7 +1449,7 @@ def testB25165602(self): code = textwrap.dedent("""\ def f(): ids = {u: i for u, i in zip(self.aaaaa, xrange(42, 42 + len(self.aaaaaa)))} - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1488,7 +1488,7 @@ def testB25131481(self): 'materialize': lambda x: some_type_of_function('materialize ' + x.command_def), '#': lambda x: x # do nothing }) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ APPARENT_ACTIONS = ( 'command_type', @@ -1498,7 +1498,7 @@ def testB25131481(self): '#': lambda x: x # do nothing }) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1513,7 +1513,7 @@ def foo(): "PPPPPPPPPPPPPPPPPPPPP": FLAGS.aaaaaaaaaaaaaa + FLAGS.bbbbbbbbbbbbbbbbbbb, }) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def foo(): if True: @@ -1525,7 +1525,7 @@ def foo(): "PPPPPPPPPPPPPPPPPPPPP": FLAGS.aaaaaaaaaaaaaa + FLAGS.bbbbbbbbbbbbbbbbbbb, }) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1593,7 +1593,7 @@ def testB20551180(self): def foo(): if True: return (struct.pack('aaaa', bbbbbbbbbb, ccccccccccccccc, dddddddd) + eeeeeee) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def foo(): if True: @@ -1608,7 +1608,7 @@ def testB23944849(self): class A(object): def xxxxxxxxx(self, aaaaaaa, bbbbbbb=ccccccccccc, dddddd=300, eeeeeeeeeeeeee=None, fffffffffffffff=0): pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ class A(object): @@ -1628,7 +1628,7 @@ def testB23935890(self): class F(): def functioni(self, aaaaaaa, bbbbbbb, cccccc, dddddddddddddd, eeeeeeeeeeeeeee): pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ class F(): @@ -1660,7 +1660,7 @@ def _(): | m.ggggggg(bbbbbbbbbbbbbbb)) | m.jjjj() | m.ppppp(m.vvv[0] + m.vvv[1])) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1678,7 +1678,7 @@ def f(): | m.ggggggg(self.gggggggg)) | m.jjjj() | m.ppppp(m.VAL[0] / m.VAL[1])) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1686,7 +1686,7 @@ def testB20016122(self): unformatted_code = textwrap.dedent("""\ from a_very_long_or_indented_module_name_yada_yada import (long_argument_1, long_argument_2) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ from a_very_long_or_indented_module_name_yada_yada import ( long_argument_1, long_argument_2) @@ -1719,7 +1719,7 @@ def __eq__(self, other): and self.gggggg == other.gggggg and self.hhh == other.hhh and len(self.iiiiiiii) == len(other.iiiiiiii) and all(jjjjjjj in other.iiiiiiii for jjjjjjj in self.iiiiiiii)) - """) + """) # noqa try: style.SetGlobalStyle( @@ -1736,7 +1736,7 @@ def testB22527411(self): def f(): if True: aaaaaa.bbbbbbbbbbbbbbbbbbbb[-1].cccccccccccccc.ddd().eeeeeeee(ffffffffffffff) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def f(): if True: @@ -1762,7 +1762,7 @@ def main(unused_argv): 'xxx': '%s/cccccc/ddddddddddddddddddd.jar' % (eeeeee.FFFFFFFFFFFFFFFFFF), } - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1785,7 +1785,7 @@ def testB20605036(self): 'dddddddddddddddddddddddddddddddddddddddddd', } } - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1834,7 +1834,7 @@ def do_nothing(self, class_1_count): class_0_count=class_0_count, class_1_name=self.class_1_name, class_1_count=class_1_count)) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1843,7 +1843,7 @@ def testB19626808(self): if True: aaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbb( 'ccccccccccc', ddddddddd='eeeee').fffffffff([ggggggggggggggggggggg]) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -1907,7 +1907,7 @@ def bar(self): fffffffffff=(aaaaaaa.bbbbbbbb.ccccccc.dddddddddddddddddddd .Mmmmmmmmmmmmmmmmmm(-1, 'permission error'))): self.assertRaises(nnnnnnnnnnnnnnnn.ooooo, ppppp.qqqqqqqqqqqqqqqqq) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ class Foo(object): @@ -1918,7 +1918,7 @@ def bar(self): aaaaaaa.bbbbbbbb.ccccccc.dddddddddddddddddddd.Mmmmmmmmmmmmmmmmmm( -1, 'permission error'))): self.assertRaises(nnnnnnnnnnnnnnnn.ooooo, ppppp.qqqqqqqqqqqqqqqqq) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2054,7 +2054,7 @@ def bbbbbbbbbb(self): os.path.join(aaaaa.bbbbb.ccccccccccc, DDDDDDDDDDDDDDD, "eeeeeeeee ffffffffff"), "rb") as gggggggggggggggggggg: print(gggggggggggggggggggg) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2092,7 +2092,7 @@ def testB16783631(self): eeeeeeeee=self.fffffffffffff )as gggg: pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ if True: with aaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccc( @@ -2107,7 +2107,7 @@ def testB16572361(self): def foo(self): def bar(my_dict_name): self.my_dict_name['foo-bar-baz-biz-boo-baa-baa'].IncrementBy.assert_called_once_with('foo_bar_baz_boo') - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def foo(self): @@ -2115,7 +2115,7 @@ def bar(my_dict_name): self.my_dict_name[ 'foo-bar-baz-biz-boo-baa-baa'].IncrementBy.assert_called_once_with( 'foo_bar_baz_boo') - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2125,7 +2125,7 @@ def testB15884241(self): if 1: for row in AAAA: self.create(aaaaaaaa="/aaa/bbbb/cccc/dddddd/eeeeeeeeeeeeeeeeeeeeeeeeee/%s" % row [0].replace(".foo", ".bar"), aaaaa=bbb[1], ccccc=bbb[2], dddd=bbb[3], eeeeeeeeeee=[s.strip() for s in bbb[4].split(",")], ffffffff=[s.strip() for s in bbb[5].split(",")], gggggg=bbb[6]) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ if 1: if 1: @@ -2139,7 +2139,7 @@ def testB15884241(self): eeeeeeeeeee=[s.strip() for s in bbb[4].split(",")], ffffffff=[s.strip() for s in bbb[5].split(",")], gggggg=bbb[6]) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2152,7 +2152,7 @@ def main(unused_argv): bad_slice = map(math.sqrt, an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A]) a_long_name_slicing = an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A] bad_slice = ("I am a crazy, no good, string what's too long, etc." + " no really ")[:ARBITRARY_CONSTANT_A] - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def main(unused_argv): ARBITRARY_CONSTANT_A = 10 @@ -2164,7 +2164,7 @@ def main(unused_argv): ARBITRARY_CONSTANT_A] bad_slice = ("I am a crazy, no good, string what's too long, etc." + " no really ")[:ARBITRARY_CONSTANT_A] - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2174,7 +2174,7 @@ def testB15597568(self): if True: if True: print(("Return code was %d" + (", and the process timed out." if did_time_out else ".")) % errorcode) -""" +""" # noqa expected_formatted_code = """\ if True: if True: @@ -2189,11 +2189,11 @@ def testB15597568(self): def testB15542157(self): unformatted_code = textwrap.dedent("""\ aaaaaaaaaaaa = bbbb.ccccccccccccccc(dddddd.eeeeeeeeeeeeee, ffffffffffffffffff, gggggg.hhhhhhhhhhhhhhhhh) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaaaa = bbbb.ccccccccccccccc(dddddd.eeeeeeeeeeeeee, ffffffffffffffffff, gggggg.hhhhhhhhhhhhhhhhh) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2213,7 +2213,7 @@ def testB15438132(self): iiiiiiiiiiiiiiiiiii.jjjjjjjjjj.kkkkkkk, lllll.mm), nnnnnnnnnn=ooooooo.pppppppppp) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ if aaaaaaa.bbbbbbbbbb: cccccc.dddddddddd(eeeeeeeeeee=fffffffffffff.gggggggggggggggggg) @@ -2228,7 +2228,7 @@ def testB15438132(self): dddddddddddd=eeeeeeeeeeeeeeeeeee.fffffffffffffffff( gggggg.hh, iiiiiiiiiiiiiiiiiii.jjjjjjjjjj.kkkkkkk, lllll.mm), nnnnnnnnnn=ooooooo.pppppppppp) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2256,7 +2256,7 @@ def foo1(parameter_1, parameter_2, parameter_3, parameter_4, \ def foo1(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6): pass - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2264,11 +2264,11 @@ def testB13900309(self): unformatted_code = textwrap.dedent("""\ self.aaaaaaaaaaa( # A comment in the middle of it all. 948.0/3600, self.bbb.ccccccccccccccccccccc(dddddddddddddddd.eeee, True)) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ self.aaaaaaaaaaa( # A comment in the middle of it all. 948.0 / 3600, self.bbb.ccccccccccccccccccccc(dddddddddddddddd.eeee, True)) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2283,7 +2283,7 @@ def testB13900309(self): unformatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc().dddddddddddddddddddddddddd(1, 2, 3, 4) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc( ).dddddddddddddddddddddddddd(1, 2, 3, 4) @@ -2293,7 +2293,7 @@ def testB13900309(self): unformatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc(x).dddddddddddddddddddddddddd(1, 2, 3, 4) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc( x).dddddddddddddddddddddddddd(1, 2, 3, 4) @@ -2303,11 +2303,11 @@ def testB13900309(self): unformatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx).dddddddddddddddddddddddddd(1, 2, 3, 4) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa( xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx).dddddddddddddddddddddddddd(1, 2, 3, 4) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -2341,7 +2341,7 @@ def testB67935687(self): expected_formatted_code = textwrap.dedent("""\ shelf_renderer.expand_text = text.translate_to_unicode(expand_text % {'creator': creator}) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) diff --git a/yapftests/reformatter_facebook_test.py b/yapftests/reformatter_facebook_test.py index 289aa8534..2e6b1d7db 100644 --- a/yapftests/reformatter_facebook_test.py +++ b/yapftests/reformatter_facebook_test.py @@ -53,7 +53,7 @@ def overly_long_function_name( first_argument_on_the_same_line, second_argument_makes_the_line_too_long ): pass - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -151,7 +151,7 @@ def testBrokenIdempotency(self): pass except (IOError, OSError, LookupError, RuntimeError, OverflowError) as exception: pass - """) + """) # noqa pass1_code = textwrap.dedent("""\ try: pass @@ -201,7 +201,7 @@ def testSimpleDedenting(self): unformatted_code = textwrap.dedent("""\ if True: self.assertEqual(result.reason_not_added, "current preflight is still running") - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ if True: self.assertEqual( @@ -220,7 +220,7 @@ def baz(cls, clues_list, effect, constraints, constraint_manager): if clues_lists: return cls.single_constraint_not(clues_lists, effect, constraints[0], constraint_manager) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ class Foo: class Bar: @@ -230,7 +230,7 @@ def baz(cls, clues_list, effect, constraints, constraint_manager): return cls.single_constraint_not( clues_lists, effect, constraints[0], constraint_manager ) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -241,7 +241,7 @@ def _(): cls.effect_clues = { 'effect': Clue((cls.effect_time, 'apache_host'), effect_line, 40) } - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -283,7 +283,7 @@ def _pack_results_for_constraint_or(): ('localhost', os.path.join(path, 'node_1.log'), super_parser), ('localhost', os.path.join(path, 'node_2.log'), super_parser) ] - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ class Foo(): def _pack_results_for_constraint_or(): @@ -319,7 +319,7 @@ def _pack_results_for_constraint_or(): ('localhost', os.path.join(path, 'node_1.log'), super_parser), ('localhost', os.path.join(path, 'node_2.log'), super_parser) ] - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -331,7 +331,7 @@ def _(): effect_line_offset, line_content, LineSource('localhost', xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) ) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(uwlines)) @@ -374,7 +374,7 @@ def _pack_results_for_constraint_or(cls, combination, constraints): (clue for clue in combination if not clue == Verifier.UNMATCHED), constraints, InvestigationResult.OR ) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(code) reformatted_code = reformatter.Reformat(uwlines) self.assertCodeEqual(code, reformatted_code) @@ -388,8 +388,8 @@ def testCommentWithNewlinesInPrefix(self): def foo(): if 0: return False - - + + #a deadly comment elif 1: return True @@ -401,7 +401,7 @@ def foo(): def foo(): if 0: return False - + #a deadly comment elif 1: return True @@ -416,7 +416,7 @@ def testIfStmtClosingBracket(self): unformatted_code = """\ if (isinstance(value , (StopIteration , StopAsyncIteration )) and exc.__cause__ is value_asdfasdfasdfasdfsafsafsafdasfasdfs): return False -""" +""" # noqa expected_formatted_code = """\ if ( isinstance(value, (StopIteration, StopAsyncIteration)) and diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index c70ec49dc..b07ae1e3a 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -132,7 +132,7 @@ def f(): zzzzz = '%s-%s'.ww(xxxxxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxx.yyy + 1) zzzzz = '%s-%s' % (xxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxxxxxx + 1) zzzzz = '%s-%s'.ww(xxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxxxxxx + 1) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def f(): if True: @@ -172,7 +172,7 @@ def g(): xxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb' ): pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def f(): @@ -181,7 +181,7 @@ def g(): and xxxxxxxxxxxxxxxxxxxx( yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): pass - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -189,7 +189,7 @@ def testIndentSizeChanging(self): unformatted_code = textwrap.dedent("""\ if True: runtime_mins = (program_end_time - program_start_time).total_seconds() / 60.0 - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ if True: runtime_mins = (program_end_time - @@ -212,7 +212,7 @@ def h(): for connection in itertools.chain(branch.contact, branch.address, morestuff.andmore.andmore.andmore.andmore.andmore.andmore.andmore): dosomething(connection) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ if (aaaaaaaaaaaaaa + bbbbbbbbbbbbbbbb == ccccccccccccccccc and xxxxxxxxxxxxx or yyyyyyyyyyyyyyyyy): @@ -233,7 +233,7 @@ def h(): branch.contact, branch.address, morestuff.andmore.andmore.andmore.andmore.andmore.andmore.andmore): dosomething(connection) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -250,7 +250,7 @@ def foo(): update.message.supergroup_chat_created or update.message.channel_chat_created or update.message.migrate_to_chat_id or update.message.migrate_from_chat_id or update.message.pinned_message) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def foo(): return bool( @@ -263,7 +263,7 @@ def foo(): or update.message.migrate_to_chat_id or update.message.migrate_from_chat_id or update.message.pinned_message) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -275,13 +275,13 @@ def testContiguousListEndingWithComment(self): if True: if True: keys.append(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) # may be unassigned. - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ if True: if True: keys.append( aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) # may be unassigned. - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -293,7 +293,7 @@ def testSplittingBeforeFirstArgument(self): unformatted_code = textwrap.dedent("""\ a_very_long_function_name(long_argument_name_1=1, long_argument_name_2=2, long_argument_name_3=3, long_argument_name_4=4) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ a_very_long_function_name( long_argument_name_1=1, @@ -311,7 +311,7 @@ def testSplittingExpressionsInsideSubscripts(self): unformatted_code = textwrap.dedent("""\ def foo(): df = df[(df['campaign_status'] == 'LIVE') & (df['action_status'] == 'LIVE')] - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def foo(): df = df[(df['campaign_status'] == 'LIVE') @@ -390,7 +390,7 @@ def testNoSplitBeforeDictValue(self): 'description': _("Lorem ipsum dolor met sit amet elit, si vis pacem para bellum " "elites nihi very long string."), } - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ some_dict = { 'title': _("I am example data"), @@ -399,21 +399,21 @@ def testNoSplitBeforeDictValue(self): "elites nihi very long string." ), } - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) unformatted_code = textwrap.dedent("""\ X = {'a': 1, 'b': 2, 'key': this_is_a_function_call_that_goes_over_the_column_limit_im_pretty_sure()} - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ X = { 'a': 1, 'b': 2, 'key': this_is_a_function_call_that_goes_over_the_column_limit_im_pretty_sure() } - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -423,7 +423,7 @@ def testNoSplitBeforeDictValue(self): 'category': category, 'role': forms.ModelChoiceField(label=_("Role"), required=False, queryset=category_roles, initial=selected_role, empty_label=_("No access"),), } - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ attrs = { 'category': category, @@ -446,7 +446,7 @@ def testNoSplitBeforeDictValue(self): required=False, help_text=_("Optional CSS class used to customize this category appearance from templates."), ) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ css_class = forms.CharField( label=_("CSS class"), @@ -455,7 +455,7 @@ def testNoSplitBeforeDictValue(self): "Optional CSS class used to customize this category appearance from templates." ), ) - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -528,7 +528,7 @@ def testSplitBeforeArithmeticOperators(self): unformatted_code = """\ def _(): raise ValueError('This is a long message that ends with an argument: ' + str(42)) -""" +""" # noqa expected_formatted_code = """\ def _(): raise ValueError('This is a long message that ends with an argument: ' @@ -604,7 +604,7 @@ def __init__(self, title: Optional[str], diffs: Collection[BinaryDiff] = (), cha justify: str = 'rjust'): self._cs = charset self._preprocess = preprocess - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ class _(): @@ -654,7 +654,7 @@ def testTwoWordComparisonOperators(self): unformatted_code = textwrap.dedent("""\ _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl is not ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj) _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl not in {ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj}) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl is not ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj) @@ -687,7 +687,7 @@ def testStableInlinedDictionaryFormatting(self): def _(): url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( value, urllib.urlencode({'action': 'update', 'parameter': value})) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def _(): url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index ae557552c..dbf39309a 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -36,7 +36,7 @@ def testTypedNames(self): unformatted_code = textwrap.dedent("""\ def x(aaaaaaaaaaaaaaa:int,bbbbbbbbbbbbbbbb:str,ccccccccccccccc:dict,eeeeeeeeeeeeee:set={1, 2, 3})->bool: pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def x(aaaaaaaaaaaaaaa: int, bbbbbbbbbbbbbbbb: str, @@ -51,12 +51,12 @@ def testTypedNameWithLongNamedArg(self): unformatted_code = textwrap.dedent("""\ def func(arg=long_function_call_that_pushes_the_line_over_eighty_characters()) -> ReturnType: pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def func(arg=long_function_call_that_pushes_the_line_over_eighty_characters() ) -> ReturnType: pass - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -253,7 +253,7 @@ def _ReduceAbstractContainers( self, *args: Optional[automation_converter.PyiCollectionAbc]) -> List[ automation_converter.PyiCollectionAbc]: pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def _ReduceAbstractContainers( self, *args: Optional[automation_converter.PyiCollectionAbc] @@ -297,7 +297,7 @@ def open_file(file, mode='r', buffering=-1, encoding=None, errors=None, newline= def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): pass -""" +""" # noqa expected_formatted_code = """\ async def open_file( file, @@ -454,7 +454,7 @@ def testParameterListIndentationConflicts(self): def raw_message( # pylint: disable=too-many-arguments self, text, user_id=1000, chat_type='private', forward_date=None, forward_from=None): pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def raw_message( # pylint: disable=too-many-arguments self, diff --git a/yapftests/reformatter_style_config_test.py b/yapftests/reformatter_style_config_test.py index d77c19700..9c258ca1e 100644 --- a/yapftests/reformatter_style_config_test.py +++ b/yapftests/reformatter_style_config_test.py @@ -155,7 +155,7 @@ def testNoSplitBeforeFirstArgumentStyle1(self): plt.plot(veryverylongvariablename, veryverylongvariablename, marker="x", color="r") - """) + """) # noqa uwlines = yapf_test_helper.ParseAndUnwrap(formatted_code) self.assertCodeEqual(formatted_code, reformatter.Reformat(uwlines)) finally: diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 4e062cf36..e11604302 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -202,7 +202,7 @@ def testEnabledDisabledSameComment(self): # yapf: disable a(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, ccccccccccccccccccccccccccccccc, ddddddddddddddddddddddd, eeeeeeeeeeeeeeeeeeeeeeeeeee) # yapf: enable - """) + """) # noqa with utils.TempFileContents(self.test_tmpdir, code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(code, formatted_code) @@ -540,7 +540,7 @@ def testSetCustomStyleSpacesBeforeComment(self): expected_formatted_code = textwrap.dedent("""\ a_very_long_statement_that_extends_way_beyond # Comment short # This is a shorter statement - """) + """) # noqa style_file = textwrap.dedent(u'''\ [style] spaces_before_comment = 15, 20 @@ -576,7 +576,7 @@ def f(): subprocess.check_call(YAPF_BINARY + ['--diff', filepath], stdout=out) except subprocess.CalledProcessError as e: # Indicates the text changed. - self.assertEqual(e.returncode, 1) # pylint: disable=g-assert-in-except + self.assertEqual(e.returncode, 1) # pylint: disable=g-assert-in-except # noqa def testReformattingSpecificLines(self): unformatted_code = textwrap.dedent("""\ @@ -588,7 +588,7 @@ def h(): def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and @@ -599,7 +599,7 @@ def h(): def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass - """) + """) # noqa # TODO(ambv): the `expected_formatted_code` here is not PEP8 compliant, # raising "E129 visually indented line with same indent as next logical # line" with flake8. @@ -639,7 +639,7 @@ def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass # yapf: enable - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and @@ -652,7 +652,7 @@ def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass # yapf: enable - """) + """) # noqa self.assertYapfReformats(unformatted_code, expected_formatted_code) def testReformattingSkippingToEndOfFile(self): @@ -672,7 +672,7 @@ def e(): xxxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and @@ -691,7 +691,7 @@ def e(): xxxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): pass - """) + """) # noqa self.assertYapfReformats(unformatted_code, expected_formatted_code) def testReformattingSkippingSingleLine(self): @@ -703,7 +703,7 @@ def h(): def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): # yapf: disable pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and @@ -714,7 +714,7 @@ def h(): def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): # yapf: disable pass - """) + """) # noqa self.assertYapfReformats(unformatted_code, expected_formatted_code) def testDisableWholeDataStructure(self): @@ -758,7 +758,7 @@ def h(): def g(): if (xxxxxxxxxxxx.yyyyyyyy (zzzzzzzzzzzzz [0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): # yapf: disable pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and @@ -769,7 +769,7 @@ def h(): def g(): if (xxxxxxxxxxxx.yyyyyyyy (zzzzzzzzzzzzz [0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): # yapf: disable pass - """) + """) # noqa self.assertYapfReformats(unformatted_code, expected_formatted_code) def testRetainingVerticalWhitespace(self): @@ -784,7 +784,7 @@ def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and @@ -797,7 +797,7 @@ def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass - """) + """) # noqa self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -902,7 +902,7 @@ def f(): Residence: """+palace["Winter"]+"""
""" - ''') + ''') # noqa expected_formatted_code = textwrap.dedent('''\ foo = 42 def f(): @@ -912,7 +912,7 @@ def f(): Residence: """+palace["Winter"]+"""
""" - ''') + ''') # noqa self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -1008,7 +1008,7 @@ def aaaaaaaaaaaaa(self): 'eeeeeeeeeeeeeeeeeeeeeeeee.%s' % c.ffffffffffff), gggggggggggg.hhhhhhhhh(c, c.ffffffffffff)) iiiii = jjjjjjjjjjjjjj.iiiii - """) + """) # noqa self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -1058,7 +1058,7 @@ def aaaaaaaaaaaaa(self): 'eeeeeeeeeeeeeeeeeeeeeeeee.%s' % c.ffffffffffff), gggggggggggg.hhhhhhhhh(c, c.ffffffffffff)) iiiii = jjjjjjjjjjjjjj.iiiii - """) + """) # noqa self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -1128,7 +1128,7 @@ def overly_long_function_name( first_argument_on_the_same_line, second_argument_makes_the_line_too_long ): pass - """) + """) # noqa self.assertYapfReformats( unformatted_code, expected_formatted_fb_code, @@ -1247,7 +1247,7 @@ def foo_function(): def foo_function(): if True: pass -""" +""" # noqa: W191,E101 style_contents = u"""\ [style] based_on_style = yapf @@ -1271,7 +1271,7 @@ def f(): 'hello', 'world', ] -""" +""" # noqa: W191,E101 style_contents = u"""\ [style] based_on_style = yapf @@ -1296,7 +1296,7 @@ def foo_function( 'hello', 'world', ] -""" +""" # noqa: W191,E101 style_contents = u"""\ [style] based_on_style = yapf @@ -1324,7 +1324,7 @@ def foo_function(arg1, arg2, 'hello', 'world', ] -""" +""" # noqa: W191,E101 style_contents = u"""\ [style] based_on_style = yapf @@ -1622,11 +1622,11 @@ def testSimple(self): """) expected_formatted_code = textwrap.dedent("""\ foo = '1' # Aligned at first list value - + foo = '2__<15>' # Aligned at second list value - + foo = '3____________<25>' # Aligned at third list value - + foo = '4______________________<35>' # Aligned beyond list values """) self._Check(unformatted_code, expected_formatted_code) @@ -1705,7 +1705,7 @@ def testBlockCommentSuffix(self): # Line 6 # Aligned with prev comment block - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ func(1) # Line 1 func(2) # Line 2 @@ -1715,7 +1715,7 @@ def testBlockCommentSuffix(self): # Line 6 # Aligned with prev comment block - """) + """) # noqa self._Check(unformatted_code, expected_formatted_code) def testBlockIndentedFuncSuffix(self): @@ -1732,14 +1732,14 @@ def testBlockIndentedFuncSuffix(self): def Func(): pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ if True: func(1) # Line 1 func(2) # Line 2 # Line 3 func(3) # Line 4 - + # Line 5 - SpliceComments makes this a new block # Line 6 @@ -1760,7 +1760,7 @@ def testBlockIndentedCommentSuffix(self): func(3) # Line 4 # Line 5 # Line 6 - + # Not aligned """) expected_formatted_code = textwrap.dedent("""\ @@ -1787,9 +1787,9 @@ def testBlockMultiIndented(self): func(3) # Line 4 # Line 5 # Line 6 - + # Not aligned - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ if True: if True: @@ -1800,7 +1800,7 @@ def testBlockMultiIndented(self): func(3) # Line 4 # Line 5 # Line 6 - + # Not aligned """) self._Check(unformatted_code, expected_formatted_code) @@ -1923,7 +1923,7 @@ def testStandard(self): { 1: 2 } { k: v for k, v in other.items() } { k for k in [1, 2, 3] } - + # The following statements should not change {} {1 : 2} # yapf: disable @@ -1931,7 +1931,7 @@ def testStandard(self): # yapf: disable {1 : 2} # yapf: enable - + # Dict settings should not impact lists or tuples [1, 2] (3, 4) @@ -1982,12 +1982,12 @@ def testStandard(self): index[a, b] [] [v for v in [1,2,3] if v & 1] # yapf: disable - + # yapf: disable [a,b,c] [4,5,] # yapf: enable - + # List settings should not impact dicts or tuples {a: b} (1, 2) @@ -2040,14 +2040,14 @@ def testStandard(self): (this_func or that_func)(3, 4) if (True and False): pass () - + (0, 1) # yapf: disable # yapf: disable (0, 1) (2, 3) # yapf: enable - + # Tuple settings should not impact dicts or lists {a: b} [3, 4] diff --git a/yapftests/yapf_test_helper.py b/yapftests/yapf_test_helper.py index f6a2b66b2..df89b7013 100644 --- a/yapftests/yapf_test_helper.py +++ b/yapftests/yapf_test_helper.py @@ -41,17 +41,17 @@ def assertCodeEqual(self, expected_code, code): if code != expected_code: msg = ['Code format mismatch:', 'Expected:'] linelen = style.Get('COLUMN_LIMIT') - for l in expected_code.splitlines(): - if len(l) > linelen: - msg.append('!> %s' % l) + for line in expected_code.splitlines(): + if len(line) > linelen: + msg.append('!> %s' % line) else: - msg.append(' > %s' % l) + msg.append(' > %s' % line) msg.append('Actual:') - for l in code.splitlines(): - if len(l) > linelen: - msg.append('!> %s' % l) + for line in code.splitlines(): + if len(line) > linelen: + msg.append('!> %s' % line) else: - msg.append(' > %s' % l) + msg.append(' > %s' % line) msg.append('Diff:') msg.extend( difflib.unified_diff( From 3747f0673f59634761d96b80d5672d5a4c8390fd Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 8 Nov 2021 01:36:48 -0800 Subject: [PATCH 510/719] Cleanup of the FormatToken interface Don't rely upon the original "pytree node" object. This helps isolate the lib2to3 objects from yapf. --- CHANGELOG | 2 + yapf/yapflib/format_decision_state.py | 26 ++++---- yapf/yapflib/format_token.py | 92 +++++++++------------------ yapf/yapflib/reformatter.py | 4 +- yapf/yapflib/unwrapped_line.py | 8 +-- yapftests/reformatter_basic_test.py | 13 ++-- 6 files changed, 55 insertions(+), 90 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ecbda460c..13e03a7d0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,8 @@ - Change tests to support "pytest". - Reformat so that "flake8" is happy. - Use GitHub Actions instead of Travis for CI. +- Clean up the FormatToken interface to limit how much it relies upon the + pytree node object. ### Fixed - Enable `BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF` knob for "pep8" style, so method definitions inside a class are surrounded by a single blank line as diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 3c0db37ab..6c3c0fd16 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -132,7 +132,7 @@ def CanSplit(self, must_split): current = self.next_token previous = current.previous_token - if current.is_pseudo_paren: + if current.is_pseudo: return False if (not must_split and @@ -171,7 +171,7 @@ def MustSplit(self): current = self.next_token previous = current.previous_token - if current.is_pseudo_paren: + if current.is_pseudo: return False if current.must_break_before: @@ -268,7 +268,7 @@ def SurroundedByParens(token): token = token.next_token return False - if (previous.value == '(' and not previous.is_pseudo_paren and + if (previous.value == '(' and not previous.is_pseudo and not unwrapped_line.IsSurroundedByBrackets(previous)): pptoken = previous.previous_token if (pptoken and not pptoken.is_name and not pptoken.is_keyword and @@ -350,7 +350,7 @@ def SurroundedByParens(token): return True if (format_token.Subtype.DICTIONARY_VALUE in current.subtypes or - (previous.is_pseudo_paren and previous.value == '(' and + (previous.is_pseudo and previous.value == '(' and not current.is_comment)): # Split before the dictionary value if we can't fit every dictionary # entry on its own line. @@ -674,7 +674,7 @@ def _AddTokenOnNewline(self, dry_run, must_split): # Don't penalize for a must split. return penalty - if previous.is_pseudo_paren and previous.value == '(': + if previous.is_pseudo and previous.value == '(': # Small penalty for splitting after a pseudo paren. penalty += 50 @@ -734,7 +734,7 @@ def MoveStateToNextToken(self): if is_multiline_string: # This is a multiline string. Only look at the first line. self.column += len(current.value.split('\n')[0]) - elif not current.is_pseudo_paren: + elif not current.is_pseudo: self.column += len(current.value) self.next_token = self.next_token.next_token @@ -965,7 +965,7 @@ def _GetNewlineColumn(self): return previous.column if style.Get('INDENT_DICTIONARY_VALUE'): - if previous and (previous.value == ':' or previous.is_pseudo_paren): + if previous and (previous.value == ':' or previous.is_pseudo): if format_token.Subtype.DICTIONARY_VALUE in current.subtypes: return top_of_stack.indent @@ -993,7 +993,7 @@ def _GetNewlineColumn(self): def _FitsOnLine(self, start, end): """Determines if line between start and end can fit on the current line.""" length = end.total_length - start.total_length - if not start.is_pseudo_paren: + if not start.is_pseudo: length += len(start.value) return length + self.column <= self.column_limit @@ -1008,7 +1008,7 @@ def PreviousNonCommentToken(tok): def ImplicitStringConcatenation(tok): num_strings = 0 - if tok.is_pseudo_paren: + if tok.is_pseudo: tok = tok.next_token while tok.is_string: num_strings += 1 @@ -1021,7 +1021,7 @@ def DictValueIsContainer(opening, closing): return False colon = opening.previous_token while colon: - if not colon.is_pseudo_paren: + if not colon.is_pseudo: break colon = colon.previous_token if not colon or colon.value != ':': @@ -1048,7 +1048,7 @@ def DictValueIsContainer(opening, closing): entry_start = current if current.OpensScope(): if ((current.value == '{' or - (current.is_pseudo_paren and current.next_token.value == '{') and + (current.is_pseudo and current.next_token.value == '{') and format_token.Subtype.DICTIONARY_VALUE in current.subtypes) or ImplicitStringConcatenation(current)): # A dictionary entry that cannot fit on a single line shouldn't matter @@ -1141,13 +1141,13 @@ def _IsArgumentToFunction(token): def _GetOpeningBracket(current): """Get the opening bracket containing the current token.""" - if current.matching_bracket and not current.is_pseudo_paren: + if current.matching_bracket and not current.is_pseudo: return current if current.OpensScope() else current.matching_bracket while current: if current.ClosesScope(): current = current.matching_bracket - elif current.is_pseudo_paren: + elif current.is_pseudo: current = current.previous_token elif current.OpensScope(): return current diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 92c26ee57..0f3cb606e 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -131,18 +131,27 @@ def __init__(self, node): self.whitespace_prefix = '' self.can_break_before = False self.must_break_before = False - self.total_length = 0 # TODO(morbo): Think up a better name. + self.total_length = 0 self.split_penalty = 0 + self.type = node.type + self.column = node.column + self.lineno = node.lineno + + self.spaces_required_before = 0 if self.is_comment: self.spaces_required_before = style.Get('SPACES_BEFORE_COMMENT') - else: - self.spaces_required_before = 0 + self.value = node.value if self.is_continuation: - self.value = self.node.value.rstrip() - else: - self.value = self.node.value + self.value = node.value.rstrip() + + subtypes = pytree_utils.GetNodeAnnotation(node, + pytree_utils.Annotation.SUBTYPE) + self.subtypes = [Subtype.NONE] if subtypes is None else subtypes + self.name = pytree_utils.NodeName(node) + self.is_pseudo = hasattr(node, 'is_pseudo') and node.is_pseudo + self.is_docstring = self.is_multiline_string and not node.prev_sibling @property def formatted_whitespace_prefix(self): @@ -176,10 +185,10 @@ def AddWhitespacePrefix(self, newlines_before, spaces=0, indent_level=0): if self.is_comment: comment_lines = [s.lstrip() for s in self.value.splitlines()] - self.node.value = ('\n' + indent_before).join(comment_lines) + self.value = ('\n' + indent_before).join(comment_lines) # Update our own value since we are changing node value - self.value = self.node.value + self.value = self.value if not self.whitespace_prefix: self.whitespace_prefix = ('\n' * (self.newlines or newlines_before) + @@ -198,7 +207,7 @@ def RetainHorizontalSpacing(self, first_column, depth): if not previous: return - if previous.is_pseudo_paren: + if previous.is_pseudo: previous = previous.previous_token if not previous: return @@ -209,17 +218,17 @@ def RetainHorizontalSpacing(self, first_column, depth): prev_lineno += previous.value.count('\n') if (cur_lineno != prev_lineno or - (previous.is_pseudo_paren and previous.value != ')' and + (previous.is_pseudo and previous.value != ')' and cur_lineno != previous.previous_token.lineno)): self.spaces_required_before = ( self.column - first_column + depth * style.Get('INDENT_WIDTH')) return - cur_column = self.node.column + cur_column = self.column prev_column = previous.node.column prev_len = len(previous.value) - if previous.is_pseudo_paren and previous.value == ')': + if previous.is_pseudo and previous.value == ')': prev_column -= 1 prev_len = 0 @@ -239,11 +248,10 @@ def ClosesScope(self): def __repr__(self): msg = 'FormatToken(name={0}, value={1}, lineno={2}'.format( self.name, self.value, self.lineno) - msg += ', pseudo)' if self.is_pseudo_paren else ')' + msg += ', pseudo)' if self.is_pseudo else ')' return msg @property - @py3compat.lru_cache() def node_split_penalty(self): """Split penalty attached to the pytree node of this token.""" return pytree_utils.GetNodeAnnotation( @@ -262,72 +270,42 @@ def must_split(self): pytree_utils.Annotation.MUST_SPLIT) @property - def column(self): - """The original column number of the node in the source.""" - return self.node.column - - @property - def lineno(self): - """The original line number of the node in the source.""" - return self.node.lineno - - @property - @py3compat.lru_cache() - def subtypes(self): - """Extra type information for directing formatting.""" - value = pytree_utils.GetNodeAnnotation(self.node, - pytree_utils.Annotation.SUBTYPE) - return [Subtype.NONE] if value is None else value - - @property - @py3compat.lru_cache() def is_binary_op(self): """Token is a binary operator.""" return Subtype.BINARY_OPERATOR in self.subtypes @property - @py3compat.lru_cache() def is_a_expr_op(self): """Token is an a_expr operator.""" return Subtype.A_EXPR_OPERATOR in self.subtypes @property - @py3compat.lru_cache() def is_m_expr_op(self): """Token is an m_expr operator.""" return Subtype.M_EXPR_OPERATOR in self.subtypes @property - @py3compat.lru_cache() def is_arithmetic_op(self): """Token is an arithmetic operator.""" return self.is_a_expr_op or self.is_m_expr_op @property - @py3compat.lru_cache() def is_simple_expr(self): """Token is an operator in a simple expression.""" return Subtype.SIMPLE_EXPRESSION in self.subtypes @property - @py3compat.lru_cache() def is_subscript_colon(self): """Token is a subscript colon.""" return Subtype.SUBSCRIPT_COLON in self.subtypes - @property - @py3compat.lru_cache() - def name(self): - """A string representation of the node's name.""" - return pytree_utils.NodeName(self.node) - @property def is_comment(self): - return self.node.type == token.COMMENT + return self.type == token.COMMENT @property def is_continuation(self): - return self.node.type == CONTINUATION + return self.type == CONTINUATION @property @py3compat.lru_cache() @@ -335,20 +313,18 @@ def is_keyword(self): return keyword.iskeyword(self.value) @property - @py3compat.lru_cache() def is_name(self): - return self.node.type == token.NAME and not self.is_keyword + return self.type == token.NAME and not self.is_keyword @property def is_number(self): - return self.node.type == token.NUMBER + return self.type == token.NUMBER @property def is_string(self): - return self.node.type == token.STRING + return self.type == token.STRING @property - @py3compat.lru_cache() def is_multiline_string(self): """Test if this string is a multiline string. @@ -359,16 +335,6 @@ def is_multiline_string(self): """ return self.is_string and self.value.endswith(('"""', "'''")) - @property - @py3compat.lru_cache() - def is_docstring(self): - return self.is_multiline_string and not self.node.prev_sibling - - @property - @py3compat.lru_cache() - def is_pseudo_paren(self): - return hasattr(self.node, 'is_pseudo') and self.node.is_pseudo - @property def is_pylint_comment(self): return self.is_comment and re.match(r'#.*\bpylint:\s*(disable|enable)=', @@ -381,5 +347,5 @@ def is_pytype_comment(self): @property def is_copybara_comment(self): - return self.is_comment and re.match(r'#.*\bcopybara:(strip|insert|replace)', - self.value) + return self.is_comment and re.match( + r'#.*\bcopybara:\s*(strip|insert|replace)', self.value) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 6857b107d..91cad92a5 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -135,7 +135,7 @@ def _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines): if prev_tok.is_string: prev_lineno = prev_tok.lineno + prev_tok.value.count('\n') - elif prev_tok.is_pseudo_paren: + elif prev_tok.is_pseudo: if not prev_tok.previous_token.is_multiline_string: prev_lineno = prev_tok.previous_token.lineno else: @@ -400,7 +400,7 @@ def _FormatFinalLines(final_lines, verify): for line in final_lines: formatted_line = [] for tok in line.tokens: - if not tok.is_pseudo_paren: + if not tok.is_pseudo: formatted_line.append(tok.formatted_whitespace_prefix) formatted_line.append(tok.value) elif (not tok.next_token.whitespace_prefix.startswith('\n') and diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index ddd50e0dc..215d0cd49 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -74,7 +74,7 @@ def CalculateFormattingInformation(self): _SpaceRequiredBetween(prev_token, token, self.disable)): token.spaces_required_before = 1 - tok_len = len(token.value) if not token.is_pseudo_paren else 0 + tok_len = len(token.value) if not token.is_pseudo else 0 spaces_required_before = token.spaces_required_before if isinstance(spaces_required_before, list): @@ -271,11 +271,11 @@ def _SpaceRequiredBetween(left, right, is_line_disabled): """Return True if a space is required between the left and right token.""" lval = left.value rval = right.value - if (left.is_pseudo_paren and _IsIdNumberStringToken(right) and + if (left.is_pseudo and _IsIdNumberStringToken(right) and left.previous_token and _IsIdNumberStringToken(left.previous_token)): # Space between keyword... tokens and pseudo parens. return True - if left.is_pseudo_paren or right.is_pseudo_paren: + if left.is_pseudo or right.is_pseudo: # There should be a space after the ':' in a dictionary. if left.OpensScope(): return True @@ -484,7 +484,7 @@ def _SpaceRequiredBetween(left, right, is_line_disabled): def _MustBreakBefore(prev_token, cur_token): """Return True if a line break is required before the current token.""" if prev_token.is_comment or (prev_token.previous_token and - prev_token.is_pseudo_paren and + prev_token.is_pseudo and prev_token.previous_token.is_comment): # Must break if the previous token was a comment. return True diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 185d068c3..539aa1076 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -110,8 +110,7 @@ def testSplittingTopLevelAllArgs(self): style.SetGlobalStyle( style.CreateStyleFromConfig( '{split_all_top_level_comma_separated_values: true, ' - 'column_limit: 40}' - )) + 'column_limit: 40}')) # Works the same way as split_all_comma_separated_values unformatted_code = textwrap.dedent("""\ responseDict = {"timestamp": timestamp, "someValue": value, "whatever": 120} @@ -282,8 +281,7 @@ def testBlankLinesBetweenTopLevelImportsAndVariables(self): style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: yapf, ' - 'blank_lines_between_top_level_imports_and_variables: 2}' - )) + 'blank_lines_between_top_level_imports_and_variables: 2}')) uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) @@ -1997,10 +1995,9 @@ def method(self): try: style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: pep8, indent_width: 2, ' - 'continuation_indent_width: 4, ' - 'indent_dictionary_value: True}')) + style.CreateStyleFromConfig('{based_on_style: pep8, indent_width: 2, ' + 'continuation_indent_width: 4, ' + 'indent_dictionary_value: True}')) uwlines = yapf_test_helper.ParseAndUnwrap(code) reformatted_code = reformatter.Reformat(uwlines) From 3e4286cbdffeb61eacbc3d4f7a0026e5821dce90 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 8 Nov 2021 02:24:12 -0800 Subject: [PATCH 511/719] Combine the "must_break_before" and "must_split" properties. --- yapf/yapflib/format_token.py | 9 ++------- yapf/yapflib/reformatter.py | 2 +- yapf/yapflib/unwrapped_line.py | 5 +---- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 0f3cb606e..6645585e6 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -130,7 +130,8 @@ def __init__(self, node): self.container_elements = [] self.whitespace_prefix = '' self.can_break_before = False - self.must_break_before = False + self.must_break_before = pytree_utils.GetNodeAnnotation( + node, pytree_utils.Annotation.MUST_SPLIT, default=False) self.total_length = 0 self.split_penalty = 0 @@ -263,12 +264,6 @@ def newlines(self): return pytree_utils.GetNodeAnnotation(self.node, pytree_utils.Annotation.NEWLINES) - @property - def must_split(self): - """Return true if the token requires a split before it.""" - return pytree_utils.GetNodeAnnotation(self.node, - pytree_utils.Annotation.MUST_SPLIT) - @property def is_binary_op(self): """Token is a binary operator.""" diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 91cad92a5..4626d7538 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -84,7 +84,7 @@ def Reformat(uwlines, verify=False, lines=None): _RetainRequiredVerticalSpacing(uwline, prev_uwline, lines) _EmitLineUnformatted(state) - elif _CanPlaceOnSingleLine(uwline) and not any(tok.must_split + elif _CanPlaceOnSingleLine(uwline) and not any(tok.must_break_before for tok in uwline.tokens): # The unwrapped line fits on one line. while state.next_token: diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 215d0cd49..6cbd20eb1 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -118,8 +118,6 @@ def Split(self): uwlines.append(uwline) for uwline in uwlines: - pytree_utils.SetNodeAnnotation(uwline.first.node, - pytree_utils.Annotation.MUST_SPLIT, True) uwline.first.previous_token = None uwline.last.next_token = None @@ -494,8 +492,7 @@ def _MustBreakBefore(prev_token, cur_token): # reasonable assumption, because otherwise they should have written them # all on the same line, or with a '+'. return True - return pytree_utils.GetNodeAnnotation( - cur_token.node, pytree_utils.Annotation.MUST_SPLIT, default=False) + return cur_token.must_break_before def _CanBreakBefore(prev_token, cur_token): From 59a62db3c118ab9c55135a31ea73a69fec881f8d Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 8 Nov 2021 02:32:15 -0800 Subject: [PATCH 512/719] Move the "newlines" attribute from pytree node to format token. --- yapf/yapflib/format_token.py | 17 +++++++---------- yapf/yapflib/reformatter.py | 13 ++++--------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 6645585e6..42e524e27 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -107,12 +107,13 @@ class FormatToken(object): formatter won't place n spaces before all comments. Only those that are moved to the end of a line of code. The formatter may use different spacing when appropriate. - can_break_before: True if we're allowed to break before this token. - must_break_before: True if we're required to break before this token. total_length: The total length of the unwrapped line up to and including whitespace and this token. However, this doesn't include the initial indentation amount. split_penalty: The penalty for splitting the line before this token. + can_break_before: True if we're allowed to break before this token. + must_break_before: True if we're required to break before this token. + newlines: The number of newlines needed before this token. """ def __init__(self, node): @@ -129,11 +130,13 @@ def __init__(self, node): self.container_opening = None self.container_elements = [] self.whitespace_prefix = '' + self.total_length = 0 + self.split_penalty = 0 self.can_break_before = False self.must_break_before = pytree_utils.GetNodeAnnotation( node, pytree_utils.Annotation.MUST_SPLIT, default=False) - self.total_length = 0 - self.split_penalty = 0 + self.newlines = pytree_utils.GetNodeAnnotation( + node, pytree_utils.Annotation.NEWLINES) self.type = node.type self.column = node.column @@ -258,12 +261,6 @@ def node_split_penalty(self): return pytree_utils.GetNodeAnnotation( self.node, pytree_utils.Annotation.SPLIT_PENALTY, default=0) - @property - def newlines(self): - """The number of newlines needed before this token.""" - return pytree_utils.GetNodeAnnotation(self.node, - pytree_utils.Annotation.NEWLINES) - @property def is_binary_op(self): """Token is a binary operator.""" diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 4626d7538..a61d46354 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -629,8 +629,7 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, # The first line in the file. Don't add blank lines. # FIXME(morbo): Is this correct? if first_token.newlines is not None: - pytree_utils.SetNodeAnnotation(first_token.node, - pytree_utils.Annotation.NEWLINES, None) + first_token.newlines = None return 0 if first_token.is_docstring: @@ -661,8 +660,7 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, if (first_nested and not style.Get('BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF') and _IsClassOrDef(first_token)): - pytree_utils.SetNodeAnnotation(first_token.node, - pytree_utils.Annotation.NEWLINES, None) + first_token.newlines = None return NO_BLANK_LINES if _NoBlankLinesBeforeCurrentToken(prev_last_token.value, first_token, prev_last_token): @@ -694,15 +692,12 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, prev_last_token.AdjustNewlinesBefore( 1 + style.Get('BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION')) if first_token.newlines is not None: - pytree_utils.SetNodeAnnotation(first_token.node, - pytree_utils.Annotation.NEWLINES, - None) + first_token.newlines = None return NO_BLANK_LINES elif _IsClassOrDef(prev_uwline.first): if first_nested and not style.Get( 'BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'): - pytree_utils.SetNodeAnnotation(first_token.node, - pytree_utils.Annotation.NEWLINES, None) + first_token.newlines = None return NO_BLANK_LINES # Calculate how many newlines were between the original lines. We want to From 34963b35ccee5d6f7da826f62ad778e2452aa705 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 23 Dec 2021 15:51:06 -0800 Subject: [PATCH 513/719] Unify the YAPF exceptions There are many potential exceptions that can be generated. Unify them into a single YapfError with a standardized error message format. --- yapf/__init__.py | 13 ++++++------- yapf/yapflib/errors.py | 18 +++++++++++++++++- yapf/yapflib/yapf_api.py | 20 ++++++++++++++------ yapftests/main_test.py | 4 ++-- 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 4fe2ddfaa..21eaa012b 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -109,8 +109,8 @@ def main(argv): style_config=style_config, lines=lines, verify=args.verify) - except tokenize.TokenError as e: - raise errors.YapfError('%s:%s' % (e.args[1][0], e.args[0])) + except Exception as e: + raise errors.YapfError(errors.FormatErrorMsg(e)) file_resources.WriteReformattedCode('', reformatted_source) return 0 @@ -123,7 +123,7 @@ def main(argv): (args.exclude or []) + exclude_patterns_from_ignore_file) if not files: - raise errors.YapfError('Input filenames did not match any python files') + raise errors.YapfError('input filenames did not match any python files') changed = FormatFiles( files, @@ -234,11 +234,10 @@ def _FormatFile(filename, print_diff=print_diff, verify=verify, logger=logging.warning) - except tokenize.TokenError as e: - raise errors.YapfError('%s:%s:%s' % (filename, e.args[1][0], e.args[0])) - except SyntaxError as e: - e.filename = filename + except errors.YapfError: raise + except Exception as e: + raise errors.YapfError(errors.FormatErrorMsg(e)) if not in_place and not quiet and reformatted_code: file_resources.WriteReformattedCode(filename, reformatted_code, encoding, diff --git a/yapf/yapflib/errors.py b/yapf/yapflib/errors.py index 3946275c8..5726ff148 100644 --- a/yapf/yapflib/errors.py +++ b/yapf/yapflib/errors.py @@ -11,7 +11,23 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -"""YAPF error object.""" +"""YAPF error objects.""" + + +def FormatErrorMsg(e): + """Convert an exception into a standard format. + + The standard error message format is: + + ::: + + Arguments: + e: An exception. + + Returns: + A properly formatted error message string. + """ + return '{}:{}:{}: {}'.format(e.args[1][0], e.args[1][1], e.args[1][2], e.msg) class YapfError(Exception): diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 0ef2a1eb9..ac0466ece 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -37,10 +37,12 @@ import sys from lib2to3.pgen2 import parse +from lib2to3.pgen2 import tokenize from yapf.yapflib import blank_line_calculator from yapf.yapflib import comment_splicer from yapf.yapflib import continuation_splicer +from yapf.yapflib import errors from yapf.yapflib import file_resources from yapf.yapflib import identify_container from yapf.yapflib import py3compat @@ -179,8 +181,12 @@ def FormatCode(unformatted_source, """ try: tree = pytree_utils.ParseCodeToTree(unformatted_source) - except parse.ParseError as e: - e.msg = filename + ': ' + e.msg + except tokenize.TokenError as e: + e.msg = e.args[0] + e.args = (e.msg, (filename, e.args[1][0], e.args[1][1])) + raise + except Exception as e: + e.args = (e.args[0], (filename, e.args[1][1], e.args[1][2], e.args[1][3])) raise reformatted_source = FormatTree( @@ -236,15 +242,17 @@ def ReadFile(filename, logger=None): line_ending = file_resources.LineEnding(lines) source = '\n'.join(line.rstrip('\r\n') for line in lines) + '\n' return source, line_ending, encoding - except IOError as err: # pragma: no cover + except IOError as e: # pragma: no cover if logger: - logger(err) + logger(e) + e.args = (e.args[0], (filename, e.args[1][1], e.args[1][2], e.args[1][3])) raise - except UnicodeDecodeError as err: # pragma: no cover + except UnicodeDecodeError as e: # pragma: no cover if logger: logger('Could not parse %s! Consider excluding this file with --exclude.', filename) - logger(err) + logger(e) + e.args = (e.args[0], (filename, e.args[1][1], e.args[1][2], e.args[1][3])) raise diff --git a/yapftests/main_test.py b/yapftests/main_test.py index a9069b082..dd89753b4 100644 --- a/yapftests/main_test.py +++ b/yapftests/main_test.py @@ -89,7 +89,7 @@ class RunMainTest(yapf_test_helper.YAPFTest): def testShouldHandleYapfError(self): """run_main should handle YapfError and sys.exit(1).""" - expected_message = 'yapf: Input filenames did not match any python files\n' + expected_message = 'yapf: input filenames did not match any python files\n' sys.argv = ['yapf', 'foo.c'] with captured_output() as (out, err): with self.assertRaises(SystemExit): @@ -126,7 +126,7 @@ def testEchoBadInput(self): bad_syntax = ' a = 1\n' with patched_input(bad_syntax): with captured_output() as (_, _): - with self.assertRaisesRegex(SyntaxError, 'unexpected indent'): + with self.assertRaisesRegex(yapf.errors.YapfError, 'unexpected indent'): yapf.main([]) def testHelp(self): From 82f5f346e0dde3a85e3b50c09ae05f0779f23dab Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 23 Dec 2021 15:56:18 -0800 Subject: [PATCH 514/719] Use Python's argument parser's "version" action --- yapf/__init__.py | 11 ++++------- yapftests/main_test.py | 7 ------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 21eaa012b..ecb462bd2 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -59,10 +59,6 @@ def main(argv): """ parser = _BuildParser() args = parser.parse_args(argv[1:]) - if args.version: - print('yapf {}'.format(__version__)) - return 0 - style_config = args.style if args.style_help: @@ -276,12 +272,13 @@ def _BuildParser(): Returns: An ArgumentParser instance for the CLI. """ - parser = argparse.ArgumentParser(description='Formatter for Python code.') + parser = argparse.ArgumentParser( + prog='yapf', description='Formatter for Python code.') parser.add_argument( '-v', '--version', - action='store_true', - help='show version number and exit') + action='version', + version='%(prog)s {}'.format(__version__)) diff_inplace_quiet_group = parser.add_mutually_exclusive_group() diff_inplace_quiet_group.add_argument( diff --git a/yapftests/main_test.py b/yapftests/main_test.py index dd89753b4..c83b8b66a 100644 --- a/yapftests/main_test.py +++ b/yapftests/main_test.py @@ -137,10 +137,3 @@ def testHelp(self): self.assertIn('indent_width=4', help_message) self.assertIn('The number of spaces required before a trailing comment.', help_message) - - def testVersion(self): - with captured_output() as (out, _): - ret = yapf.main(['-', '--version']) - self.assertEqual(ret, 0) - version = 'yapf {}\n'.format(yapf.__version__) - self.assertEqual(version, out.getvalue()) From 7d9f50e17ee06daf3f44f153495eb825ceef2627 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 23 Dec 2021 16:18:53 -0800 Subject: [PATCH 515/719] Compare the node's type instead of its name --- yapf/yapflib/blank_line_calculator.py | 6 +++-- yapf/yapflib/identify_container.py | 6 +++-- yapf/yapflib/pytree_unwrapper.py | 12 ++++------ yapf/yapflib/split_penalty.py | 11 +++++---- yapf/yapflib/subtype_assigner.py | 34 ++++++++++++++------------- 5 files changed, 37 insertions(+), 32 deletions(-) diff --git a/yapf/yapflib/blank_line_calculator.py b/yapf/yapflib/blank_line_calculator.py index 374134853..3d78646ea 100644 --- a/yapf/yapflib/blank_line_calculator.py +++ b/yapf/yapflib/blank_line_calculator.py @@ -22,6 +22,8 @@ newlines: The number of newlines required before the node. """ +from lib2to3.pgen2 import token as grammar_token + from yapf.yapflib import py3compat from yapf.yapflib import pytree_utils from yapf.yapflib import pytree_visitor @@ -64,7 +66,7 @@ def __init__(self): def Visit_simple_stmt(self, node): # pylint: disable=invalid-name self.DefaultNodeVisit(node) - if pytree_utils.NodeName(node.children[0]) == 'COMMENT': + if node.children[0].type == grammar_token.COMMENT: self.last_comment_lineno = node.children[0].lineno def Visit_decorator(self, node): # pylint: disable=invalid-name @@ -174,4 +176,4 @@ def _StartsInZerothColumn(node): def _AsyncFunction(node): return (py3compat.PY3 and node.prev_sibling and - pytree_utils.NodeName(node.prev_sibling) == 'ASYNC') + node.prev_sibling.type == grammar_token.ASYNC) diff --git a/yapf/yapflib/identify_container.py b/yapf/yapflib/identify_container.py index 5c5fc5bf0..888dbbb54 100644 --- a/yapf/yapflib/identify_container.py +++ b/yapf/yapflib/identify_container.py @@ -19,6 +19,8 @@ IdentifyContainers(): the main function exported by this module. """ +from lib2to3.pgen2 import token as grammar_token + from yapf.yapflib import pytree_utils from yapf.yapflib import pytree_visitor @@ -42,7 +44,7 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name if len(node.children) != 3: return - if pytree_utils.NodeName(node.children[0]) != 'LPAR': + if node.children[0].type != grammar_token.LPAR: return if pytree_utils.NodeName(node.children[1]) == 'arglist': @@ -59,7 +61,7 @@ def Visit_atom(self, node): # pylint: disable=invalid-name if len(node.children) != 3: return - if pytree_utils.NodeName(node.children[0]) != 'LPAR': + if node.children[0].type != grammar_token.LPAR: return for child in node.children[1].children: diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index c7e32a3e5..88272efd3 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -205,7 +205,7 @@ def Visit_async_funcdef(self, node): # pylint: disable=invalid-name for child in node.children: index += 1 self.Visit(child) - if pytree_utils.NodeName(child) == 'ASYNC': + if child.type == grammar_token.ASYNC: break for child in node.children[index].children: self.Visit(child) @@ -221,18 +221,17 @@ def Visit_async_stmt(self, node): # pylint: disable=invalid-name for child in node.children: index += 1 self.Visit(child) - if pytree_utils.NodeName(child) == 'ASYNC': + if child.type == grammar_token.ASYNC: break for child in node.children[index].children: - if pytree_utils.NodeName(child) == 'NAME' and child.value == 'else': + if child.type == grammar_token.NAME and child.value == 'else': self._StartNewLine() self.Visit(child) def Visit_decorator(self, node): # pylint: disable=invalid-name for child in node.children: self.Visit(child) - if (pytree_utils.NodeName(child) == 'COMMENT' and - child == node.children[0]): + if child.type == grammar_token.COMMENT and child == node.children[0]: self._StartNewLine() def Visit_decorators(self, node): # pylint: disable=invalid-name @@ -386,8 +385,7 @@ def _DetermineMustSplitAnnotation(node): if not _ContainsComments(node): token = next(node.parent.leaves()) if token.value == '(': - if sum(1 for ch in node.children - if pytree_utils.NodeName(ch) == 'COMMA') < 2: + if sum(1 for ch in node.children if ch.type == grammar_token.COMMA) < 2: return if (not isinstance(node.children[-1], pytree.Leaf) or node.children[-1].value != ','): diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index d4c3dc475..40aedb4ab 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -16,6 +16,7 @@ import re from lib2to3 import pytree +from lib2to3.pgen2 import token as grammar_token from yapf.yapflib import format_token from yapf.yapflib import py3compat @@ -123,7 +124,7 @@ def Visit_lambdef(self, node): # pylint: disable=invalid-name allow_multiline_lambdas = style.Get('ALLOW_MULTILINE_LAMBDAS') if not allow_multiline_lambdas: for child in node.children: - if pytree_utils.NodeName(child) == 'COMMENT': + if child.type == grammar_token.COMMENT: if re.search(r'pylint:.*disable=.*\bg-long-lambda', child.value): allow_multiline_lambdas = True break @@ -145,7 +146,7 @@ def Visit_parameters(self, node): # pylint: disable=invalid-name def Visit_arglist(self, node): # pylint: disable=invalid-name # arglist ::= argument (',' argument)* [','] - if pytree_utils.NodeName(node.children[0]) == 'STAR': + if node.children[0].type == grammar_token.STAR: # Python 3 treats a star expression as a specific expression type. # Process it in that method. self.Visit_star_expr(node) @@ -200,7 +201,7 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name # (test (comp_for | (',' test)* [','])) ) for child in node.children: self.Visit(child) - if pytree_utils.NodeName(child) == 'COLON': + if child.type == grammar_token.COLON: # This is a key to a dictionary. We don't want to split the key if at # all possible. _SetStronglyConnected(child) @@ -229,7 +230,7 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name _SetSplitPenalty( pytree_utils.FirstLeafNode(node.children[1]), ONE_ELEMENT_ARGUMENT) - elif (pytree_utils.NodeName(node.children[0]) == 'LSQB' and + elif (node.children[0].type == grammar_token.LSQB and len(node.children[1].children) > 2 and (name.endswith('_test') or name.endswith('_expr'))): _SetStronglyConnected(node.children[1].children[0]) @@ -347,7 +348,7 @@ def Visit_subscriptlist(self, node): # pylint: disable=invalid-name _SetSplitPenalty(pytree_utils.FirstLeafNode(node), 0) prev_child = None for child in node.children: - if prev_child and pytree_utils.NodeName(prev_child) == 'COMMA': + if prev_child and prev_child.type == grammar_token.COMMA: _SetSplitPenalty(pytree_utils.FirstLeafNode(child), 0) prev_child = child diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 1a54522e9..cb7880960 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -26,7 +26,7 @@ """ from lib2to3 import pytree -from lib2to3.pgen2 import token +from lib2to3.pgen2 import token as grammar_token from lib2to3.pygram import python_symbols as syms from yapf.yapflib import format_token @@ -75,14 +75,14 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name comp_for = True _AppendFirstLeafTokenSubtype(child, format_token.Subtype.DICT_SET_GENERATOR) - elif pytree_utils.NodeName(child) in ('COLON', 'DOUBLESTAR'): + elif child.type in (grammar_token.COLON, grammar_token.DOUBLESTAR): dict_maker = True if not comp_for and dict_maker: last_was_colon = False unpacking = False for child in node.children: - if pytree_utils.NodeName(child) == 'DOUBLESTAR': + if child.type == grammar_token.DOUBLESTAR: _AppendFirstLeafTokenSubtype(child, format_token.Subtype.KWARGS_STAR_STAR) if last_was_colon: @@ -100,8 +100,8 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name _AppendFirstLeafTokenSubtype(child, format_token.Subtype.DICTIONARY_KEY) _AppendSubtypeRec(child, format_token.Subtype.DICTIONARY_KEY_PART) - last_was_colon = pytree_utils.NodeName(child) == 'COLON' - if pytree_utils.NodeName(child) == 'DOUBLESTAR': + last_was_colon = child.type == grammar_token.COLON + if child.type == grammar_token.DOUBLESTAR: unpacking = True elif last_was_colon: unpacking = False @@ -274,7 +274,7 @@ def Visit_funcdef(self, node): # pylint: disable=invalid-name # funcdef ::= # 'def' NAME parameters ['->' test] ':' suite for child in node.children: - if pytree_utils.NodeName(child) == 'NAME' and child.value != 'def': + if child.type == grammar_token.NAME and child.value != 'def': _AppendTokenSubtype(child, format_token.Subtype.FUNC_DEF) break for child in node.children: @@ -311,10 +311,10 @@ def Visit_typedargslist(self, node): # pylint: disable=invalid-name for i in range(1, len(node.children)): prev_child = node.children[i - 1] child = node.children[i] - if pytree_utils.NodeName(prev_child) == 'COMMA': + if prev_child.type == grammar_token.COMMA: _AppendFirstLeafTokenSubtype(child, format_token.Subtype.PARAMETER_START) - elif pytree_utils.NodeName(child) == 'COMMA': + elif child.type == grammar_token.COMMA: _AppendLastLeafTokenSubtype(prev_child, format_token.Subtype.PARAMETER_STOP) @@ -322,9 +322,9 @@ def Visit_typedargslist(self, node): # pylint: disable=invalid-name tname = True _SetArgListSubtype(child, format_token.Subtype.TYPED_NAME, format_token.Subtype.TYPED_NAME_ARG_LIST) - elif pytree_utils.NodeName(child) == 'COMMA': + elif child.type == grammar_token.COMMA: tname = False - elif pytree_utils.NodeName(child) == 'EQUAL' and tname: + elif child.type == grammar_token.EQUAL and tname: _AppendTokenSubtype(child, subtype=format_token.Subtype.TYPED_NAME) tname = False @@ -436,14 +436,14 @@ def _InsertPseudoParentheses(node): """Insert pseudo parentheses so that dicts can be formatted correctly.""" comment_node = None if isinstance(node, pytree.Node): - if node.children[-1].type == token.COMMENT: + if node.children[-1].type == grammar_token.COMMENT: comment_node = node.children[-1].clone() node.children[-1].remove() first = pytree_utils.FirstLeafNode(node) last = pytree_utils.LastLeafNode(node) - if first == last and first.type == token.COMMENT: + if first == last and first.type == grammar_token.COMMENT: # A comment was inserted before the value, which is a pytree.Leaf. # Encompass the dictionary's value into an ATOM node. last = first.next_sibling @@ -462,17 +462,19 @@ def _InsertPseudoParentheses(node): last = pytree_utils.LastLeafNode(node) lparen = pytree.Leaf( - token.LPAR, u'(', context=('', (first.get_lineno(), first.column - 1))) + grammar_token.LPAR, + u'(', + context=('', (first.get_lineno(), first.column - 1))) last_lineno = last.get_lineno() - if last.type == token.STRING and '\n' in last.value: + if last.type == grammar_token.STRING and '\n' in last.value: last_lineno += last.value.count('\n') - if last.type == token.STRING and '\n' in last.value: + if last.type == grammar_token.STRING and '\n' in last.value: last_column = len(last.value.split('\n')[-1]) + 1 else: last_column = last.column + len(last.value) + 1 rparen = pytree.Leaf( - token.RPAR, u')', context=('', (last_lineno, last_column))) + grammar_token.RPAR, u')', context=('', (last_lineno, last_column))) lparen.is_pseudo = True rparen.is_pseudo = True From c1c786d3ea837cd30a1439f7dd302b7366817c9f Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 24 Dec 2021 01:20:50 -0600 Subject: [PATCH 516/719] Remove unused import --- yapf/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index ecb462bd2..d9b4dd602 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -32,8 +32,6 @@ import os import sys -from lib2to3.pgen2 import tokenize - from yapf.yapflib import errors from yapf.yapflib import file_resources from yapf.yapflib import py3compat From cfeca1cfca410bfde0678f014a403f6e64224676 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 24 Dec 2021 01:24:05 -0600 Subject: [PATCH 517/719] Fix up the "name" and "is_docstring" bits of a format_token --- yapf/yapflib/format_token.py | 12 ++++++++---- yapftests/format_token_test.py | 10 ++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 42e524e27..9d616627a 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -141,6 +141,7 @@ def __init__(self, node): self.type = node.type self.column = node.column self.lineno = node.lineno + self.name = pytree_utils.NodeName(node) self.spaces_required_before = 0 if self.is_comment: @@ -153,9 +154,7 @@ def __init__(self, node): subtypes = pytree_utils.GetNodeAnnotation(node, pytree_utils.Annotation.SUBTYPE) self.subtypes = [Subtype.NONE] if subtypes is None else subtypes - self.name = pytree_utils.NodeName(node) self.is_pseudo = hasattr(node, 'is_pseudo') and node.is_pseudo - self.is_docstring = self.is_multiline_string and not node.prev_sibling @property def formatted_whitespace_prefix(self): @@ -250,8 +249,9 @@ def ClosesScope(self): return self.value in pytree_utils.CLOSING_BRACKETS def __repr__(self): - msg = 'FormatToken(name={0}, value={1}, lineno={2}'.format( - self.name, self.value, self.lineno) + msg = 'FormatToken(name={0}, value={1}, column={2}, lineno={3}'.format( + 'DOCSTRING' if self.is_docstring else self.name, self.value, + self.column, self.lineno) msg += ', pseudo)' if self.is_pseudo else ')' return msg @@ -327,6 +327,10 @@ def is_multiline_string(self): """ return self.is_string and self.value.endswith(('"""', "'''")) + @property + def is_docstring(self): + return self.is_string and self.previous_token is None + @property def is_pylint_comment(self): return self.is_comment and re.match(r'#.*\bpylint:\s*(disable|enable)=', diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index b4c715107..8c7151ac2 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -67,13 +67,15 @@ class FormatTokenTest(unittest.TestCase): def testSimple(self): tok = format_token.FormatToken(pytree.Leaf(token.STRING, "'hello world'")) - self.assertEqual("FormatToken(name=STRING, value='hello world', lineno=0)", - str(tok)) + self.assertEqual( + "FormatToken(name=DOCSTRING, value='hello world', column=0, lineno=0)", + str(tok)) self.assertTrue(tok.is_string) tok = format_token.FormatToken(pytree.Leaf(token.COMMENT, '# A comment')) - self.assertEqual('FormatToken(name=COMMENT, value=# A comment, lineno=0)', - str(tok)) + self.assertEqual( + 'FormatToken(name=COMMENT, value=# A comment, column=0, lineno=0)', + str(tok)) self.assertTrue(tok.is_comment) def testIsMultilineString(self): From d658e35dd0bd80bf333e77037809bafb27998c9d Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 24 Dec 2021 23:30:35 -0600 Subject: [PATCH 518/719] Remove useless a_expr and m_expr subtypes --- yapf/yapflib/format_token.py | 29 ++++++++++++++++------------- yapf/yapflib/subtype_assigner.py | 2 -- yapftests/subtype_assigner_test.py | 27 +++++---------------------- 3 files changed, 21 insertions(+), 37 deletions(-) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 9d616627a..65615d74b 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -36,8 +36,6 @@ class Subtype(object): NONE = 0 UNARY_OPERATOR = 1 BINARY_OPERATOR = 2 - A_EXPR_OPERATOR = 3 - M_EXPR_OPERATOR = 4 SUBSCRIPT_COLON = 5 SUBSCRIPT_BRACKET = 6 DEFAULT_OR_NAMED_ASSIGN = 7 @@ -267,19 +265,24 @@ def is_binary_op(self): return Subtype.BINARY_OPERATOR in self.subtypes @property - def is_a_expr_op(self): - """Token is an a_expr operator.""" - return Subtype.A_EXPR_OPERATOR in self.subtypes - - @property - def is_m_expr_op(self): - """Token is an m_expr operator.""" - return Subtype.M_EXPR_OPERATOR in self.subtypes - - @property + @py3compat.lru_cache() def is_arithmetic_op(self): """Token is an arithmetic operator.""" - return self.is_a_expr_op or self.is_m_expr_op + return self.value in frozenset({ + '+', # Add + '-', # Subtract + '*', # Multiply + '@', # Matrix Multiply + '/', # Divide + '//', # Floor Divide + '%', # Modulo + '<<', # Left Shift + '>>', # Right Shift + '|', # Bitwise Or + '&', # Bitwise Add + '^', # Bitwise Xor + '**', # Power + }) @property def is_simple_expr(self): diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index cb7880960..7bcdf5fed 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -189,7 +189,6 @@ def Visit_arith_expr(self, node): # pylint: disable=invalid-name self.Visit(child) if _IsAExprOperator(child): _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) - _AppendTokenSubtype(child, format_token.Subtype.A_EXPR_OPERATOR) if _IsSimpleExpression(node): for child in node.children: @@ -202,7 +201,6 @@ def Visit_term(self, node): # pylint: disable=invalid-name self.Visit(child) if _IsMExprOperator(child): _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) - _AppendTokenSubtype(child, format_token.Subtype.M_EXPR_OPERATOR) if _IsSimpleExpression(node): for child in node.children: diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index b42b8cfab..d695be13c 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -216,48 +216,31 @@ def testArithmeticOperators(self): ('(', [format_token.Subtype.NONE]), ('(', [format_token.Subtype.NONE]), ('a', [format_token.Subtype.NONE]), - ('+', { - format_token.Subtype.BINARY_OPERATOR, - format_token.Subtype.A_EXPR_OPERATOR, - }), + ('+', {format_token.Subtype.BINARY_OPERATOR}), ('(', [format_token.Subtype.NONE]), ('b', [format_token.Subtype.NONE]), ('-', { format_token.Subtype.BINARY_OPERATOR, - format_token.Subtype.A_EXPR_OPERATOR, format_token.Subtype.SIMPLE_EXPRESSION, }), ('3', [format_token.Subtype.NONE]), (')', [format_token.Subtype.NONE]), - ('*', { - format_token.Subtype.BINARY_OPERATOR, - format_token.Subtype.M_EXPR_OPERATOR, - }), + ('*', {format_token.Subtype.BINARY_OPERATOR}), ('(', [format_token.Subtype.NONE]), ('1', [format_token.Subtype.NONE]), ('%', { format_token.Subtype.BINARY_OPERATOR, - format_token.Subtype.M_EXPR_OPERATOR, format_token.Subtype.SIMPLE_EXPRESSION, }), ('c', [format_token.Subtype.NONE]), (')', [format_token.Subtype.NONE]), - ('@', { - format_token.Subtype.BINARY_OPERATOR, - format_token.Subtype.M_EXPR_OPERATOR, - }), + ('@', {format_token.Subtype.BINARY_OPERATOR}), ('d', [format_token.Subtype.NONE]), (')', [format_token.Subtype.NONE]), - ('/', { - format_token.Subtype.BINARY_OPERATOR, - format_token.Subtype.M_EXPR_OPERATOR, - }), + ('/', {format_token.Subtype.BINARY_OPERATOR}), ('3', [format_token.Subtype.NONE]), (')', [format_token.Subtype.NONE]), - ('//', { - format_token.Subtype.BINARY_OPERATOR, - format_token.Subtype.M_EXPR_OPERATOR, - }), + ('//', {format_token.Subtype.BINARY_OPERATOR}), ('1', [format_token.Subtype.NONE]), ], ]) From 4f9bd31628405ee67e1e3e25de4de62628d17943 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 24 Dec 2021 23:53:01 -0600 Subject: [PATCH 519/719] Move subtypes into their own module. This unlinks the subtypes from the format_token module, where it doesn't really belong. --- yapf/yapflib/format_decision_state.py | 65 +++---- yapf/yapflib/format_token.py | 45 +---- yapf/yapflib/object_state.py | 3 +- yapf/yapflib/pytree_unwrapper.py | 7 +- yapf/yapflib/split_penalty.py | 9 +- yapf/yapflib/subtype_assigner.py | 135 ++++++-------- yapf/yapflib/subtypes.py | 40 ++++ yapf/yapflib/unwrapped_line.py | 61 +++--- yapftests/subtype_assigner_test.py | 259 +++++++++++++------------- 9 files changed, 311 insertions(+), 313 deletions(-) create mode 100644 yapf/yapflib/subtypes.py diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 6c3c0fd16..be5770c5d 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -30,6 +30,7 @@ from yapf.yapflib import object_state from yapf.yapflib import split_penalty from yapf.yapflib import style +from yapf.yapflib import subtypes from yapf.yapflib import unwrapped_line @@ -135,16 +136,14 @@ def CanSplit(self, must_split): if current.is_pseudo: return False - if (not must_split and - format_token.Subtype.DICTIONARY_KEY_PART in current.subtypes and - format_token.Subtype.DICTIONARY_KEY not in current.subtypes and + if (not must_split and subtypes.DICTIONARY_KEY_PART in current.subtypes and + subtypes.DICTIONARY_KEY not in current.subtypes and not style.Get('ALLOW_MULTILINE_DICTIONARY_KEYS')): # In some situations, a dictionary may be multiline, but pylint doesn't # like it. So don't allow it unless forced to. return False - if (not must_split and - format_token.Subtype.DICTIONARY_VALUE in current.subtypes and + if (not must_split and subtypes.DICTIONARY_VALUE in current.subtypes and not style.Get('ALLOW_SPLIT_BEFORE_DICT_VALUE')): return False @@ -157,7 +156,7 @@ def CanSplit(self, must_split): if not prev or prev.name not in {'NAME', 'DOT'}: break token = token.previous_token - if token and format_token.Subtype.DICTIONARY_VALUE in token.subtypes: + if token and subtypes.DICTIONARY_VALUE in token.subtypes: if not style.Get('ALLOW_SPLIT_BEFORE_DICT_VALUE'): return False @@ -207,7 +206,7 @@ def MustSplit(self): (current.value in '}]' and style.Get('SPLIT_BEFORE_CLOSING_BRACKET') or current.value in '}])' and style.Get('INDENT_CLOSING_BRACKETS'))): # Split before the closing bracket if we can. - if format_token.Subtype.SUBSCRIPT_BRACKET not in current.subtypes: + if subtypes.SUBSCRIPT_BRACKET not in current.subtypes: return current.node_split_penalty != split_penalty.UNBREAKABLE if (current.value == ')' and previous.value == ',' and @@ -227,7 +226,7 @@ def MustSplit(self): style.Get('INDENT_CLOSING_BRACKETS') or style.Get('SPLIT_BEFORE_FIRST_ARGUMENT')): bracket = current if current.ClosesScope() else previous - if format_token.Subtype.SUBSCRIPT_BRACKET not in bracket.subtypes: + if subtypes.SUBSCRIPT_BRACKET not in bracket.subtypes: if bracket.OpensScope(): if style.Get('COALESCE_BRACKETS'): if current.OpensScope(): @@ -312,20 +311,19 @@ def SurroundedByParens(token): return True if (current.OpensScope() and previous.value == ',' and - format_token.Subtype.DICTIONARY_KEY not in current.next_token.subtypes): + subtypes.DICTIONARY_KEY not in current.next_token.subtypes): # If we have a list of tuples, then we can get a similar look as above. If # the full list cannot fit on the line, then we want a split. open_bracket = unwrapped_line.IsSurroundedByBrackets(current) if (open_bracket and open_bracket.value in '[{' and - format_token.Subtype.SUBSCRIPT_BRACKET not in open_bracket.subtypes): + subtypes.SUBSCRIPT_BRACKET not in open_bracket.subtypes): if not self._FitsOnLine(current, current.matching_bracket): return True ########################################################################### # Dict/Set Splitting if (style.Get('EACH_DICT_ENTRY_ON_SEPARATE_LINE') and - format_token.Subtype.DICTIONARY_KEY in current.subtypes and - not current.is_comment): + subtypes.DICTIONARY_KEY in current.subtypes and not current.is_comment): # Place each dictionary entry onto its own line. if previous.value == '{' and previous.previous_token: opening = _GetOpeningBracket(previous.previous_token) @@ -345,11 +343,11 @@ def SurroundedByParens(token): return True if (style.Get('SPLIT_BEFORE_DICT_SET_GENERATOR') and - format_token.Subtype.DICT_SET_GENERATOR in current.subtypes): + subtypes.DICT_SET_GENERATOR in current.subtypes): # Split before a dict/set generator. return True - if (format_token.Subtype.DICTIONARY_VALUE in current.subtypes or + if (subtypes.DICTIONARY_VALUE in current.subtypes or (previous.is_pseudo and previous.value == '(' and not current.is_comment)): # Split before the dictionary value if we can't fit every dictionary @@ -370,8 +368,7 @@ def SurroundedByParens(token): ########################################################################### # Argument List Splitting if (style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and not current.is_comment and - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST - in current.subtypes): + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in current.subtypes): if (previous.value not in {'=', ':', '*', '**'} and current.value not in ':=,)' and not _IsFunctionDefinition(previous)): # If we're going to split the lines because of named arguments, then we @@ -506,7 +503,7 @@ def SurroundedByParens(token): if (previous.OpensScope() and not current.OpensScope() and not current.is_comment and - format_token.Subtype.SUBSCRIPT_BRACKET not in previous.subtypes): + subtypes.SUBSCRIPT_BRACKET not in previous.subtypes): if pprevious and not pprevious.is_keyword and not pprevious.is_name: # We want to split if there's a comment in the container. token = current @@ -723,7 +720,7 @@ def MoveStateToNextToken(self): # If we encounter a closing bracket, we can remove a level from our # parenthesis stack. if len(self.stack) > 1 and current.ClosesScope(): - if format_token.Subtype.DICTIONARY_KEY_PART in current.subtypes: + if subtypes.DICTIONARY_KEY_PART in current.subtypes: self.stack[-2].last_space = self.stack[-2].indent else: self.stack[-2].last_space = self.stack[-1].last_space @@ -781,13 +778,12 @@ def _CalculateComprehensionState(self, newline): if newline: top_of_stack.has_interior_split = True - if (format_token.Subtype.COMP_EXPR in current.subtypes and - format_token.Subtype.COMP_EXPR not in previous.subtypes): + if (subtypes.COMP_EXPR in current.subtypes and + subtypes.COMP_EXPR not in previous.subtypes): self.comp_stack.append(object_state.ComprehensionState(current)) return penalty - if (current.value == 'for' and - format_token.Subtype.COMP_FOR in current.subtypes): + if current.value == 'for' and subtypes.COMP_FOR in current.subtypes: if top_of_stack.for_token is not None: # Treat nested comprehensions like normal comp_if expressions. # Example: @@ -811,8 +807,8 @@ def _CalculateComprehensionState(self, newline): top_of_stack.HasTrivialExpr()): penalty += split_penalty.CONNECTED - if (format_token.Subtype.COMP_IF in current.subtypes and - format_token.Subtype.COMP_IF not in previous.subtypes): + if (subtypes.COMP_IF in current.subtypes and + subtypes.COMP_IF not in previous.subtypes): # Penalize breaking at comp_if when it doesn't match the newline structure # in the rest of the comprehension. if (style.Get('SPLIT_COMPLEX_COMPREHENSION') and @@ -914,7 +910,7 @@ def _CalculateParameterListState(self, newline): param_list.has_default_values and current != param_list.parameters[0].first_token and current != param_list.closing_bracket and - format_token.Subtype.PARAMETER_START in current.subtypes): + subtypes.PARAMETER_START in current.subtypes): # If we want to split before parameters when there are named assigns, # then add a penalty for not splitting. penalty += split_penalty.STRONGLY_CONNECTED @@ -961,12 +957,12 @@ def _GetNewlineColumn(self): return top_of_stack.closing_scope_indent if (previous and previous.is_string and current.is_string and - format_token.Subtype.DICTIONARY_VALUE in current.subtypes): + subtypes.DICTIONARY_VALUE in current.subtypes): return previous.column if style.Get('INDENT_DICTIONARY_VALUE'): if previous and (previous.value == ':' or previous.is_pseudo): - if format_token.Subtype.DICTIONARY_VALUE in current.subtypes: + if subtypes.DICTIONARY_VALUE in current.subtypes: return top_of_stack.indent if (not self.param_list_stack and _IsCompoundStatement(self.line.first) and @@ -983,9 +979,9 @@ def _GetNewlineColumn(self): not self.param_list_stack[-1].SplitBeforeClosingBracket( top_of_stack.indent) and top_of_stack.indent == ((self.line.depth + 1) * style.Get('INDENT_WIDTH'))): - if (format_token.Subtype.PARAMETER_START in current.subtypes or + if (subtypes.PARAMETER_START in current.subtypes or (previous.is_comment and - format_token.Subtype.PARAMETER_START in previous.subtypes)): + subtypes.PARAMETER_START in previous.subtypes)): return top_of_stack.indent + style.Get('CONTINUATION_INDENT_WIDTH') return cont_aligned_indent @@ -1029,14 +1025,14 @@ def DictValueIsContainer(opening, closing): key = colon.previous_token if not key: return False - return format_token.Subtype.DICTIONARY_KEY_PART in key.subtypes + return subtypes.DICTIONARY_KEY_PART in key.subtypes closing = opening.matching_bracket entry_start = opening.next_token current = opening.next_token.next_token while current and current != closing: - if format_token.Subtype.DICTIONARY_KEY in current.subtypes: + if subtypes.DICTIONARY_KEY in current.subtypes: prev = PreviousNonCommentToken(current) if prev.value == ',': prev = PreviousNonCommentToken(prev.previous_token) @@ -1049,7 +1045,7 @@ def DictValueIsContainer(opening, closing): if current.OpensScope(): if ((current.value == '{' or (current.is_pseudo and current.next_token.value == '{') and - format_token.Subtype.DICTIONARY_VALUE in current.subtypes) or + subtypes.DICTIONARY_VALUE in current.subtypes) or ImplicitStringConcatenation(current)): # A dictionary entry that cannot fit on a single line shouldn't matter # to this calculation. If it can't fit on a single line, then the @@ -1061,7 +1057,7 @@ def DictValueIsContainer(opening, closing): while current: if current == closing: return True - if format_token.Subtype.DICTIONARY_KEY in current.subtypes: + if subtypes.DICTIONARY_KEY in current.subtypes: entry_start = current break current = current.next_token @@ -1163,8 +1159,7 @@ def _LastTokenInLine(current): def _IsFunctionDefinition(current): prev = current.previous_token - return (current.value == '(' and prev and - format_token.Subtype.FUNC_DEF in prev.subtypes) + return current.value == '(' and prev and subtypes.FUNC_DEF in prev.subtypes def _IsLastScopeInLine(current): diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 65615d74b..1f3f73e9c 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -24,42 +24,11 @@ from yapf.yapflib import py3compat from yapf.yapflib import pytree_utils from yapf.yapflib import style +from yapf.yapflib import subtypes CONTINUATION = token.N_TOKENS -class Subtype(object): - """Subtype information about tokens. - - Gleaned from parsing the code. Helps determine the best formatting. - """ - NONE = 0 - UNARY_OPERATOR = 1 - BINARY_OPERATOR = 2 - SUBSCRIPT_COLON = 5 - SUBSCRIPT_BRACKET = 6 - DEFAULT_OR_NAMED_ASSIGN = 7 - DEFAULT_OR_NAMED_ASSIGN_ARG_LIST = 8 - VARARGS_LIST = 9 - VARARGS_STAR = 10 - KWARGS_STAR_STAR = 11 - ASSIGN_OPERATOR = 12 - DICTIONARY_KEY = 13 - DICTIONARY_KEY_PART = 14 - DICTIONARY_VALUE = 15 - DICT_SET_GENERATOR = 16 - COMP_EXPR = 17 - COMP_FOR = 18 - COMP_IF = 19 - FUNC_DEF = 20 - DECORATOR = 21 - TYPED_NAME = 22 - TYPED_NAME_ARG_LIST = 23 - SIMPLE_EXPRESSION = 24 - PARAMETER_START = 25 - PARAMETER_STOP = 26 - - def _TabbedContinuationAlignPadding(spaces, align_style, tab_width): """Build padding string for continuation alignment in tabbed indentation. @@ -149,9 +118,9 @@ def __init__(self, node): if self.is_continuation: self.value = node.value.rstrip() - subtypes = pytree_utils.GetNodeAnnotation(node, - pytree_utils.Annotation.SUBTYPE) - self.subtypes = [Subtype.NONE] if subtypes is None else subtypes + stypes = pytree_utils.GetNodeAnnotation(node, + pytree_utils.Annotation.SUBTYPE) + self.subtypes = [subtypes.NONE] if stypes is None else stypes self.is_pseudo = hasattr(node, 'is_pseudo') and node.is_pseudo @property @@ -262,7 +231,7 @@ def node_split_penalty(self): @property def is_binary_op(self): """Token is a binary operator.""" - return Subtype.BINARY_OPERATOR in self.subtypes + return subtypes.BINARY_OPERATOR in self.subtypes @property @py3compat.lru_cache() @@ -287,12 +256,12 @@ def is_arithmetic_op(self): @property def is_simple_expr(self): """Token is an operator in a simple expression.""" - return Subtype.SIMPLE_EXPRESSION in self.subtypes + return subtypes.SIMPLE_EXPRESSION in self.subtypes @property def is_subscript_colon(self): """Token is a subscript colon.""" - return Subtype.SUBSCRIPT_COLON in self.subtypes + return subtypes.SUBSCRIPT_COLON in self.subtypes @property def is_comment(self): diff --git a/yapf/yapflib/object_state.py b/yapf/yapflib/object_state.py index f640db5eb..07925efa8 100644 --- a/yapf/yapflib/object_state.py +++ b/yapf/yapflib/object_state.py @@ -25,6 +25,7 @@ from yapf.yapflib import format_token from yapf.yapflib import py3compat from yapf.yapflib import style +from yapf.yapflib import subtypes class ComprehensionState(object): @@ -210,7 +211,7 @@ def has_default_value(self): """Returns true if the parameter has a default value.""" tok = self.first_token while tok != self.last_token: - if format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in tok.subtypes: + if subtypes.DEFAULT_OR_NAMED_ASSIGN in tok.subtypes: return True tok = tok.matching_bracket if tok.OpensScope() else tok.next_token return False diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index 88272efd3..15d9dd7c8 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -37,6 +37,7 @@ from yapf.yapflib import pytree_visitor from yapf.yapflib import split_penalty from yapf.yapflib import style +from yapf.yapflib import subtypes from yapf.yapflib import unwrapped_line @@ -337,7 +338,7 @@ def _IdentifyParameterLists(uwline): param_stack = [] for tok in uwline.tokens: # Identify parameter list objects. - if format_token.Subtype.FUNC_DEF in tok.subtypes: + if subtypes.FUNC_DEF in tok.subtypes: assert tok.next_token.value == '(' func_stack.append(tok.next_token) continue @@ -348,11 +349,11 @@ def _IdentifyParameterLists(uwline): continue # Identify parameter objects. - if format_token.Subtype.PARAMETER_START in tok.subtypes: + if subtypes.PARAMETER_START in tok.subtypes: param_stack.append(tok) # Not "elif", a parameter could be a single token. - if param_stack and format_token.Subtype.PARAMETER_STOP in tok.subtypes: + if param_stack and subtypes.PARAMETER_STOP in tok.subtypes: start = param_stack.pop() func_stack[-1].parameters.append(object_state.Parameter(start, tok)) diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 40aedb4ab..643ae24f3 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -23,6 +23,7 @@ from yapf.yapflib import pytree_utils from yapf.yapflib import pytree_visitor from yapf.yapflib import style +from yapf.yapflib import subtypes # TODO(morbo): Document the annotations in a centralized place. E.g., the # README file. @@ -256,9 +257,9 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name 'atom', 'power' }: # Don't split an argument list with one element if at all possible. - subtypes = pytree_utils.GetNodeAnnotation( + stypes = pytree_utils.GetNodeAnnotation( pytree_utils.FirstLeafNode(node), pytree_utils.Annotation.SUBTYPE) - if subtypes and format_token.Subtype.SUBSCRIPT_BRACKET in subtypes: + if stypes and subtypes.SUBSCRIPT_BRACKET in stypes: _IncreasePenalty(node, SUBSCRIPT) # Bump up the split penalty for the first part of a subscript. We @@ -319,9 +320,9 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring break if trailer.children[0].value in '([': if len(trailer.children) > 2: - subtypes = pytree_utils.GetNodeAnnotation( + stypes = pytree_utils.GetNodeAnnotation( trailer.children[0], pytree_utils.Annotation.SUBTYPE) - if subtypes and format_token.Subtype.SUBSCRIPT_BRACKET in subtypes: + if stypes and subtypes.SUBSCRIPT_BRACKET in stypes: _SetStronglyConnected( pytree_utils.FirstLeafNode(trailer.children[1])) diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 7bcdf5fed..7b45586b5 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -11,18 +11,17 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -"""Subtype assigner for lib2to3 trees. +"""Subtype assigner for format tokens. -This module assigns extra type information to the lib2to3 trees. This -information is more specific than whether something is an operator or an -identifier. For instance, it can specify if a node in the tree is part of a -subscript. +This module assigns extra type information to format tokens. This information is +more specific than whether something is an operator or an identifier. For +instance, it can specify if a node in the tree is part of a subscript. AssignSubtypes(): the main function exported by this module. Annotations: - subtype: The subtype of a pytree token. See 'format_token' module for a list - of subtypes. + subtype: The subtype of a pytree token. See 'subtypes' module for a list of + subtypes. """ from lib2to3 import pytree @@ -33,6 +32,7 @@ from yapf.yapflib import pytree_utils from yapf.yapflib import pytree_visitor from yapf.yapflib import style +from yapf.yapflib import subtypes def AssignSubtypes(tree): @@ -47,10 +47,10 @@ def AssignSubtypes(tree): # Map tokens in argument lists to their respective subtype. _ARGLIST_TOKEN_TO_SUBTYPE = { - '=': format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN, - ':': format_token.Subtype.TYPED_NAME, - '*': format_token.Subtype.VARARGS_STAR, - '**': format_token.Subtype.KWARGS_STAR_STAR, + '=': subtypes.DEFAULT_OR_NAMED_ASSIGN, + ':': subtypes.TYPED_NAME, + '*': subtypes.VARARGS_STAR, + '**': subtypes.KWARGS_STAR_STAR, } @@ -73,8 +73,7 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name for child in node.children: if pytree_utils.NodeName(child) == 'comp_for': comp_for = True - _AppendFirstLeafTokenSubtype(child, - format_token.Subtype.DICT_SET_GENERATOR) + _AppendFirstLeafTokenSubtype(child, subtypes.DICT_SET_GENERATOR) elif child.type in (grammar_token.COLON, grammar_token.DOUBLESTAR): dict_maker = True @@ -83,23 +82,20 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name unpacking = False for child in node.children: if child.type == grammar_token.DOUBLESTAR: - _AppendFirstLeafTokenSubtype(child, - format_token.Subtype.KWARGS_STAR_STAR) + _AppendFirstLeafTokenSubtype(child, subtypes.KWARGS_STAR_STAR) if last_was_colon: if style.Get('INDENT_DICTIONARY_VALUE'): _InsertPseudoParentheses(child) else: - _AppendFirstLeafTokenSubtype(child, - format_token.Subtype.DICTIONARY_VALUE) + _AppendFirstLeafTokenSubtype(child, subtypes.DICTIONARY_VALUE) elif (isinstance(child, pytree.Node) or (not child.value.startswith('#') and child.value not in '{:,')): # Mark the first leaf of a key entry as a DICTIONARY_KEY. We # normally want to split before them if the dictionary cannot exist # on a single line. if not unpacking or pytree_utils.FirstLeafNode(child).value == '**': - _AppendFirstLeafTokenSubtype(child, - format_token.Subtype.DICTIONARY_KEY) - _AppendSubtypeRec(child, format_token.Subtype.DICTIONARY_KEY_PART) + _AppendFirstLeafTokenSubtype(child, subtypes.DICTIONARY_KEY) + _AppendSubtypeRec(child, subtypes.DICTIONARY_KEY_PART) last_was_colon = child.type == grammar_token.COLON if child.type == grammar_token.DOUBLESTAR: unpacking = True @@ -112,28 +108,28 @@ def Visit_expr_stmt(self, node): # pylint: disable=invalid-name for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == '=': - _AppendTokenSubtype(child, format_token.Subtype.ASSIGN_OPERATOR) + _AppendTokenSubtype(child, subtypes.ASSIGN_OPERATOR) def Visit_or_test(self, node): # pylint: disable=invalid-name # or_test ::= and_test ('or' and_test)* for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == 'or': - _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) def Visit_and_test(self, node): # pylint: disable=invalid-name # and_test ::= not_test ('and' not_test)* for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == 'and': - _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) def Visit_not_test(self, node): # pylint: disable=invalid-name # not_test ::= 'not' not_test | comparison for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == 'not': - _AppendTokenSubtype(child, format_token.Subtype.UNARY_OPERATOR) + _AppendTokenSubtype(child, subtypes.UNARY_OPERATOR) def Visit_comparison(self, node): # pylint: disable=invalid-name # comparison ::= expr (comp_op expr)* @@ -142,104 +138,104 @@ def Visit_comparison(self, node): # pylint: disable=invalid-name self.Visit(child) if (isinstance(child, pytree.Leaf) and child.value in {'<', '>', '==', '>=', '<=', '<>', '!=', 'in', 'is'}): - _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) elif pytree_utils.NodeName(child) == 'comp_op': for grandchild in child.children: - _AppendTokenSubtype(grandchild, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(grandchild, subtypes.BINARY_OPERATOR) def Visit_star_expr(self, node): # pylint: disable=invalid-name # star_expr ::= '*' expr for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == '*': - _AppendTokenSubtype(child, format_token.Subtype.UNARY_OPERATOR) - _AppendTokenSubtype(child, format_token.Subtype.VARARGS_STAR) + _AppendTokenSubtype(child, subtypes.UNARY_OPERATOR) + _AppendTokenSubtype(child, subtypes.VARARGS_STAR) def Visit_expr(self, node): # pylint: disable=invalid-name # expr ::= xor_expr ('|' xor_expr)* for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == '|': - _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) def Visit_xor_expr(self, node): # pylint: disable=invalid-name # xor_expr ::= and_expr ('^' and_expr)* for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == '^': - _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) def Visit_and_expr(self, node): # pylint: disable=invalid-name # and_expr ::= shift_expr ('&' shift_expr)* for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == '&': - _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) def Visit_shift_expr(self, node): # pylint: disable=invalid-name # shift_expr ::= arith_expr (('<<'|'>>') arith_expr)* for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value in {'<<', '>>'}: - _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) def Visit_arith_expr(self, node): # pylint: disable=invalid-name # arith_expr ::= term (('+'|'-') term)* for child in node.children: self.Visit(child) if _IsAExprOperator(child): - _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) if _IsSimpleExpression(node): for child in node.children: if _IsAExprOperator(child): - _AppendTokenSubtype(child, format_token.Subtype.SIMPLE_EXPRESSION) + _AppendTokenSubtype(child, subtypes.SIMPLE_EXPRESSION) def Visit_term(self, node): # pylint: disable=invalid-name # term ::= factor (('*'|'/'|'%'|'//'|'@') factor)* for child in node.children: self.Visit(child) if _IsMExprOperator(child): - _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) if _IsSimpleExpression(node): for child in node.children: if _IsMExprOperator(child): - _AppendTokenSubtype(child, format_token.Subtype.SIMPLE_EXPRESSION) + _AppendTokenSubtype(child, subtypes.SIMPLE_EXPRESSION) def Visit_factor(self, node): # pylint: disable=invalid-name # factor ::= ('+'|'-'|'~') factor | power for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value in '+-~': - _AppendTokenSubtype(child, format_token.Subtype.UNARY_OPERATOR) + _AppendTokenSubtype(child, subtypes.UNARY_OPERATOR) def Visit_power(self, node): # pylint: disable=invalid-name # power ::= atom trailer* ['**' factor] for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == '**': - _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR) + _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) def Visit_trailer(self, node): # pylint: disable=invalid-name for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value in '[]': - _AppendTokenSubtype(child, format_token.Subtype.SUBSCRIPT_BRACKET) + _AppendTokenSubtype(child, subtypes.SUBSCRIPT_BRACKET) def Visit_subscript(self, node): # pylint: disable=invalid-name # subscript ::= test | [test] ':' [test] [sliceop] for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == ':': - _AppendTokenSubtype(child, format_token.Subtype.SUBSCRIPT_COLON) + _AppendTokenSubtype(child, subtypes.SUBSCRIPT_COLON) def Visit_sliceop(self, node): # pylint: disable=invalid-name # sliceop ::= ':' [test] for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == ':': - _AppendTokenSubtype(child, format_token.Subtype.SUBSCRIPT_COLON) + _AppendTokenSubtype(child, subtypes.SUBSCRIPT_COLON) def Visit_argument(self, node): # pylint: disable=invalid-name # argument ::= @@ -252,20 +248,20 @@ def Visit_arglist(self, node): # pylint: disable=invalid-name # | '*' test (',' argument)* [',' '**' test] # | '**' test) self._ProcessArgLists(node) - _SetArgListSubtype(node, format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) + _SetArgListSubtype(node, subtypes.DEFAULT_OR_NAMED_ASSIGN, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) def Visit_tname(self, node): # pylint: disable=invalid-name self._ProcessArgLists(node) - _SetArgListSubtype(node, format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) + _SetArgListSubtype(node, subtypes.DEFAULT_OR_NAMED_ASSIGN, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) def Visit_decorator(self, node): # pylint: disable=invalid-name # decorator ::= # '@' dotted_name [ '(' [arglist] ')' ] NEWLINE for child in node.children: if isinstance(child, pytree.Leaf) and child.value == '@': - _AppendTokenSubtype(child, subtype=format_token.Subtype.DECORATOR) + _AppendTokenSubtype(child, subtype=subtypes.DECORATOR) self.Visit(child) def Visit_funcdef(self, node): # pylint: disable=invalid-name @@ -273,7 +269,7 @@ def Visit_funcdef(self, node): # pylint: disable=invalid-name # 'def' NAME parameters ['->' test] ':' suite for child in node.children: if child.type == grammar_token.NAME and child.value != 'def': - _AppendTokenSubtype(child, format_token.Subtype.FUNC_DEF) + _AppendTokenSubtype(child, subtypes.FUNC_DEF) break for child in node.children: self.Visit(child) @@ -282,10 +278,8 @@ def Visit_parameters(self, node): # pylint: disable=invalid-name # parameters ::= '(' [typedargslist] ')' self._ProcessArgLists(node) if len(node.children) > 2: - _AppendFirstLeafTokenSubtype(node.children[1], - format_token.Subtype.PARAMETER_START) - _AppendLastLeafTokenSubtype(node.children[-2], - format_token.Subtype.PARAMETER_STOP) + _AppendFirstLeafTokenSubtype(node.children[1], subtypes.PARAMETER_START) + _AppendLastLeafTokenSubtype(node.children[-2], subtypes.PARAMETER_STOP) def Visit_typedargslist(self, node): # pylint: disable=invalid-name # typedargslist ::= @@ -294,36 +288,32 @@ def Visit_typedargslist(self, node): # pylint: disable=invalid-name # | '**' tname) # | tfpdef ['=' test] (',' tfpdef ['=' test])* [',']) self._ProcessArgLists(node) - _SetArgListSubtype(node, format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) + _SetArgListSubtype(node, subtypes.DEFAULT_OR_NAMED_ASSIGN, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) tname = False if not node.children: return - _AppendFirstLeafTokenSubtype(node.children[0], - format_token.Subtype.PARAMETER_START) - _AppendLastLeafTokenSubtype(node.children[-1], - format_token.Subtype.PARAMETER_STOP) + _AppendFirstLeafTokenSubtype(node.children[0], subtypes.PARAMETER_START) + _AppendLastLeafTokenSubtype(node.children[-1], subtypes.PARAMETER_STOP) tname = pytree_utils.NodeName(node.children[0]) == 'tname' for i in range(1, len(node.children)): prev_child = node.children[i - 1] child = node.children[i] if prev_child.type == grammar_token.COMMA: - _AppendFirstLeafTokenSubtype(child, - format_token.Subtype.PARAMETER_START) + _AppendFirstLeafTokenSubtype(child, subtypes.PARAMETER_START) elif child.type == grammar_token.COMMA: - _AppendLastLeafTokenSubtype(prev_child, - format_token.Subtype.PARAMETER_STOP) + _AppendLastLeafTokenSubtype(prev_child, subtypes.PARAMETER_STOP) if pytree_utils.NodeName(child) == 'tname': tname = True - _SetArgListSubtype(child, format_token.Subtype.TYPED_NAME, - format_token.Subtype.TYPED_NAME_ARG_LIST) + _SetArgListSubtype(child, subtypes.TYPED_NAME, + subtypes.TYPED_NAME_ARG_LIST) elif child.type == grammar_token.COMMA: tname = False elif child.type == grammar_token.EQUAL and tname: - _AppendTokenSubtype(child, subtype=format_token.Subtype.TYPED_NAME) + _AppendTokenSubtype(child, subtype=subtypes.TYPED_NAME) tname = False def Visit_varargslist(self, node): # pylint: disable=invalid-name @@ -336,17 +326,17 @@ def Visit_varargslist(self, node): # pylint: disable=invalid-name for child in node.children: self.Visit(child) if isinstance(child, pytree.Leaf) and child.value == '=': - _AppendTokenSubtype(child, format_token.Subtype.VARARGS_LIST) + _AppendTokenSubtype(child, subtypes.VARARGS_LIST) def Visit_comp_for(self, node): # pylint: disable=invalid-name # comp_for ::= 'for' exprlist 'in' testlist_safe [comp_iter] - _AppendSubtypeRec(node, format_token.Subtype.COMP_FOR) + _AppendSubtypeRec(node, subtypes.COMP_FOR) # Mark the previous node as COMP_EXPR unless this is a nested comprehension # as these will have the outer comprehension as their previous node. attr = pytree_utils.GetNodeAnnotation(node.parent, pytree_utils.Annotation.SUBTYPE) - if not attr or format_token.Subtype.COMP_FOR not in attr: - _AppendSubtypeRec(node.parent.children[0], format_token.Subtype.COMP_EXPR) + if not attr or subtypes.COMP_FOR not in attr: + _AppendSubtypeRec(node.parent.children[0], subtypes.COMP_EXPR) self.DefaultNodeVisit(node) def Visit_old_comp_for(self, node): # pylint: disable=invalid-name @@ -355,7 +345,7 @@ def Visit_old_comp_for(self, node): # pylint: disable=invalid-name def Visit_comp_if(self, node): # pylint: disable=invalid-name # comp_if ::= 'if' old_test [comp_iter] - _AppendSubtypeRec(node, format_token.Subtype.COMP_IF) + _AppendSubtypeRec(node, subtypes.COMP_IF) self.DefaultNodeVisit(node) def Visit_old_comp_if(self, node): # pylint: disable=invalid-name @@ -369,8 +359,7 @@ def _ProcessArgLists(self, node): if isinstance(child, pytree.Leaf): _AppendTokenSubtype( child, - subtype=_ARGLIST_TOKEN_TO_SUBTYPE.get(child.value, - format_token.Subtype.NONE)) + subtype=_ARGLIST_TOKEN_TO_SUBTYPE.get(child.value, subtypes.NONE)) def _SetArgListSubtype(node, node_subtype, list_subtype): @@ -482,14 +471,14 @@ def _InsertPseudoParentheses(node): node.append_child(rparen) if comment_node: node.append_child(comment_node) - _AppendFirstLeafTokenSubtype(node, format_token.Subtype.DICTIONARY_VALUE) + _AppendFirstLeafTokenSubtype(node, subtypes.DICTIONARY_VALUE) else: clone = node.clone() for orig_leaf, clone_leaf in zip(node.leaves(), clone.leaves()): pytree_utils.CopyYapfAnnotations(orig_leaf, clone_leaf) new_node = pytree.Node(syms.atom, [lparen, clone, rparen]) node.replace(new_node) - _AppendFirstLeafTokenSubtype(clone, format_token.Subtype.DICTIONARY_VALUE) + _AppendFirstLeafTokenSubtype(clone, subtypes.DICTIONARY_VALUE) def _IsAExprOperator(node): diff --git a/yapf/yapflib/subtypes.py b/yapf/yapflib/subtypes.py new file mode 100644 index 000000000..b4b7efe75 --- /dev/null +++ b/yapf/yapflib/subtypes.py @@ -0,0 +1,40 @@ +# Copyright 2021 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Token subtypes used to improve formatting.""" + +NONE = 0 +UNARY_OPERATOR = 1 +BINARY_OPERATOR = 2 +SUBSCRIPT_COLON = 3 +SUBSCRIPT_BRACKET = 4 +DEFAULT_OR_NAMED_ASSIGN = 5 +DEFAULT_OR_NAMED_ASSIGN_ARG_LIST = 6 +VARARGS_LIST = 7 +VARARGS_STAR = 8 +KWARGS_STAR_STAR = 9 +ASSIGN_OPERATOR = 10 +DICTIONARY_KEY = 11 +DICTIONARY_KEY_PART = 12 +DICTIONARY_VALUE = 13 +DICT_SET_GENERATOR = 14 +COMP_EXPR = 15 +COMP_FOR = 16 +COMP_IF = 17 +FUNC_DEF = 18 +DECORATOR = 19 +TYPED_NAME = 20 +TYPED_NAME_ARG_LIST = 21 +SIMPLE_EXPRESSION = 22 +PARAMETER_START = 23 +PARAMETER_STOP = 24 diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 6cbd20eb1..778cd8e57 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -24,6 +24,7 @@ from yapf.yapflib import pytree_utils from yapf.yapflib import split_penalty from yapf.yapflib import style +from yapf.yapflib import subtypes from lib2to3.fixer_util import syms as python_symbols @@ -224,7 +225,7 @@ def _IsIdNumberStringToken(tok): def _IsUnaryOperator(tok): - return format_token.Subtype.UNARY_OPERATOR in tok.subtypes + return subtypes.UNARY_OPERATOR in tok.subtypes def _HasPrecedence(tok): @@ -318,7 +319,7 @@ def _SpaceRequiredBetween(left, right, is_line_disabled): # Space after the '.' in an import statement. return True if (lval == '=' and rval in {'.', ',,,'} and - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN not in left.subtypes): + subtypes.DEFAULT_OR_NAMED_ASSIGN not in left.subtypes): # Space between equal and '.' as in "X = ...". return True if lval == ':' and rval in {'.', '...'}: @@ -328,17 +329,17 @@ def _SpaceRequiredBetween(left, right, is_line_disabled): (left.is_keyword or left.is_name)): # Don't merge two keywords/identifiers. return True - if (format_token.Subtype.SUBSCRIPT_COLON in left.subtypes or - format_token.Subtype.SUBSCRIPT_COLON in right.subtypes): + if (subtypes.SUBSCRIPT_COLON in left.subtypes or + subtypes.SUBSCRIPT_COLON in right.subtypes): # A subscript shouldn't have spaces separating its colons. return False - if (format_token.Subtype.TYPED_NAME in left.subtypes or - format_token.Subtype.TYPED_NAME in right.subtypes): + if (subtypes.TYPED_NAME in left.subtypes or + subtypes.TYPED_NAME in right.subtypes): # A typed argument should have a space after the colon. return True if left.is_string: - if (rval == '=' and format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST - in right.subtypes): + if (rval == '=' and + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in right.subtypes): # If there is a type hint, then we don't want to add a space between the # equal sign and the hint. return False @@ -351,7 +352,7 @@ def _SpaceRequiredBetween(left, right, is_line_disabled): # depending on SPACE_INSIDE_BRACKETS. A string followed by opening # brackets, however, should not. return style.Get('SPACE_INSIDE_BRACKETS') - if format_token.Subtype.SUBSCRIPT_BRACKET in right.subtypes: + if subtypes.SUBSCRIPT_BRACKET in right.subtypes: # It's legal to do this in Python: 'hello'[a] return False if left.is_binary_op and lval != '**' and _IsUnaryOperator(right): @@ -383,22 +384,22 @@ def _SpaceRequiredBetween(left, right, is_line_disabled): # The previous token was a unary op. No space is desired between it and # the current token. return False - if (format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in left.subtypes and - format_token.Subtype.TYPED_NAME not in right.subtypes): + if (subtypes.DEFAULT_OR_NAMED_ASSIGN in left.subtypes and + subtypes.TYPED_NAME not in right.subtypes): # A named argument or default parameter shouldn't have spaces around it. return style.Get('SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN') - if (format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in right.subtypes and - format_token.Subtype.TYPED_NAME not in left.subtypes): + if (subtypes.DEFAULT_OR_NAMED_ASSIGN in right.subtypes and + subtypes.TYPED_NAME not in left.subtypes): # A named argument or default parameter shouldn't have spaces around it. return style.Get('SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN') - if (format_token.Subtype.VARARGS_LIST in left.subtypes or - format_token.Subtype.VARARGS_LIST in right.subtypes): + if (subtypes.VARARGS_LIST in left.subtypes or + subtypes.VARARGS_LIST in right.subtypes): return False - if (format_token.Subtype.VARARGS_STAR in left.subtypes or - format_token.Subtype.KWARGS_STAR_STAR in left.subtypes): + if (subtypes.VARARGS_STAR in left.subtypes or + subtypes.KWARGS_STAR_STAR in left.subtypes): # Don't add a space after a vararg's star or a keyword's star-star. return False - if lval == '@' and format_token.Subtype.DECORATOR in left.subtypes: + if lval == '@' and subtypes.DECORATOR in left.subtypes: # Decorators shouldn't be separated from the 'at' sign. return False if left.is_keyword and rval == '.': @@ -464,8 +465,8 @@ def _SpaceRequiredBetween(left, right, is_line_disabled): # by SPACE_INSIDE_BRACKETS. return style.Get('SPACE_INSIDE_BRACKETS') if (lval in pytree_utils.OPENING_BRACKETS and - (format_token.Subtype.VARARGS_STAR in right.subtypes or - format_token.Subtype.KWARGS_STAR_STAR in right.subtypes)): + (subtypes.VARARGS_STAR in right.subtypes or + subtypes.KWARGS_STAR_STAR in right.subtypes)): # Don't separate a '*' or '**' from the opening bracket, unless enabled # by SPACE_INSIDE_BRACKETS. return style.Get('SPACE_INSIDE_BRACKETS') @@ -526,12 +527,12 @@ def _CanBreakBefore(prev_token, cur_token): if cur_token.is_comment and prev_token.lineno == cur_token.lineno: # Don't break a comment at the end of the line. return False - if format_token.Subtype.UNARY_OPERATOR in prev_token.subtypes: + if subtypes.UNARY_OPERATOR in prev_token.subtypes: # Don't break after a unary token. return False if not style.Get('ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS'): - if (format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in cur_token.subtypes or - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in prev_token.subtypes): + if (subtypes.DEFAULT_OR_NAMED_ASSIGN in cur_token.subtypes or + subtypes.DEFAULT_OR_NAMED_ASSIGN in prev_token.subtypes): return False return True @@ -635,11 +636,11 @@ def _SplitPenalty(prev_token, cur_token): if cval in _BITWISE_OPERATORS: return style.Get('SPLIT_PENALTY_BITWISE_OPERATOR') - if (format_token.Subtype.COMP_FOR in cur_token.subtypes or - format_token.Subtype.COMP_IF in cur_token.subtypes): + if (subtypes.COMP_FOR in cur_token.subtypes or + subtypes.COMP_IF in cur_token.subtypes): # We don't mind breaking before the 'for' or 'if' of a list comprehension. return 0 - if format_token.Subtype.UNARY_OPERATOR in prev_token.subtypes: + if subtypes.UNARY_OPERATOR in prev_token.subtypes: # Try not to break after a unary operator. return style.Get('SPLIT_PENALTY_AFTER_UNARY_OPERATOR') if pval == ',': @@ -647,8 +648,8 @@ def _SplitPenalty(prev_token, cur_token): return 0 if pval == '**' or cval == '**': return split_penalty.STRONGLY_CONNECTED - if (format_token.Subtype.VARARGS_STAR in prev_token.subtypes or - format_token.Subtype.KWARGS_STAR_STAR in prev_token.subtypes): + if (subtypes.VARARGS_STAR in prev_token.subtypes or + subtypes.KWARGS_STAR_STAR in prev_token.subtypes): # Don't split after a varargs * or kwargs **. return split_penalty.UNBREAKABLE if prev_token.OpensScope() and cval != '(': @@ -660,8 +661,8 @@ def _SplitPenalty(prev_token, cur_token): if cval == '=': # Don't split before an assignment. return split_penalty.UNBREAKABLE - if (format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in prev_token.subtypes or - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in cur_token.subtypes): + if (subtypes.DEFAULT_OR_NAMED_ASSIGN in prev_token.subtypes or + subtypes.DEFAULT_OR_NAMED_ASSIGN in cur_token.subtypes): # Don't break before or after an default or named assignment. return split_penalty.UNBREAKABLE if cval == '==': diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index d695be13c..2438646e3 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -18,6 +18,7 @@ from yapf.yapflib import format_token from yapf.yapflib import pytree_utils +from yapf.yapflib import subtypes from yapftests import yapf_test_helper @@ -51,56 +52,56 @@ def foo(a=37, *b, **c): uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [ - ('def', [format_token.Subtype.NONE]), - ('foo', {format_token.Subtype.FUNC_DEF}), - ('(', {format_token.Subtype.NONE}), + ('def', [subtypes.NONE]), + ('foo', {subtypes.FUNC_DEF}), + ('(', {subtypes.NONE}), ('a', { - format_token.Subtype.NONE, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - format_token.Subtype.PARAMETER_START, + subtypes.NONE, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + subtypes.PARAMETER_START, }), ('=', { - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + subtypes.DEFAULT_OR_NAMED_ASSIGN, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, }), ('37', { - format_token.Subtype.NONE, - format_token.Subtype.PARAMETER_STOP, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + subtypes.NONE, + subtypes.PARAMETER_STOP, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, }), - (',', {format_token.Subtype.NONE}), + (',', {subtypes.NONE}), ('*', { - format_token.Subtype.PARAMETER_START, - format_token.Subtype.VARARGS_STAR, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + subtypes.PARAMETER_START, + subtypes.VARARGS_STAR, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, }), ('b', { - format_token.Subtype.NONE, - format_token.Subtype.PARAMETER_STOP, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + subtypes.NONE, + subtypes.PARAMETER_STOP, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, }), - (',', {format_token.Subtype.NONE}), + (',', {subtypes.NONE}), ('**', { - format_token.Subtype.PARAMETER_START, - format_token.Subtype.KWARGS_STAR_STAR, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + subtypes.PARAMETER_START, + subtypes.KWARGS_STAR_STAR, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, }), ('c', { - format_token.Subtype.NONE, - format_token.Subtype.PARAMETER_STOP, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + subtypes.NONE, + subtypes.PARAMETER_STOP, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, }), - (')', {format_token.Subtype.NONE}), - (':', [format_token.Subtype.NONE]), + (')', {subtypes.NONE}), + (':', [subtypes.NONE]), ], [ - ('return', [format_token.Subtype.NONE]), - ('-', {format_token.Subtype.UNARY_OPERATOR}), - ('x', [format_token.Subtype.NONE]), - ('[', {format_token.Subtype.SUBSCRIPT_BRACKET}), - (':', {format_token.Subtype.SUBSCRIPT_COLON}), - ('42', [format_token.Subtype.NONE]), - (']', {format_token.Subtype.SUBSCRIPT_BRACKET}), + ('return', [subtypes.NONE]), + ('-', {subtypes.UNARY_OPERATOR}), + ('x', [subtypes.NONE]), + ('[', {subtypes.SUBSCRIPT_BRACKET}), + (':', {subtypes.SUBSCRIPT_COLON}), + ('42', [subtypes.NONE]), + (']', {subtypes.SUBSCRIPT_BRACKET}), ], ]) @@ -111,20 +112,20 @@ def testFuncCallWithDefaultAssign(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [ - ('foo', [format_token.Subtype.NONE]), - ('(', [format_token.Subtype.NONE]), + ('foo', [subtypes.NONE]), + ('(', [subtypes.NONE]), ('x', { - format_token.Subtype.NONE, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + subtypes.NONE, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, }), - (',', {format_token.Subtype.NONE}), + (',', {subtypes.NONE}), ('a', { - format_token.Subtype.NONE, - format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + subtypes.NONE, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, }), - ('=', {format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN}), - ("'hello world'", {format_token.Subtype.NONE}), - (')', [format_token.Subtype.NONE]), + ('=', {subtypes.DEFAULT_OR_NAMED_ASSIGN}), + ("'hello world'", {subtypes.NONE}), + (')', [subtypes.NONE]), ], ]) @@ -136,33 +137,33 @@ def foo(strs): uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [ - ('def', [format_token.Subtype.NONE]), - ('foo', {format_token.Subtype.FUNC_DEF}), - ('(', {format_token.Subtype.NONE}), + ('def', [subtypes.NONE]), + ('foo', {subtypes.FUNC_DEF}), + ('(', {subtypes.NONE}), ('strs', { - format_token.Subtype.NONE, - format_token.Subtype.PARAMETER_START, - format_token.Subtype.PARAMETER_STOP, + subtypes.NONE, + subtypes.PARAMETER_START, + subtypes.PARAMETER_STOP, }), - (')', {format_token.Subtype.NONE}), - (':', [format_token.Subtype.NONE]), + (')', {subtypes.NONE}), + (':', [subtypes.NONE]), ], [ - ('return', [format_token.Subtype.NONE]), - ('{', [format_token.Subtype.NONE]), - ('s', {format_token.Subtype.COMP_EXPR}), - ('.', {format_token.Subtype.COMP_EXPR}), - ('lower', {format_token.Subtype.COMP_EXPR}), - ('(', {format_token.Subtype.COMP_EXPR}), - (')', {format_token.Subtype.COMP_EXPR}), + ('return', [subtypes.NONE]), + ('{', [subtypes.NONE]), + ('s', {subtypes.COMP_EXPR}), + ('.', {subtypes.COMP_EXPR}), + ('lower', {subtypes.COMP_EXPR}), + ('(', {subtypes.COMP_EXPR}), + (')', {subtypes.COMP_EXPR}), ('for', { - format_token.Subtype.DICT_SET_GENERATOR, - format_token.Subtype.COMP_FOR, + subtypes.DICT_SET_GENERATOR, + subtypes.COMP_FOR, }), - ('s', {format_token.Subtype.COMP_FOR}), - ('in', {format_token.Subtype.COMP_FOR}), - ('strs', {format_token.Subtype.COMP_FOR}), - ('}', [format_token.Subtype.NONE]), + ('s', {subtypes.COMP_FOR}), + ('in', {subtypes.COMP_FOR}), + ('strs', {subtypes.COMP_FOR}), + ('}', [subtypes.NONE]), ], ]) @@ -171,9 +172,9 @@ def testUnaryNotOperator(self): not a """) uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes( - uwlines, [[('not', {format_token.Subtype.UNARY_OPERATOR}), - ('a', [format_token.Subtype.NONE])]]) + self._CheckFormatTokenSubtypes(uwlines, + [[('not', {subtypes.UNARY_OPERATOR}), + ('a', [subtypes.NONE])]]) def testBitwiseOperators(self): code = textwrap.dedent("""\ @@ -182,25 +183,25 @@ def testBitwiseOperators(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [ - ('x', [format_token.Subtype.NONE]), - ('=', {format_token.Subtype.ASSIGN_OPERATOR}), - ('(', [format_token.Subtype.NONE]), - ('(', [format_token.Subtype.NONE]), - ('a', [format_token.Subtype.NONE]), - ('|', {format_token.Subtype.BINARY_OPERATOR}), - ('(', [format_token.Subtype.NONE]), - ('b', [format_token.Subtype.NONE]), - ('^', {format_token.Subtype.BINARY_OPERATOR}), - ('3', [format_token.Subtype.NONE]), - (')', [format_token.Subtype.NONE]), - ('&', {format_token.Subtype.BINARY_OPERATOR}), - ('c', [format_token.Subtype.NONE]), - (')', [format_token.Subtype.NONE]), - ('<<', {format_token.Subtype.BINARY_OPERATOR}), - ('3', [format_token.Subtype.NONE]), - (')', [format_token.Subtype.NONE]), - ('>>', {format_token.Subtype.BINARY_OPERATOR}), - ('1', [format_token.Subtype.NONE]), + ('x', [subtypes.NONE]), + ('=', {subtypes.ASSIGN_OPERATOR}), + ('(', [subtypes.NONE]), + ('(', [subtypes.NONE]), + ('a', [subtypes.NONE]), + ('|', {subtypes.BINARY_OPERATOR}), + ('(', [subtypes.NONE]), + ('b', [subtypes.NONE]), + ('^', {subtypes.BINARY_OPERATOR}), + ('3', [subtypes.NONE]), + (')', [subtypes.NONE]), + ('&', {subtypes.BINARY_OPERATOR}), + ('c', [subtypes.NONE]), + (')', [subtypes.NONE]), + ('<<', {subtypes.BINARY_OPERATOR}), + ('3', [subtypes.NONE]), + (')', [subtypes.NONE]), + ('>>', {subtypes.BINARY_OPERATOR}), + ('1', [subtypes.NONE]), ], ]) @@ -211,37 +212,37 @@ def testArithmeticOperators(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [ - ('x', [format_token.Subtype.NONE]), - ('=', {format_token.Subtype.ASSIGN_OPERATOR}), - ('(', [format_token.Subtype.NONE]), - ('(', [format_token.Subtype.NONE]), - ('a', [format_token.Subtype.NONE]), - ('+', {format_token.Subtype.BINARY_OPERATOR}), - ('(', [format_token.Subtype.NONE]), - ('b', [format_token.Subtype.NONE]), + ('x', [subtypes.NONE]), + ('=', {subtypes.ASSIGN_OPERATOR}), + ('(', [subtypes.NONE]), + ('(', [subtypes.NONE]), + ('a', [subtypes.NONE]), + ('+', {subtypes.BINARY_OPERATOR}), + ('(', [subtypes.NONE]), + ('b', [subtypes.NONE]), ('-', { - format_token.Subtype.BINARY_OPERATOR, - format_token.Subtype.SIMPLE_EXPRESSION, + subtypes.BINARY_OPERATOR, + subtypes.SIMPLE_EXPRESSION, }), - ('3', [format_token.Subtype.NONE]), - (')', [format_token.Subtype.NONE]), - ('*', {format_token.Subtype.BINARY_OPERATOR}), - ('(', [format_token.Subtype.NONE]), - ('1', [format_token.Subtype.NONE]), + ('3', [subtypes.NONE]), + (')', [subtypes.NONE]), + ('*', {subtypes.BINARY_OPERATOR}), + ('(', [subtypes.NONE]), + ('1', [subtypes.NONE]), ('%', { - format_token.Subtype.BINARY_OPERATOR, - format_token.Subtype.SIMPLE_EXPRESSION, + subtypes.BINARY_OPERATOR, + subtypes.SIMPLE_EXPRESSION, }), - ('c', [format_token.Subtype.NONE]), - (')', [format_token.Subtype.NONE]), - ('@', {format_token.Subtype.BINARY_OPERATOR}), - ('d', [format_token.Subtype.NONE]), - (')', [format_token.Subtype.NONE]), - ('/', {format_token.Subtype.BINARY_OPERATOR}), - ('3', [format_token.Subtype.NONE]), - (')', [format_token.Subtype.NONE]), - ('//', {format_token.Subtype.BINARY_OPERATOR}), - ('1', [format_token.Subtype.NONE]), + ('c', [subtypes.NONE]), + (')', [subtypes.NONE]), + ('@', {subtypes.BINARY_OPERATOR}), + ('d', [subtypes.NONE]), + (')', [subtypes.NONE]), + ('/', {subtypes.BINARY_OPERATOR}), + ('3', [subtypes.NONE]), + (')', [subtypes.NONE]), + ('//', {subtypes.BINARY_OPERATOR}), + ('1', [subtypes.NONE]), ], ]) @@ -252,14 +253,14 @@ def testSubscriptColon(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [ - ('x', [format_token.Subtype.NONE]), - ('[', {format_token.Subtype.SUBSCRIPT_BRACKET}), - ('0', [format_token.Subtype.NONE]), - (':', {format_token.Subtype.SUBSCRIPT_COLON}), - ('42', [format_token.Subtype.NONE]), - (':', {format_token.Subtype.SUBSCRIPT_COLON}), - ('1', [format_token.Subtype.NONE]), - (']', {format_token.Subtype.SUBSCRIPT_BRACKET}), + ('x', [subtypes.NONE]), + ('[', {subtypes.SUBSCRIPT_BRACKET}), + ('0', [subtypes.NONE]), + (':', {subtypes.SUBSCRIPT_COLON}), + ('42', [subtypes.NONE]), + (':', {subtypes.SUBSCRIPT_COLON}), + ('1', [subtypes.NONE]), + (']', {subtypes.SUBSCRIPT_BRACKET}), ], ]) @@ -270,15 +271,15 @@ def testFunctionCallWithStarExpression(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [ - ('[', [format_token.Subtype.NONE]), - ('a', [format_token.Subtype.NONE]), - (',', [format_token.Subtype.NONE]), + ('[', [subtypes.NONE]), + ('a', [subtypes.NONE]), + (',', [subtypes.NONE]), ('*', { - format_token.Subtype.UNARY_OPERATOR, - format_token.Subtype.VARARGS_STAR, + subtypes.UNARY_OPERATOR, + subtypes.VARARGS_STAR, }), - ('b', [format_token.Subtype.NONE]), - (']', [format_token.Subtype.NONE]), + ('b', [subtypes.NONE]), + (']', [subtypes.NONE]), ], ]) From 4da4f9ce0aeefe40f3ad4ded7cac7211f0b529dc Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 25 Dec 2021 00:14:19 -0600 Subject: [PATCH 520/719] Add "splitpenalty" to the format_token repr --- yapf/yapflib/format_token.py | 7 ++++--- yapftests/format_token_test.py | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 1f3f73e9c..af31d3215 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -216,9 +216,10 @@ def ClosesScope(self): return self.value in pytree_utils.CLOSING_BRACKETS def __repr__(self): - msg = 'FormatToken(name={0}, value={1}, column={2}, lineno={3}'.format( - 'DOCSTRING' if self.is_docstring else self.name, self.value, - self.column, self.lineno) + msg = ('FormatToken(name={0}, value={1}, column={2}, lineno={3}, ' + 'splitpenalty={4}'.format( + 'DOCSTRING' if self.is_docstring else self.name, self.value, + self.column, self.lineno, self.split_penalty)) msg += ', pseudo)' if self.is_pseudo else ')' return msg diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index 8c7151ac2..e324983d5 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -68,14 +68,14 @@ class FormatTokenTest(unittest.TestCase): def testSimple(self): tok = format_token.FormatToken(pytree.Leaf(token.STRING, "'hello world'")) self.assertEqual( - "FormatToken(name=DOCSTRING, value='hello world', column=0, lineno=0)", - str(tok)) + "FormatToken(name=DOCSTRING, value='hello world', column=0, " + "lineno=0, splitpenalty=0)", str(tok)) self.assertTrue(tok.is_string) tok = format_token.FormatToken(pytree.Leaf(token.COMMENT, '# A comment')) self.assertEqual( - 'FormatToken(name=COMMENT, value=# A comment, column=0, lineno=0)', - str(tok)) + 'FormatToken(name=COMMENT, value=# A comment, column=0, ' + 'lineno=0, splitpenalty=0)', str(tok)) self.assertTrue(tok.is_comment) def testIsMultilineString(self): From daae87d835b644419d1b13dc7ade14306939829e Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 25 Dec 2021 01:45:53 -0600 Subject: [PATCH 521/719] Fixup YapfError messages --- yapf/__init__.py | 2 ++ yapf/yapflib/errors.py | 7 +++++++ yapf/yapflib/yapf_api.py | 8 ++------ yapftests/yapf_test.py | 7 +++++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index d9b4dd602..d09d4c774 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -103,6 +103,8 @@ def main(argv): style_config=style_config, lines=lines, verify=args.verify) + except errors.YapfError: + raise except Exception as e: raise errors.YapfError(errors.FormatErrorMsg(e)) diff --git a/yapf/yapflib/errors.py b/yapf/yapflib/errors.py index 5726ff148..99e88d9c0 100644 --- a/yapf/yapflib/errors.py +++ b/yapf/yapflib/errors.py @@ -13,6 +13,8 @@ # limitations under the License. """YAPF error objects.""" +from lib2to3.pgen2 import tokenize + def FormatErrorMsg(e): """Convert an exception into a standard format. @@ -27,6 +29,11 @@ def FormatErrorMsg(e): Returns: A properly formatted error message string. """ + if isinstance(e, SyntaxError): + return '{}:{}:{}: {}'.format(e.filename, e.lineno, e.offset, e.msg) + if isinstance(e, tokenize.TokenError): + return '{}:{}:{}: {}'.format(e.filename, e.args[1][0], e.args[1][1], + e.args[0]) return '{}:{}:{}: {}'.format(e.args[1][0], e.args[1][1], e.args[1][2], e.msg) diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index ac0466ece..06c9a734e 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -181,13 +181,9 @@ def FormatCode(unformatted_source, """ try: tree = pytree_utils.ParseCodeToTree(unformatted_source) - except tokenize.TokenError as e: - e.msg = e.args[0] - e.args = (e.msg, (filename, e.args[1][0], e.args[1][1])) - raise except Exception as e: - e.args = (e.args[0], (filename, e.args[1][1], e.args[1][2], e.args[1][3])) - raise + e.filename = filename + raise errors.YapfError(errors.FormatErrorMsg(e)) reformatted_source = FormatTree( tree, style_config=style_config, lines=lines, verify=verify) diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index e11604302..2330f4e18 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -26,6 +26,7 @@ from lib2to3.pgen2 import tokenize +from yapf.yapflib import errors from yapf.yapflib import py3compat from yapf.yapflib import style from yapf.yapflib import yapf_api @@ -62,6 +63,7 @@ def testNoEndingNewline(self): """) self._Check(unformatted_code, expected_formatted_code) + @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testPrintAfterPeriod(self): unformatted_code = textwrap.dedent("""a.print\n""") expected_formatted_code = textwrap.dedent("""a.print\n""") @@ -428,6 +430,7 @@ def assertYapfReformats(self, self.assertEqual(stderrdata, b'') self.assertMultiLineEqual(reformatted_code.decode('utf-8'), expected) + @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testUnicodeEncodingPipedToFile(self): unformatted_code = textwrap.dedent(u"""\ def foo(): @@ -1560,11 +1563,11 @@ class BadInputTest(unittest.TestCase): def testBadSyntax(self): code = ' a = 1\n' - self.assertRaises(SyntaxError, yapf_api.FormatCode, code) + self.assertRaises(errors.YapfError, yapf_api.FormatCode, code) def testBadCode(self): code = 'x = """hello\n' - self.assertRaises(tokenize.TokenError, yapf_api.FormatCode, code) + self.assertRaises(errors.YapfError, yapf_api.FormatCode, code) class DiffIndentTest(unittest.TestCase): From 5be707702c99afbb187dff6663babd90bb140b22 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 25 Dec 2021 02:08:00 -0600 Subject: [PATCH 522/719] Use a set for subtypes. This prevents us from adding the same subtype multiple times. --- yapf/yapflib/format_token.py | 5 +- yapftests/subtype_assigner_test.py | 106 ++++++++++++++--------------- 2 files changed, 57 insertions(+), 54 deletions(-) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index af31d3215..42eeaa521 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -120,7 +120,7 @@ def __init__(self, node): stypes = pytree_utils.GetNodeAnnotation(node, pytree_utils.Annotation.SUBTYPE) - self.subtypes = [subtypes.NONE] if stypes is None else stypes + self.subtypes = {subtypes.NONE} if not stypes else stypes self.is_pseudo = hasattr(node, 'is_pseudo') and node.is_pseudo @property @@ -215,6 +215,9 @@ def OpensScope(self): def ClosesScope(self): return self.value in pytree_utils.CLOSING_BRACKETS + def AddSubtype(self, subtype): + self.subtypes.add(subtype) + def __repr__(self): msg = ('FormatToken(name={0}, value={1}, column={2}, lineno={3}, ' 'splitpenalty={4}'.format( diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index 2438646e3..66be68eea 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -52,7 +52,7 @@ def foo(a=37, *b, **c): uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [ - ('def', [subtypes.NONE]), + ('def', {subtypes.NONE}), ('foo', {subtypes.FUNC_DEF}), ('(', {subtypes.NONE}), ('a', { @@ -92,15 +92,15 @@ def foo(a=37, *b, **c): subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, }), (')', {subtypes.NONE}), - (':', [subtypes.NONE]), + (':', {subtypes.NONE}), ], [ - ('return', [subtypes.NONE]), + ('return', {subtypes.NONE}), ('-', {subtypes.UNARY_OPERATOR}), - ('x', [subtypes.NONE]), + ('x', {subtypes.NONE}), ('[', {subtypes.SUBSCRIPT_BRACKET}), (':', {subtypes.SUBSCRIPT_COLON}), - ('42', [subtypes.NONE]), + ('42', {subtypes.NONE}), (']', {subtypes.SUBSCRIPT_BRACKET}), ], ]) @@ -112,8 +112,8 @@ def testFuncCallWithDefaultAssign(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [ - ('foo', [subtypes.NONE]), - ('(', [subtypes.NONE]), + ('foo', {subtypes.NONE}), + ('(', {subtypes.NONE}), ('x', { subtypes.NONE, subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, @@ -125,7 +125,7 @@ def testFuncCallWithDefaultAssign(self): }), ('=', {subtypes.DEFAULT_OR_NAMED_ASSIGN}), ("'hello world'", {subtypes.NONE}), - (')', [subtypes.NONE]), + (')', {subtypes.NONE}), ], ]) @@ -137,7 +137,7 @@ def foo(strs): uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [ - ('def', [subtypes.NONE]), + ('def', {subtypes.NONE}), ('foo', {subtypes.FUNC_DEF}), ('(', {subtypes.NONE}), ('strs', { @@ -146,11 +146,11 @@ def foo(strs): subtypes.PARAMETER_STOP, }), (')', {subtypes.NONE}), - (':', [subtypes.NONE]), + (':', {subtypes.NONE}), ], [ - ('return', [subtypes.NONE]), - ('{', [subtypes.NONE]), + ('return', {subtypes.NONE}), + ('{', {subtypes.NONE}), ('s', {subtypes.COMP_EXPR}), ('.', {subtypes.COMP_EXPR}), ('lower', {subtypes.COMP_EXPR}), @@ -163,7 +163,7 @@ def foo(strs): ('s', {subtypes.COMP_FOR}), ('in', {subtypes.COMP_FOR}), ('strs', {subtypes.COMP_FOR}), - ('}', [subtypes.NONE]), + ('}', {subtypes.NONE}), ], ]) @@ -174,7 +174,7 @@ def testUnaryNotOperator(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [[('not', {subtypes.UNARY_OPERATOR}), - ('a', [subtypes.NONE])]]) + ('a', {subtypes.NONE})]]) def testBitwiseOperators(self): code = textwrap.dedent("""\ @@ -183,25 +183,25 @@ def testBitwiseOperators(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [ - ('x', [subtypes.NONE]), + ('x', {subtypes.NONE}), ('=', {subtypes.ASSIGN_OPERATOR}), - ('(', [subtypes.NONE]), - ('(', [subtypes.NONE]), - ('a', [subtypes.NONE]), + ('(', {subtypes.NONE}), + ('(', {subtypes.NONE}), + ('a', {subtypes.NONE}), ('|', {subtypes.BINARY_OPERATOR}), - ('(', [subtypes.NONE]), - ('b', [subtypes.NONE]), + ('(', {subtypes.NONE}), + ('b', {subtypes.NONE}), ('^', {subtypes.BINARY_OPERATOR}), - ('3', [subtypes.NONE]), - (')', [subtypes.NONE]), + ('3', {subtypes.NONE}), + (')', {subtypes.NONE}), ('&', {subtypes.BINARY_OPERATOR}), - ('c', [subtypes.NONE]), - (')', [subtypes.NONE]), + ('c', {subtypes.NONE}), + (')', {subtypes.NONE}), ('<<', {subtypes.BINARY_OPERATOR}), - ('3', [subtypes.NONE]), - (')', [subtypes.NONE]), + ('3', {subtypes.NONE}), + (')', {subtypes.NONE}), ('>>', {subtypes.BINARY_OPERATOR}), - ('1', [subtypes.NONE]), + ('1', {subtypes.NONE}), ], ]) @@ -212,37 +212,37 @@ def testArithmeticOperators(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [ - ('x', [subtypes.NONE]), + ('x', {subtypes.NONE}), ('=', {subtypes.ASSIGN_OPERATOR}), - ('(', [subtypes.NONE]), - ('(', [subtypes.NONE]), - ('a', [subtypes.NONE]), + ('(', {subtypes.NONE}), + ('(', {subtypes.NONE}), + ('a', {subtypes.NONE}), ('+', {subtypes.BINARY_OPERATOR}), - ('(', [subtypes.NONE]), - ('b', [subtypes.NONE]), + ('(', {subtypes.NONE}), + ('b', {subtypes.NONE}), ('-', { subtypes.BINARY_OPERATOR, subtypes.SIMPLE_EXPRESSION, }), - ('3', [subtypes.NONE]), - (')', [subtypes.NONE]), + ('3', {subtypes.NONE}), + (')', {subtypes.NONE}), ('*', {subtypes.BINARY_OPERATOR}), - ('(', [subtypes.NONE]), - ('1', [subtypes.NONE]), + ('(', {subtypes.NONE}), + ('1', {subtypes.NONE}), ('%', { subtypes.BINARY_OPERATOR, subtypes.SIMPLE_EXPRESSION, }), - ('c', [subtypes.NONE]), - (')', [subtypes.NONE]), + ('c', {subtypes.NONE}), + (')', {subtypes.NONE}), ('@', {subtypes.BINARY_OPERATOR}), - ('d', [subtypes.NONE]), - (')', [subtypes.NONE]), + ('d', {subtypes.NONE}), + (')', {subtypes.NONE}), ('/', {subtypes.BINARY_OPERATOR}), - ('3', [subtypes.NONE]), - (')', [subtypes.NONE]), + ('3', {subtypes.NONE}), + (')', {subtypes.NONE}), ('//', {subtypes.BINARY_OPERATOR}), - ('1', [subtypes.NONE]), + ('1', {subtypes.NONE}), ], ]) @@ -253,13 +253,13 @@ def testSubscriptColon(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [ - ('x', [subtypes.NONE]), + ('x', {subtypes.NONE}), ('[', {subtypes.SUBSCRIPT_BRACKET}), - ('0', [subtypes.NONE]), + ('0', {subtypes.NONE}), (':', {subtypes.SUBSCRIPT_COLON}), - ('42', [subtypes.NONE]), + ('42', {subtypes.NONE}), (':', {subtypes.SUBSCRIPT_COLON}), - ('1', [subtypes.NONE]), + ('1', {subtypes.NONE}), (']', {subtypes.SUBSCRIPT_BRACKET}), ], ]) @@ -271,15 +271,15 @@ def testFunctionCallWithStarExpression(self): uwlines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(uwlines, [ [ - ('[', [subtypes.NONE]), - ('a', [subtypes.NONE]), - (',', [subtypes.NONE]), + ('[', {subtypes.NONE}), + ('a', {subtypes.NONE}), + (',', {subtypes.NONE}), ('*', { subtypes.UNARY_OPERATOR, subtypes.VARARGS_STAR, }), - ('b', [subtypes.NONE]), - (']', [subtypes.NONE]), + ('b', {subtypes.NONE}), + (']', {subtypes.NONE}), ], ]) From 76e77434d6d74f689fdb0998bc4c24a988e14b32 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 25 Dec 2021 02:09:20 -0600 Subject: [PATCH 523/719] Add "start" and "end" properties This gives the starting (lineno, column) and ending (lineno, column) for a logical line. --- yapf/yapflib/unwrapped_line.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py index 778cd8e57..3b480a0eb 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/unwrapped_line.py @@ -211,6 +211,24 @@ def lineno(self): """ return self.first.lineno + @property + def start(self): + """The start of the logical line. + + Returns: + A tuple of the starting line number and column. + """ + return (self.first.lineno, self.first.column) + + @property + def end(self): + """The end of the logical line. + + Returns: + A tuple of the ending line number and column. + """ + return (self.last.lineno, self.last.column + len(self.last.value)) + @property def is_comment(self): return self.first.is_comment From cd5a45949625db0440928d7bae6e7e138be0c5c2 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 25 Dec 2021 22:31:14 -0600 Subject: [PATCH 524/719] Use "logical line" instead of "unwrapped line" The concept of an "unwrapped line" is better described as a "logical line". Use that nomenclature instead. --- CHANGELOG | 2 + README.rst | 16 +- yapf/yapflib/format_decision_state.py | 31 +- yapf/yapflib/format_token.py | 10 +- yapf/yapflib/line_joiner.py | 8 +- .../{unwrapped_line.py => logical_line.py} | 46 +- yapf/yapflib/pytree_unwrapper.py | 76 +- yapf/yapflib/reformatter.py | 225 +++--- yapf/yapflib/style.py | 2 +- yapf/yapflib/yapf_api.py | 28 +- yapftests/blank_line_calculator_test.py | 40 +- yapftests/format_decision_state_test.py | 24 +- yapftests/line_joiner_test.py | 6 +- ...pped_line_test.py => logical_line_test.py} | 48 +- yapftests/pytree_unwrapper_test.py | 104 +-- yapftests/reformatter_basic_test.py | 692 +++++++++--------- yapftests/reformatter_buganizer_test.py | 524 ++++++------- yapftests/reformatter_facebook_test.py | 80 +- yapftests/reformatter_pep8_test.py | 172 ++--- yapftests/reformatter_python3_test.py | 100 +-- yapftests/reformatter_style_config_test.py | 24 +- yapftests/reformatter_verify_test.py | 22 +- yapftests/subtype_assigner_test.py | 42 +- yapftests/yapf_test_helper.py | 12 +- 24 files changed, 1163 insertions(+), 1171 deletions(-) rename yapf/yapflib/{unwrapped_line.py => logical_line.py} (95%) rename yapftests/{unwrapped_line_test.py => logical_line_test.py} (63%) diff --git a/CHANGELOG b/CHANGELOG index 13e03a7d0..ba56ac20b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -15,6 +15,8 @@ - Use GitHub Actions instead of Travis for CI. - Clean up the FormatToken interface to limit how much it relies upon the pytree node object. +- Rename "unwrapped_line" module to "logical_line." +- Rename "UnwrappedLine" class to "LogicalLine." ### Fixed - Enable `BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF` knob for "pep8" style, so method definitions inside a class are surrounded by a single blank line as diff --git a/README.rst b/README.rst index 739acbd0e..12286a9dd 100644 --- a/README.rst +++ b/README.rst @@ -843,7 +843,7 @@ Knobs The penalty for characters over the column limit. ``SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT`` - The penalty incurred by adding a line split to the unwrapped line. The more + The penalty incurred by adding a line split to the logical line. The more line splits added the higher the penalty. ``SPLIT_PENALTY_IMPORT_NAMES`` @@ -962,15 +962,15 @@ Gory Details Algorithm Design ---------------- -The main data structure in YAPF is the ``UnwrappedLine`` object. It holds a list -of ``FormatToken``\s, that we would want to place on a single line if there were -no column limit. An exception being a comment in the middle of an expression -statement will force the line to be formatted on more than one line. The -formatter works on one ``UnwrappedLine`` object at a time. +The main data structure in YAPF is the ``LogicalLine`` object. It holds a list +of ``FormatToken``\s, that we would want to place on a single line if there +were no column limit. An exception being a comment in the middle of an +expression statement will force the line to be formatted on more than one line. +The formatter works on one ``LogicalLine`` object at a time. -An ``UnwrappedLine`` typically won't affect the formatting of lines before or +An ``LogicalLine`` typically won't affect the formatting of lines before or after it. There is a part of the algorithm that may join two or more -``UnwrappedLine``\s into one line. For instance, an if-then statement with a +``LogicalLine``\s into one line. For instance, an if-then statement with a short body can be placed on a single line: .. code-block:: python diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index be5770c5d..74d086175 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -27,22 +27,22 @@ """ from yapf.yapflib import format_token +from yapf.yapflib import logical_line from yapf.yapflib import object_state from yapf.yapflib import split_penalty from yapf.yapflib import style from yapf.yapflib import subtypes -from yapf.yapflib import unwrapped_line class FormatDecisionState(object): - """The current state when indenting an unwrapped line. + """The current state when indenting a logical line. The FormatDecisionState object is meant to be copied instead of referenced. Attributes: first_indent: The indent of the first token. column: The number of used columns in the current line. - line: The unwrapped line we're currently processing. + line: The logical line we're currently processing. next_token: The next token to be formatted. paren_level: The level of nesting inside (), [], and {}. lowest_level_on_line: The lowest paren_level on the current line. @@ -64,7 +64,7 @@ def __init__(self, line, first_indent): 'first_indent'. Arguments: - line: (UnwrappedLine) The unwrapped line we're currently processing. + line: (LogicalLine) The logical line we're currently processing. first_indent: (int) The indent of the first token. """ self.next_token = line.first @@ -234,7 +234,7 @@ def MustSplit(self): return False if (not _IsLastScopeInLine(bracket) or - unwrapped_line.IsSurroundedByBrackets(bracket)): + logical_line.IsSurroundedByBrackets(bracket)): last_token = bracket.matching_bracket else: last_token = _LastTokenInLine(bracket.matching_bracket) @@ -268,7 +268,7 @@ def SurroundedByParens(token): return False if (previous.value == '(' and not previous.is_pseudo and - not unwrapped_line.IsSurroundedByBrackets(previous)): + not logical_line.IsSurroundedByBrackets(previous)): pptoken = previous.previous_token if (pptoken and not pptoken.is_name and not pptoken.is_keyword and SurroundedByParens(current)): @@ -300,7 +300,7 @@ def SurroundedByParens(token): tok = tok.next_token func_call_or_string_format = tok and tok.value == '%' if func_call_or_string_format: - open_bracket = unwrapped_line.IsSurroundedByBrackets(current) + open_bracket = logical_line.IsSurroundedByBrackets(current) if open_bracket: if open_bracket.value in '[{': if not self._FitsOnLine(open_bracket, @@ -314,7 +314,7 @@ def SurroundedByParens(token): subtypes.DICTIONARY_KEY not in current.next_token.subtypes): # If we have a list of tuples, then we can get a similar look as above. If # the full list cannot fit on the line, then we want a split. - open_bracket = unwrapped_line.IsSurroundedByBrackets(current) + open_bracket = logical_line.IsSurroundedByBrackets(current) if (open_bracket and open_bracket.value in '[{' and subtypes.SUBSCRIPT_BRACKET not in open_bracket.subtypes): if not self._FitsOnLine(current, current.matching_bracket): @@ -382,7 +382,7 @@ def SurroundedByParens(token): # b=1, # c=2) if (self._FitsOnLine(previous, previous.matching_bracket) and - unwrapped_line.IsSurroundedByBrackets(previous)): + logical_line.IsSurroundedByBrackets(previous)): # An argument to a function is a function call with named # assigns. return False @@ -551,7 +551,7 @@ def SurroundedByParens(token): if (current.is_comment and previous.lineno < current.lineno - current.value.count('\n')): - # If a comment comes in the middle of an unwrapped line (like an if + # If a comment comes in the middle of a logical line (like an if # conditional with comments interspersed), then we want to split if the # original comments were on a separate line. return True @@ -1088,14 +1088,7 @@ def _ArgumentListHasDictionaryEntry(self, token): return False def _ContainerFitsOnStartLine(self, opening): - """Check if the container can fit on its starting line. - - Arguments: - opening: (FormatToken) The unwrapped line we're currently processing. - - Returns: - True if the container fits on the start line. - """ + """Check if the container can fit on its starting line.""" return (opening.matching_bracket.total_length - opening.total_length + self.stack[-1].indent) <= self.column_limit @@ -1128,7 +1121,7 @@ def _IsFunctionCallWithArguments(token): def _IsArgumentToFunction(token): - bracket = unwrapped_line.IsSurroundedByBrackets(token) + bracket = logical_line.IsSurroundedByBrackets(token) if not bracket or bracket.value != '(': return False previous = bracket.previous_token diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 42eeaa521..487f3a948 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -55,10 +55,10 @@ class FormatToken(object): Attributes: node: The PyTree node this token represents. - next_token: The token in the unwrapped line after this token or None if this - is the last token in the unwrapped line. - previous_token: The token in the unwrapped line before this token or None if - this is the first token in the unwrapped line. + next_token: The token in the logical line after this token or None if this + is the last token in the logical line. + previous_token: The token in the logical line before this token or None if + this is the first token in the logical line. matching_bracket: If a bracket token ('[', '{', or '(') the matching bracket. parameters: If this and its following tokens make up a parameter list, then @@ -74,7 +74,7 @@ class FormatToken(object): formatter won't place n spaces before all comments. Only those that are moved to the end of a line of code. The formatter may use different spacing when appropriate. - total_length: The total length of the unwrapped line up to and including + total_length: The total length of the logical line up to and including whitespace and this token. However, this doesn't include the initial indentation amount. split_penalty: The penalty for splitting the line before this token. diff --git a/yapf/yapflib/line_joiner.py b/yapf/yapflib/line_joiner.py index 84346c268..f0acd2f37 100644 --- a/yapf/yapflib/line_joiner.py +++ b/yapf/yapflib/line_joiner.py @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -"""Join unwrapped lines together. +"""Join logical lines together. Determine how many lines can be joined into one line. For instance, we could join these statements into one line: @@ -43,8 +43,8 @@ def CanMergeMultipleLines(lines, last_was_merged=False): """Determine if multiple lines can be joined into one. Arguments: - lines: (list of UnwrappedLine) This is a splice of UnwrappedLines from the - full code base. + lines: (list of LogicalLine) This is a splice of LogicalLines from the full + code base. last_was_merged: (bool) The last line was merged. Returns: @@ -91,7 +91,7 @@ def _CanMergeLineIntoIfStatement(lines, limit): 'continue', and 'break'. Arguments: - lines: (list of UnwrappedLine) The lines we are wanting to merge. + lines: (list of LogicalLine) The lines we are wanting to merge. limit: (int) The amount of space remaining on the line. Returns: diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/logical_line.py similarity index 95% rename from yapf/yapflib/unwrapped_line.py rename to yapf/yapflib/logical_line.py index 3b480a0eb..5723440d8 100644 --- a/yapf/yapflib/unwrapped_line.py +++ b/yapf/yapflib/logical_line.py @@ -11,12 +11,12 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -"""UnwrappedLine primitive for formatting. +"""LogicalLine primitive for formatting. -An unwrapped line is the containing data structure produced by the parser. It -collects all nodes (stored in FormatToken objects) that could appear on a -single line if there were no line length restrictions. It's then used by the -parser to perform the wrapping required to comply with the style guide. +A logical line is the containing data structure produced by the parser. It +collects all nodes (stored in FormatToken objects) that could appear on a single +line if there were no line length restrictions. It's then used by the parser to +perform the wrapping required to comply with the style guide. """ from yapf.yapflib import format_token @@ -29,8 +29,8 @@ from lib2to3.fixer_util import syms as python_symbols -class UnwrappedLine(object): - """Represents a single unwrapped line in the output. +class LogicalLine(object): + """Represents a single logical line in the output. Attributes: depth: indentation depth of this line. This is just a numeric value used to @@ -41,7 +41,7 @@ class UnwrappedLine(object): def __init__(self, depth, tokens=None): """Constructor. - Creates a new unwrapped line with the given depth an initial list of tokens. + Creates a new logical line with the given depth an initial list of tokens. Constructs the doubly-linked lists for format tokens using their built-in next_token and previous_token attributes. @@ -63,7 +63,7 @@ def __init__(self, depth, tokens=None): def CalculateFormattingInformation(self): """Calculate the split penalty and total length for the tokens.""" # Say that the first token in the line should have a space before it. This - # means only that if this unwrapped line is joined with a predecessor line, + # means only that if this logical line is joined with a predecessor line, # then there will be a space between them. self.first.spaces_required_before = 1 self.first.total_length = len(self.first.value) @@ -106,23 +106,23 @@ def Split(self): if not self.has_semicolon or self.disable: return [self] - uwlines = [] - uwline = UnwrappedLine(self.depth) + llines = [] + lline = LogicalLine(self.depth) for tok in self._tokens: if tok.value == ';': - uwlines.append(uwline) - uwline = UnwrappedLine(self.depth) + llines.append(lline) + lline = LogicalLine(self.depth) else: - uwline.AppendToken(tok) + lline.AppendToken(tok) - if uwline.tokens: - uwlines.append(uwline) + if lline.tokens: + llines.append(lline) - for uwline in uwlines: - uwline.first.previous_token = None - uwline.last.next_token = None + for lline in llines: + lline.first.previous_token = None + lline.last.next_token = None - return uwlines + return llines ############################################################################ # Token Access and Manipulation Methods # @@ -184,7 +184,7 @@ def __str__(self): # pragma: no cover def __repr__(self): # pragma: no cover tokens_repr = ','.join( '{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens) - return 'UnwrappedLine(depth={0}, tokens=[{1}])'.format( + return 'LogicalLine(depth={0}, tokens=[{1}])'.format( self.depth, tokens_repr) ############################################################################ @@ -204,10 +204,10 @@ def tokens(self): @property def lineno(self): - """Return the line number of this unwrapped line. + """Return the line number of this logical line. Returns: - The line number of the first token in this unwrapped line. + The line number of the first token in this logical line. """ return self.first.lineno diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index 15d9dd7c8..1b05b0ee2 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -11,13 +11,13 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -"""PyTreeUnwrapper - produces a list of unwrapped lines from a pytree. +"""PyTreeUnwrapper - produces a list of logical lines from a pytree. -[for a description of what an unwrapped line is, see unwrapped_line.py] +[for a description of what a logical line is, see logical_line.py] This is a pytree visitor that goes over a parse tree and produces a list of -UnwrappedLine containers from it, each with its own depth and containing all -the tokens that could fit on the line if there were no maximal line-length +LogicalLine containers from it, each with its own depth and containing all the +tokens that could fit on the line if there were no maximal line-length limitations. Note: a precondition to running this visitor and obtaining correct results is @@ -32,29 +32,29 @@ from lib2to3.pgen2 import token as grammar_token from yapf.yapflib import format_token +from yapf.yapflib import logical_line from yapf.yapflib import object_state from yapf.yapflib import pytree_utils from yapf.yapflib import pytree_visitor from yapf.yapflib import split_penalty from yapf.yapflib import style from yapf.yapflib import subtypes -from yapf.yapflib import unwrapped_line def UnwrapPyTree(tree): - """Create and return a list of unwrapped lines from the given pytree. + """Create and return a list of logical lines from the given pytree. Arguments: - tree: the top-level pytree node to unwrap. + tree: the top-level pytree node to unwrap.. Returns: - A list of UnwrappedLine objects. + A list of LogicalLine objects. """ unwrapper = PyTreeUnwrapper() unwrapper.Visit(tree) - uwlines = unwrapper.GetUnwrappedLines() - uwlines.sort(key=lambda x: x.lineno) - return uwlines + llines = unwrapper.GetLogicalLines() + llines.sort(key=lambda x: x.lineno) + return llines # Grammar tokens considered as whitespace for the purpose of unwrapping. @@ -80,40 +80,40 @@ class PyTreeUnwrapper(pytree_visitor.PyTreeVisitor): """ def __init__(self): - # A list of all unwrapped lines finished visiting so far. - self._unwrapped_lines = [] + # A list of all logical lines finished visiting so far. + self._logical_lines = [] - # Builds up a "current" unwrapped line while visiting pytree nodes. Some - # nodes will finish a line and start a new one. - self._cur_unwrapped_line = unwrapped_line.UnwrappedLine(0) + # Builds up a "current" logical line while visiting pytree nodes. Some nodes + # will finish a line and start a new one. + self._cur_logical_line = logical_line.LogicalLine(0) # Current indentation depth. self._cur_depth = 0 - def GetUnwrappedLines(self): + def GetLogicalLines(self): """Fetch the result of the tree walk. Note: only call this after visiting the whole tree. Returns: - A list of UnwrappedLine objects. + A list of LogicalLine objects. """ # Make sure the last line that was being populated is flushed. self._StartNewLine() - return self._unwrapped_lines + return self._logical_lines def _StartNewLine(self): """Finish current line and start a new one. - Place the currently accumulated line into the _unwrapped_lines list and + Place the currently accumulated line into the _logical_lines list and start a new one. """ - if self._cur_unwrapped_line.tokens: - self._unwrapped_lines.append(self._cur_unwrapped_line) - _MatchBrackets(self._cur_unwrapped_line) - _IdentifyParameterLists(self._cur_unwrapped_line) - _AdjustSplitPenalty(self._cur_unwrapped_line) - self._cur_unwrapped_line = unwrapped_line.UnwrappedLine(self._cur_depth) + if self._cur_logical_line.tokens: + self._logical_lines.append(self._cur_logical_line) + _MatchBrackets(self._cur_logical_line) + _IdentifyParameterLists(self._cur_logical_line) + _AdjustSplitPenalty(self._cur_logical_line) + self._cur_logical_line = logical_line.LogicalLine(self._cur_depth) _STMT_TYPES = frozenset({ 'if_stmt', @@ -152,7 +152,7 @@ def _VisitCompoundStatement(self, node, substatement_names): """Helper for visiting compound statements. Python compound statements serve as containers for other statements. Thus, - when we encounter a new compound statement we start a new unwrapped line. + when we encounter a new compound statement, we start a new logical line. Arguments: node: the node to visit. @@ -285,7 +285,7 @@ def Visit_typedargslist(self, node): # pylint: disable=invalid-name def DefaultLeafVisit(self, leaf): """Default visitor for tree leaves. - A tree leaf is always just gets appended to the current unwrapped line. + A tree leaf is always just gets appended to the current logical line. Arguments: leaf: the leaf to visit. @@ -294,13 +294,13 @@ def DefaultLeafVisit(self, leaf): self._StartNewLine() elif leaf.type != grammar_token.COMMENT or leaf.value.strip(): # Add non-whitespace tokens and comments that aren't empty. - self._cur_unwrapped_line.AppendNode(leaf) + self._cur_logical_line.AppendNode(leaf) _BRACKET_MATCH = {')': '(', '}': '{', ']': '['} -def _MatchBrackets(uwline): +def _MatchBrackets(line): """Visit the node and match the brackets. For every open bracket ('[', '{', or '('), find the associated closing bracket @@ -308,10 +308,10 @@ def _MatchBrackets(uwline): or close bracket. Arguments: - uwline: (UnwrappedLine) An unwrapped line. + line: (LogicalLine) A logical line. """ bracket_stack = [] - for token in uwline.tokens: + for token in line.tokens: if token.value in pytree_utils.OPENING_BRACKETS: bracket_stack.append(token) elif token.value in pytree_utils.CLOSING_BRACKETS: @@ -325,18 +325,18 @@ def _MatchBrackets(uwline): token.container_opening = bracket -def _IdentifyParameterLists(uwline): +def _IdentifyParameterLists(line): """Visit the node to create a state for parameter lists. For instance, a parameter is considered an "object" with its first and last token uniquely identifying the object. Arguments: - uwline: (UnwrappedLine) An unwrapped line. + line: (LogicalLine) A logical line. """ func_stack = [] param_stack = [] - for tok in uwline.tokens: + for tok in line.tokens: # Identify parameter list objects. if subtypes.FUNC_DEF in tok.subtypes: assert tok.next_token.value == '(' @@ -358,17 +358,17 @@ def _IdentifyParameterLists(uwline): func_stack[-1].parameters.append(object_state.Parameter(start, tok)) -def _AdjustSplitPenalty(uwline): +def _AdjustSplitPenalty(line): """Visit the node and adjust the split penalties if needed. A token shouldn't be split if it's not within a bracket pair. Mark any token that's not within a bracket pair as "unbreakable". Arguments: - uwline: (UnwrappedLine) An unwrapped line. + line: (LogicalLine) An logical line. """ bracket_level = 0 - for index, token in enumerate(uwline.tokens): + for index, token in enumerate(line.tokens): if index and not bracket_level: pytree_utils.SetNodeAnnotation(token.node, pytree_utils.Annotation.SPLIT_PENALTY, diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index a61d46354..724289484 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -13,9 +13,8 @@ # limitations under the License. """Decide what the format for the code should be. -The `unwrapped_line.UnwrappedLine`s are now ready to be formatted. -UnwrappedLines that can be merged together are. The best formatting is returned -as a string. +The `logical_line.LogicalLine`s are now ready to be formatted. LogicalLInes that +can be merged together are. The best formatting is returned as a string. Reformat(): the main function exported by this module. """ @@ -36,11 +35,11 @@ from yapf.yapflib import verifier -def Reformat(uwlines, verify=False, lines=None): - """Reformat the unwrapped lines. +def Reformat(llines, verify=False, lines=None): + """Reformat the logical lines. Arguments: - uwlines: (list of unwrapped_line.UnwrappedLine) Lines we want to format. + llines: (list of logical_line.LogicalLine) Lines we want to format. verify: (bool) True if reformatted code should be verified for syntax. lines: (set of int) The lines which can be modified or None if there is no line range restriction. @@ -49,81 +48,81 @@ def Reformat(uwlines, verify=False, lines=None): A string representing the reformatted code. """ final_lines = [] - prev_uwline = None # The previous line. + prev_line = None # The previous line. indent_width = style.Get('INDENT_WIDTH') - for uwline in _SingleOrMergedLines(uwlines): - first_token = uwline.first - _FormatFirstToken(first_token, uwline.depth, prev_uwline, final_lines) + for lline in _SingleOrMergedLines(llines): + first_token = lline.first + _FormatFirstToken(first_token, lline.depth, prev_line, final_lines) - indent_amt = indent_width * uwline.depth - state = format_decision_state.FormatDecisionState(uwline, indent_amt) + indent_amt = indent_width * lline.depth + state = format_decision_state.FormatDecisionState(lline, indent_amt) state.MoveStateToNextToken() - if not uwline.disable: - if uwline.first.is_comment: - uwline.first.node.value = uwline.first.node.value.rstrip() - elif uwline.last.is_comment: - uwline.last.node.value = uwline.last.node.value.rstrip() - if prev_uwline and prev_uwline.disable: + if not lline.disable: + if lline.first.is_comment: + lline.first.node.value = lline.first.node.value.rstrip() + elif lline.last.is_comment: + lline.last.node.value = lline.last.node.value.rstrip() + if prev_line and prev_line.disable: # Keep the vertical spacing between a disabled and enabled formatting # region. - _RetainRequiredVerticalSpacingBetweenTokens(uwline.first, - prev_uwline.last, lines) - if any(tok.is_comment for tok in uwline.tokens): - _RetainVerticalSpacingBeforeComments(uwline) - - if uwline.disable or _LineHasContinuationMarkers(uwline): - _RetainHorizontalSpacing(uwline) - _RetainRequiredVerticalSpacing(uwline, prev_uwline, lines) + _RetainRequiredVerticalSpacingBetweenTokens(lline.first, + prev_line.last, lines) + if any(tok.is_comment for tok in lline.tokens): + _RetainVerticalSpacingBeforeComments(lline) + + if lline.disable or _LineHasContinuationMarkers(lline): + _RetainHorizontalSpacing(lline) + _RetainRequiredVerticalSpacing(lline, prev_line, lines) _EmitLineUnformatted(state) - elif (_LineContainsPylintDisableLineTooLong(uwline) or - _LineContainsI18n(uwline)): + elif (_LineContainsPylintDisableLineTooLong(lline) or + _LineContainsI18n(lline)): # Don't modify vertical spacing, but fix any horizontal spacing issues. - _RetainRequiredVerticalSpacing(uwline, prev_uwline, lines) + _RetainRequiredVerticalSpacing(lline, prev_line, lines) _EmitLineUnformatted(state) - elif _CanPlaceOnSingleLine(uwline) and not any(tok.must_break_before - for tok in uwline.tokens): - # The unwrapped line fits on one line. + elif _CanPlaceOnSingleLine(lline) and not any(tok.must_break_before + for tok in lline.tokens): + # The logical line fits on one line. while state.next_token: state.AddTokenToState(newline=False, dry_run=False) elif not _AnalyzeSolutionSpace(state): # Failsafe mode. If there isn't a solution to the line, then just emit # it as is. - state = format_decision_state.FormatDecisionState(uwline, indent_amt) + state = format_decision_state.FormatDecisionState(lline, indent_amt) state.MoveStateToNextToken() - _RetainHorizontalSpacing(uwline) - _RetainRequiredVerticalSpacing(uwline, prev_uwline, None) + _RetainHorizontalSpacing(lline) + _RetainRequiredVerticalSpacing(lline, prev_line, None) _EmitLineUnformatted(state) - final_lines.append(uwline) - prev_uwline = uwline + final_lines.append(lline) + prev_line = lline _AlignTrailingComments(final_lines) return _FormatFinalLines(final_lines, verify) -def _RetainHorizontalSpacing(uwline): +def _RetainHorizontalSpacing(line): """Retain all horizontal spacing between tokens.""" - for tok in uwline.tokens: - tok.RetainHorizontalSpacing(uwline.first.column, uwline.depth) + for tok in line.tokens: + tok.RetainHorizontalSpacing(line.first.column, line.depth) -def _RetainRequiredVerticalSpacing(cur_uwline, prev_uwline, lines): +def _RetainRequiredVerticalSpacing(cur_line, prev_line, lines): """Retain all vertical spacing between lines.""" prev_tok = None - if prev_uwline is not None: - prev_tok = prev_uwline.last + if prev_line is not None: + prev_tok = prev_line.last - if cur_uwline.disable: + if cur_line.disable: # After the first token we are acting on a single line. So if it is # disabled we must not reformat. lines = set() - for cur_tok in cur_uwline.tokens: + for cur_tok in cur_line.tokens: _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines) prev_tok = cur_tok @@ -165,10 +164,10 @@ def _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines): cur_tok.AdjustNewlinesBefore(required_newlines) -def _RetainVerticalSpacingBeforeComments(uwline): +def _RetainVerticalSpacingBeforeComments(line): """Retain vertical spacing before comments.""" prev_token = None - for tok in uwline.tokens: + for tok in line.tokens: if tok.is_comment and prev_token: if tok.lineno - tok.value.count('\n') - prev_token.lineno > 1: tok.AdjustNewlinesBefore(ONE_BLANK_LINE) @@ -203,57 +202,57 @@ def _EmitLineUnformatted(state): state.AddTokenToState(newline=newline, dry_run=False) -def _LineContainsI18n(uwline): +def _LineContainsI18n(line): """Return true if there are i18n comments or function calls in the line. I18n comments and pseudo-function calls are closely related. They cannot be moved apart without breaking i18n. Arguments: - uwline: (unwrapped_line.UnwrappedLine) The line currently being formatted. + line: (logical_line.LogicalLine) The line currently being formatted. Returns: True if the line contains i18n comments or function calls. False otherwise. """ if style.Get('I18N_COMMENT'): - for tok in uwline.tokens: + for tok in line.tokens: if tok.is_comment and re.match(style.Get('I18N_COMMENT'), tok.value): # Contains an i18n comment. return True if style.Get('I18N_FUNCTION_CALL'): - length = len(uwline.tokens) + length = len(line.tokens) for index in range(length - 1): - if (uwline.tokens[index + 1].value == '(' and - uwline.tokens[index].value in style.Get('I18N_FUNCTION_CALL')): + if (line.tokens[index + 1].value == '(' and + line.tokens[index].value in style.Get('I18N_FUNCTION_CALL')): return True return False -def _LineContainsPylintDisableLineTooLong(uwline): +def _LineContainsPylintDisableLineTooLong(line): """Return true if there is a "pylint: disable=line-too-long" comment.""" - return re.search(r'\bpylint:\s+disable=line-too-long\b', uwline.last.value) + return re.search(r'\bpylint:\s+disable=line-too-long\b', line.last.value) -def _LineHasContinuationMarkers(uwline): +def _LineHasContinuationMarkers(line): """Return true if the line has continuation markers in it.""" - return any(tok.is_continuation for tok in uwline.tokens) + return any(tok.is_continuation for tok in line.tokens) -def _CanPlaceOnSingleLine(uwline): - """Determine if the unwrapped line can go on a single line. +def _CanPlaceOnSingleLine(line): + """Determine if the logical line can go on a single line. Arguments: - uwline: (unwrapped_line.UnwrappedLine) The line currently being formatted. + line: (logical_line.LogicalLine) The line currently being formatted. Returns: True if the line can or should be added to a single line. False otherwise. """ - token_names = [x.name for x in uwline.tokens] + token_names = [x.name for x in line.tokens] if (style.Get('FORCE_MULTILINE_DICT') and 'LBRACE' in token_names): return False - indent_amt = style.Get('INDENT_WIDTH') * uwline.depth - last = uwline.last + indent_amt = style.Get('INDENT_WIDTH') * line.depth + last = line.last last_index = -1 if (last.is_pylint_comment or last.is_pytype_comment or last.is_copybara_comment): @@ -262,7 +261,7 @@ def _CanPlaceOnSingleLine(uwline): if last is None: return True return (last.total_length + indent_amt <= style.Get('COLUMN_LIMIT') and - not any(tok.is_comment for tok in uwline.tokens[:last_index])) + not any(tok.is_comment for tok in line.tokens[:last_index])) def _AlignTrailingComments(final_lines): @@ -305,7 +304,7 @@ def _AlignTrailingComments(final_lines): all_pc_line_lengths.append([]) continue - # Calculate the length of each line in this unwrapped line. + # Calculate the length of each line in this logical line. line_content = '' pc_line_lengths = [] @@ -561,20 +560,19 @@ def _ReconstructPath(initial_state, current): NESTED_DEPTH = [] -def _FormatFirstToken(first_token, indent_depth, prev_uwline, final_lines): - """Format the first token in the unwrapped line. +def _FormatFirstToken(first_token, indent_depth, prev_line, final_lines): + """Format the first token in the logical line. - Add a newline and the required indent before the first token of the unwrapped + Add a newline and the required indent before the first token of the logical line. Arguments: - first_token: (format_token.FormatToken) The first token in the unwrapped - line. + first_token: (format_token.FormatToken) The first token in the logical line. indent_depth: (int) The line's indentation depth. - prev_uwline: (list of unwrapped_line.UnwrappedLine) The unwrapped line - previous to this line. - final_lines: (list of unwrapped_line.UnwrappedLine) The unwrapped lines - that have already been processed. + prev_line: (list of logical_line.LogicalLine) The logical line previous to + this line. + final_lines: (list of logical_line.LogicalLine) The logical lines that have + already been processed. """ global NESTED_DEPTH while NESTED_DEPTH and NESTED_DEPTH[-1] > indent_depth: @@ -589,7 +587,7 @@ def _FormatFirstToken(first_token, indent_depth, prev_uwline, final_lines): NESTED_DEPTH.append(indent_depth) first_token.AddWhitespacePrefix( - _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, + _CalculateNumberOfNewlines(first_token, indent_depth, prev_line, final_lines, first_nested), indent_level=indent_depth) @@ -606,18 +604,18 @@ def _IsClassOrDef(tok): tok.next_token.value == 'def') -def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, +def _CalculateNumberOfNewlines(first_token, indent_depth, prev_line, final_lines, first_nested): """Calculate the number of newlines we need to add. Arguments: - first_token: (format_token.FormatToken) The first token in the unwrapped + first_token: (format_token.FormatToken) The first token in the logical line. indent_depth: (int) The line's indentation depth. - prev_uwline: (list of unwrapped_line.UnwrappedLine) The unwrapped line - previous to this line. - final_lines: (list of unwrapped_line.UnwrappedLine) The unwrapped lines - that have already been processed. + prev_line: (list of logical_line.LogicalLine) The logical line previous to + this line. + final_lines: (list of logical_line.LogicalLine) The logical lines that have + already been processed. first_nested: (boolean) Whether this is the first nested class or function. Returns: @@ -625,7 +623,7 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, """ # TODO(morbo): Special handling for imports. # TODO(morbo): Create a knob that can tune these. - if prev_uwline is None: + if prev_line is None: # The first line in the file. Don't add blank lines. # FIXME(morbo): Is this correct? if first_token.newlines is not None: @@ -633,11 +631,11 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, return 0 if first_token.is_docstring: - if (prev_uwline.first.value == 'class' and + if (prev_line.first.value == 'class' and style.Get('BLANK_LINE_BEFORE_CLASS_DOCSTRING')): # Enforce a blank line before a class's docstring. return ONE_BLANK_LINE - elif (prev_uwline.first.value.startswith('#') and + elif (prev_line.first.value.startswith('#') and style.Get('BLANK_LINE_BEFORE_MODULE_DOCSTRING')): # Enforce a blank line before a module's docstring. return ONE_BLANK_LINE @@ -645,13 +643,13 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, return NO_BLANK_LINES if first_token.is_name and not indent_depth: - if prev_uwline.first.value in {'from', 'import'}: + if prev_line.first.value in {'from', 'import'}: # Support custom number of blank lines between top-level imports and # variable definitions. return 1 + style.Get( 'BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES') - prev_last_token = prev_uwline.last + prev_last_token = prev_line.last if prev_last_token.is_docstring: if (not indent_depth and first_token.value in {'class', 'def', 'async'}): # Separate a class or function from the module-level docstring with @@ -674,7 +672,7 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, if not indent_depth: # This is a top-level class or function. is_inline_comment = prev_last_token.whitespace_prefix.count('\n') == 0 - if (not prev_uwline.disable and prev_last_token.is_comment and + if (not prev_line.disable and prev_last_token.is_comment and not is_inline_comment): # This token follows a non-inline comment. if _NoBlankLinesBeforeCurrentToken(prev_last_token.value, first_token, @@ -694,7 +692,7 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, if first_token.newlines is not None: first_token.newlines = None return NO_BLANK_LINES - elif _IsClassOrDef(prev_uwline.first): + elif _IsClassOrDef(prev_line.first): if first_nested and not style.Get( 'BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'): first_token.newlines = None @@ -717,11 +715,11 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline, return NO_BLANK_LINES -def _SingleOrMergedLines(uwlines): +def _SingleOrMergedLines(lines): """Generate the lines we want to format. Arguments: - uwlines: (list of unwrapped_line.UnwrappedLine) Lines we want to format. + lines: (list of logical_line.LogicalLine) Lines we want to format. Yields: Either a single line, if the current line cannot be merged with the @@ -729,38 +727,38 @@ def _SingleOrMergedLines(uwlines): """ index = 0 last_was_merged = False - while index < len(uwlines): - if uwlines[index].disable: - uwline = uwlines[index] + while index < len(lines): + if lines[index].disable: + line = lines[index] index += 1 - while index < len(uwlines): - column = uwline.last.column + 2 - if uwlines[index].lineno != uwline.lineno: + while index < len(lines): + column = line.last.column + 2 + if lines[index].lineno != line.lineno: break - if uwline.last.value != ':': + if line.last.value != ':': leaf = pytree.Leaf( - type=token.SEMI, value=';', context=('', (uwline.lineno, column))) - uwline.AppendToken(format_token.FormatToken(leaf)) - for tok in uwlines[index].tokens: - uwline.AppendToken(tok) + type=token.SEMI, value=';', context=('', (line.lineno, column))) + line.AppendToken(format_token.FormatToken(leaf)) + for tok in lines[index].tokens: + line.AppendToken(tok) index += 1 - yield uwline - elif line_joiner.CanMergeMultipleLines(uwlines[index:], last_was_merged): + yield line + elif line_joiner.CanMergeMultipleLines(lines[index:], last_was_merged): # TODO(morbo): This splice is potentially very slow. Come up with a more # performance-friendly way of determining if two lines can be merged. - next_uwline = uwlines[index + 1] - for tok in next_uwline.tokens: - uwlines[index].AppendToken(tok) - if (len(next_uwline.tokens) == 1 and - next_uwline.first.is_multiline_string): + next_line = lines[index + 1] + for tok in next_line.tokens: + lines[index].AppendToken(tok) + if (len(next_line.tokens) == 1 and + next_line.first.is_multiline_string): # This may be a multiline shebang. In that case, we want to retain the # formatting. Otherwise, it could mess up the shell script's syntax. - uwlines[index].disable = True - yield uwlines[index] + lines[index].disable = True + yield lines[index] index += 2 last_was_merged = True else: - yield uwlines[index] + yield lines[index] index += 1 last_was_merged = False @@ -777,9 +775,8 @@ def _NoBlankLinesBeforeCurrentToken(text, cur_token, prev_token): Arguments: text: (unicode) The text of the docstring or comment before the current token. - cur_token: (format_token.FormatToken) The current token in the unwrapped - line. - prev_token: (format_token.FormatToken) The previous token in the unwrapped + cur_token: (format_token.FormatToken) The current token in the logical line. + prev_token: (format_token.FormatToken) The previous token in the logical line. Returns: diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 40b23c4de..233a64e6b 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -392,7 +392,7 @@ def method(): SPLIT_PENALTY_EXCESS_CHARACTER=textwrap.dedent("""\ The penalty for characters over the column limit."""), SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=textwrap.dedent("""\ - The penalty incurred by adding a line split to the unwrapped line. The + The penalty incurred by adding a line split to the logical line. The more line splits added the higher the penalty."""), SPLIT_PENALTY_IMPORT_NAMES=textwrap.dedent("""\ The penalty of splitting a list of "import as" names. For example: diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 06c9a734e..09c31bcdb 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -142,13 +142,13 @@ def FormatTree(tree, style_config=None, lines=None, verify=False): split_penalty.ComputeSplitPenalties(tree) blank_line_calculator.CalculateBlankLines(tree) - uwlines = pytree_unwrapper.UnwrapPyTree(tree) - for uwl in uwlines: - uwl.CalculateFormattingInformation() + llines = pytree_unwrapper.UnwrapPyTree(tree) + for lline in llines: + lline.CalculateFormattingInformation() lines = _LineRangesToSet(lines) - _MarkLinesToFormat(uwlines, lines) - return reformatter.Reformat(_SplitSemicolons(uwlines), verify, lines) + _MarkLinesToFormat(llines, lines) + return reformatter.Reformat(_SplitSemicolons(llines), verify, lines) def FormatCode(unformatted_source, @@ -252,10 +252,10 @@ def ReadFile(filename, logger=None): raise -def _SplitSemicolons(uwlines): +def _SplitSemicolons(lines): res = [] - for uwline in uwlines: - res.extend(uwline.Split()) + for line in lines: + res.extend(line.Split()) return res @@ -276,23 +276,23 @@ def _LineRangesToSet(line_ranges): return line_set -def _MarkLinesToFormat(uwlines, lines): +def _MarkLinesToFormat(llines, lines): """Skip sections of code that we shouldn't reformat.""" if lines: - for uwline in uwlines: + for uwline in llines: uwline.disable = not lines.intersection( range(uwline.lineno, uwline.last.lineno + 1)) # Now go through the lines and disable any lines explicitly marked as # disabled. index = 0 - while index < len(uwlines): - uwline = uwlines[index] + while index < len(llines): + uwline = llines[index] if uwline.is_comment: if _DisableYAPF(uwline.first.value.strip()): index += 1 - while index < len(uwlines): - uwline = uwlines[index] + while index < len(llines): + uwline = llines[index] line = uwline.first.value.strip() if uwline.is_comment and _EnableYAPF(line): if not _DisableYAPF(line): diff --git a/yapftests/blank_line_calculator_test.py b/yapftests/blank_line_calculator_test.py index 80dc55c21..18fa83e0b 100644 --- a/yapftests/blank_line_calculator_test.py +++ b/yapftests/blank_line_calculator_test.py @@ -41,8 +41,8 @@ def foo(): def foo(): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testComplexDecorators(self): unformatted_code = textwrap.dedent("""\ @@ -77,8 +77,8 @@ class moo(object): def method(self): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testCodeAfterFunctionsAndClasses(self): unformatted_code = textwrap.dedent("""\ @@ -122,8 +122,8 @@ def method_2(self): except Error as error: pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testCommentSpacing(self): unformatted_code = textwrap.dedent("""\ @@ -188,8 +188,8 @@ def foo(self): # comment pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testCommentBeforeMethod(self): code = textwrap.dedent("""\ @@ -199,8 +199,8 @@ class foo(object): def f(self): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentsBeforeClassDefs(self): code = textwrap.dedent('''\ @@ -212,8 +212,8 @@ def testCommentsBeforeClassDefs(self): class Foo(object): pass ''') - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentsBeforeDecorator(self): code = textwrap.dedent("""\ @@ -222,8 +222,8 @@ def testCommentsBeforeDecorator(self): def a(): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) code = textwrap.dedent("""\ # Hello world @@ -233,8 +233,8 @@ def a(): def a(): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentsAfterDecorator(self): code = textwrap.dedent("""\ @@ -250,8 +250,8 @@ def _(): def test_unicode_filename_in_sdist(self, sdist_unicode, tmpdir, monkeypatch): pass """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testInnerClasses(self): unformatted_code = textwrap.dedent("""\ @@ -274,8 +274,8 @@ class TaskValidationError(Error): class DeployAPIHTTPError(Error): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testLinesOnRangeBoundary(self): unformatted_code = textwrap.dedent(u"""\ diff --git a/yapftests/format_decision_state_test.py b/yapftests/format_decision_state_test.py index 39e7e8e03..9d6226738 100644 --- a/yapftests/format_decision_state_test.py +++ b/yapftests/format_decision_state_test.py @@ -17,9 +17,9 @@ import unittest from yapf.yapflib import format_decision_state +from yapf.yapflib import logical_line from yapf.yapflib import pytree_utils from yapf.yapflib import style -from yapf.yapflib import unwrapped_line from yapftests import yapf_test_helper @@ -35,12 +35,12 @@ def testSimpleFunctionDefWithNoSplitting(self): def f(a, b): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - uwline = unwrapped_line.UnwrappedLine(0, _FilterLine(uwlines[0])) - uwline.CalculateFormattingInformation() + llines = yapf_test_helper.ParseAndUnwrap(code) + lline = logical_line.LogicalLine(0, _FilterLine(llines[0])) + lline.CalculateFormattingInformation() # Add: 'f' - state = format_decision_state.FormatDecisionState(uwline, 0) + state = format_decision_state.FormatDecisionState(lline, 0) state.MoveStateToNextToken() self.assertEqual('f', state.next_token.value) self.assertFalse(state.CanSplit(False)) @@ -89,12 +89,12 @@ def testSimpleFunctionDefWithSplitting(self): def f(a, b): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - uwline = unwrapped_line.UnwrappedLine(0, _FilterLine(uwlines[0])) - uwline.CalculateFormattingInformation() + llines = yapf_test_helper.ParseAndUnwrap(code) + lline = logical_line.LogicalLine(0, _FilterLine(llines[0])) + lline.CalculateFormattingInformation() # Add: 'f' - state = format_decision_state.FormatDecisionState(uwline, 0) + state = format_decision_state.FormatDecisionState(lline, 0) state.MoveStateToNextToken() self.assertEqual('f', state.next_token.value) self.assertFalse(state.CanSplit(False)) @@ -133,10 +133,10 @@ def f(a, b): self.assertEqual(repr(state), repr(clone)) -def _FilterLine(uwline): - """Filter out nonsemantic tokens from the UnwrappedLines.""" +def _FilterLine(lline): + """Filter out nonsemantic tokens from the LogicalLines.""" return [ - ft for ft in uwline.tokens + ft for ft in lline.tokens if ft.name not in pytree_utils.NONSEMANTIC_TOKENS ] diff --git a/yapftests/line_joiner_test.py b/yapftests/line_joiner_test.py index 67252a23c..2eaf16478 100644 --- a/yapftests/line_joiner_test.py +++ b/yapftests/line_joiner_test.py @@ -29,14 +29,14 @@ def setUpClass(cls): style.SetGlobalStyle(style.CreatePEP8Style()) def _CheckLineJoining(self, code, join_lines): - """Check that the given UnwrappedLines are joined as expected. + """Check that the given LogicalLines are joined as expected. Arguments: code: The code to check to see if we can join it. join_lines: True if we expect the lines to be joined. """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(line_joiner.CanMergeMultipleLines(uwlines), join_lines) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(line_joiner.CanMergeMultipleLines(llines), join_lines) def testSimpleSingleLineStatement(self): code = textwrap.dedent(u"""\ diff --git a/yapftests/unwrapped_line_test.py b/yapftests/logical_line_test.py similarity index 63% rename from yapftests/unwrapped_line_test.py rename to yapftests/logical_line_test.py index 90be1a13a..6876efe0f 100644 --- a/yapftests/unwrapped_line_test.py +++ b/yapftests/logical_line_test.py @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -"""Tests for yapf.unwrapped_line.""" +"""Tests for yapf.logical_line.""" import textwrap import unittest @@ -20,62 +20,62 @@ from lib2to3.pgen2 import token from yapf.yapflib import format_token +from yapf.yapflib import logical_line from yapf.yapflib import split_penalty -from yapf.yapflib import unwrapped_line from yapftests import yapf_test_helper -class UnwrappedLineBasicTest(unittest.TestCase): +class LogicalLineBasicTest(unittest.TestCase): def testConstruction(self): toks = _MakeFormatTokenList([(token.DOT, '.'), (token.VBAR, '|')]) - uwl = unwrapped_line.UnwrappedLine(20, toks) - self.assertEqual(20, uwl.depth) - self.assertEqual(['DOT', 'VBAR'], [tok.name for tok in uwl.tokens]) + lline = logical_line.LogicalLine(20, toks) + self.assertEqual(20, lline.depth) + self.assertEqual(['DOT', 'VBAR'], [tok.name for tok in lline.tokens]) def testFirstLast(self): toks = _MakeFormatTokenList([(token.DOT, '.'), (token.LPAR, '('), (token.VBAR, '|')]) - uwl = unwrapped_line.UnwrappedLine(20, toks) - self.assertEqual(20, uwl.depth) - self.assertEqual('DOT', uwl.first.name) - self.assertEqual('VBAR', uwl.last.name) + lline = logical_line.LogicalLine(20, toks) + self.assertEqual(20, lline.depth) + self.assertEqual('DOT', lline.first.name) + self.assertEqual('VBAR', lline.last.name) def testAsCode(self): toks = _MakeFormatTokenList([(token.DOT, '.'), (token.LPAR, '('), (token.VBAR, '|')]) - uwl = unwrapped_line.UnwrappedLine(2, toks) - self.assertEqual(' . ( |', uwl.AsCode()) + lline = logical_line.LogicalLine(2, toks) + self.assertEqual(' . ( |', lline.AsCode()) def testAppendToken(self): - uwl = unwrapped_line.UnwrappedLine(0) - uwl.AppendToken(_MakeFormatTokenLeaf(token.LPAR, '(')) - uwl.AppendToken(_MakeFormatTokenLeaf(token.RPAR, ')')) - self.assertEqual(['LPAR', 'RPAR'], [tok.name for tok in uwl.tokens]) + lline = logical_line.LogicalLine(0) + lline.AppendToken(_MakeFormatTokenLeaf(token.LPAR, '(')) + lline.AppendToken(_MakeFormatTokenLeaf(token.RPAR, ')')) + self.assertEqual(['LPAR', 'RPAR'], [tok.name for tok in lline.tokens]) def testAppendNode(self): - uwl = unwrapped_line.UnwrappedLine(0) - uwl.AppendNode(pytree.Leaf(token.LPAR, '(')) - uwl.AppendNode(pytree.Leaf(token.RPAR, ')')) - self.assertEqual(['LPAR', 'RPAR'], [tok.name for tok in uwl.tokens]) + lline = logical_line.LogicalLine(0) + lline.AppendNode(pytree.Leaf(token.LPAR, '(')) + lline.AppendNode(pytree.Leaf(token.RPAR, ')')) + self.assertEqual(['LPAR', 'RPAR'], [tok.name for tok in lline.tokens]) -class UnwrappedLineFormattingInformationTest(yapf_test_helper.YAPFTest): +class LogicalLineFormattingInformationTest(yapf_test_helper.YAPFTest): def testFuncDef(self): code = textwrap.dedent(r""" def f(a, b): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) + llines = yapf_test_helper.ParseAndUnwrap(code) - f = uwlines[0].tokens[1] + f = llines[0].tokens[1] self.assertFalse(f.can_break_before) self.assertFalse(f.must_break_before) self.assertEqual(f.split_penalty, split_penalty.UNBREAKABLE) - lparen = uwlines[0].tokens[2] + lparen = llines[0].tokens[2] self.assertFalse(lparen.can_break_before) self.assertFalse(lparen.must_break_before) self.assertEqual(lparen.split_penalty, split_penalty.UNBREAKABLE) diff --git a/yapftests/pytree_unwrapper_test.py b/yapftests/pytree_unwrapper_test.py index f95f3666c..b6ab80977 100644 --- a/yapftests/pytree_unwrapper_test.py +++ b/yapftests/pytree_unwrapper_test.py @@ -23,22 +23,22 @@ class PytreeUnwrapperTest(yapf_test_helper.YAPFTest): - def _CheckUnwrappedLines(self, uwlines, list_of_expected): - """Check that the given UnwrappedLines match expectations. + def _CheckLogicalLines(self, llines, list_of_expected): + """Check that the given LogicalLines match expectations. Args: - uwlines: list of UnwrappedLine + llines: list of LogicalLine list_of_expected: list of (depth, values) pairs. Non-semantic tokens are filtered out from the expected values. """ actual = [] - for uwl in uwlines: + for lline in llines: filtered_values = [ ft.value - for ft in uwl.tokens + for ft in lline.tokens if ft.name not in pytree_utils.NONSEMANTIC_TOKENS ] - actual.append((uwl.depth, filtered_values)) + actual.append((lline.depth, filtered_values)) self.assertEqual(list_of_expected, actual) @@ -48,8 +48,8 @@ def testSimpleFileScope(self): # a comment y = 2 """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckUnwrappedLines(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckLogicalLines(llines, [ (0, ['x', '=', '1']), (0, ['# a comment']), (0, ['y', '=', '2']), @@ -60,8 +60,8 @@ def testSimpleMultilineStatement(self): y = (1 + x) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckUnwrappedLines(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckLogicalLines(llines, [ (0, ['y', '=', '(', '1', '+', 'x', ')']), ]) @@ -70,8 +70,8 @@ def testFileScopeWithInlineComment(self): x = 1 # a comment y = 2 """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckUnwrappedLines(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckLogicalLines(llines, [ (0, ['x', '=', '1', '# a comment']), (0, ['y', '=', '2']), ]) @@ -82,8 +82,8 @@ def testSimpleIf(self): x = 1 y = 2 """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckUnwrappedLines(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckLogicalLines(llines, [ (0, ['if', 'foo', ':']), (1, ['x', '=', '1']), (1, ['y', '=', '2']), @@ -96,8 +96,8 @@ def testSimpleIfWithComments(self): x = 1 y = 2 """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckUnwrappedLines(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckLogicalLines(llines, [ (0, ['# c1']), (0, ['if', 'foo', ':', '# c2']), (1, ['x', '=', '1']), @@ -112,8 +112,8 @@ def testIfWithCommentsInside(self): # c3 y = 2 """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckUnwrappedLines(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckLogicalLines(llines, [ (0, ['if', 'foo', ':']), (1, ['# c1']), (1, ['x', '=', '1', '# c2']), @@ -131,8 +131,8 @@ def testIfElifElse(self): # c3 z = 1 """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckUnwrappedLines(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckLogicalLines(llines, [ (0, ['if', 'x', ':']), (1, ['x', '=', '1', '# c1']), (0, ['elif', 'y', ':', '# c2']), @@ -151,8 +151,8 @@ def testNestedCompoundTwoLevel(self): j = 1 k = 1 """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckUnwrappedLines(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckLogicalLines(llines, [ (0, ['if', 'x', ':']), (1, ['x', '=', '1', '# c1']), (1, ['while', 't', ':']), @@ -167,8 +167,8 @@ def testSimpleWhile(self): # c2 x = 1 """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckUnwrappedLines(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckLogicalLines(llines, [ (0, ['while', 'x', '>', '1', ':', '# c1']), (1, ['# c2']), (1, ['x', '=', '1']), @@ -187,8 +187,8 @@ def testSimpleTry(self): finally: pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckUnwrappedLines(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckLogicalLines(llines, [ (0, ['try', ':']), (1, ['pass']), (0, ['except', ':']), @@ -207,8 +207,8 @@ def foo(x): # c1 # c2 return x """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckUnwrappedLines(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckLogicalLines(llines, [ (0, ['def', 'foo', '(', 'x', ')', ':', '# c1']), (1, ['# c2']), (1, ['return', 'x']), @@ -224,8 +224,8 @@ def bar(): # c3 # c4 return x """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckUnwrappedLines(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckLogicalLines(llines, [ (0, ['def', 'foo', '(', 'x', ')', ':', '# c1']), (1, ['# c2']), (1, ['return', 'x']), @@ -240,8 +240,8 @@ class Klass: # c1 # c2 p = 1 """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckUnwrappedLines(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckLogicalLines(llines, [ (0, ['class', 'Klass', ':', '# c1']), (1, ['# c2']), (1, ['p', '=', '1']), @@ -251,8 +251,8 @@ def testSingleLineStmtInFunc(self): code = textwrap.dedent(r""" def f(): return 37 """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckUnwrappedLines(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckLogicalLines(llines, [ (0, ['def', 'f', '(', ')', ':']), (1, ['return', '37']), ]) @@ -265,8 +265,8 @@ def testMultipleComments(self): def f(): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckUnwrappedLines(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckLogicalLines(llines, [ (0, ['# Comment #1']), (0, ['# Comment #2']), (0, ['def', 'f', '(', ')', ':']), @@ -281,48 +281,48 @@ def testSplitListWithComment(self): 'c', # hello world ] """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckUnwrappedLines(uwlines, [(0, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckLogicalLines(llines, [(0, [ 'a', '=', '[', "'a'", ',', "'b'", ',', "'c'", ',', '# hello world', ']' ])]) class MatchBracketsTest(yapf_test_helper.YAPFTest): - def _CheckMatchingBrackets(self, uwlines, list_of_expected): + def _CheckMatchingBrackets(self, llines, list_of_expected): """Check that the tokens have the expected matching bracket. Arguments: - uwlines: list of UnwrappedLine. + llines: list of LogicalLine. list_of_expected: list of (index, index) pairs. The matching brackets at the indexes need to match. Non-semantic tokens are filtered out from the expected values. """ actual = [] - for uwl in uwlines: + for lline in llines: filtered_values = [(ft, ft.matching_bracket) - for ft in uwl.tokens + for ft in lline.tokens if ft.name not in pytree_utils.NONSEMANTIC_TOKENS] if filtered_values: actual.append(filtered_values) for index, bracket_list in enumerate(list_of_expected): - uwline = actual[index] + lline = actual[index] if not bracket_list: - for value in uwline: + for value in lline: self.assertIsNone(value[1]) else: for open_bracket, close_bracket in bracket_list: - self.assertEqual(uwline[open_bracket][0], uwline[close_bracket][1]) - self.assertEqual(uwline[close_bracket][0], uwline[open_bracket][1]) + self.assertEqual(lline[open_bracket][0], lline[close_bracket][1]) + self.assertEqual(lline[close_bracket][0], lline[open_bracket][1]) def testFunctionDef(self): code = textwrap.dedent("""\ def foo(a, b=['w','d'], c=[42, 37]): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckMatchingBrackets(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckMatchingBrackets(llines, [ [(2, 20), (7, 11), (15, 19)], [], ]) @@ -333,8 +333,8 @@ def testDecorator(self): def foo(a, b, c): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckMatchingBrackets(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckMatchingBrackets(llines, [ [(2, 3)], [(2, 8)], [], @@ -345,8 +345,8 @@ def testClassDef(self): class A(B, C, D): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckMatchingBrackets(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckMatchingBrackets(llines, [ [(2, 8)], [], ]) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 539aa1076..5037f1110 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -43,8 +43,8 @@ def testSplittingAllArgs(self): "whatever": 120 } """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ yes = { 'yes': 'no', 'no': 'yes', } @@ -55,8 +55,8 @@ def testSplittingAllArgs(self): 'no': 'yes', } """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ def foo(long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args): pass @@ -68,8 +68,8 @@ def foo(long_arg, cant_keep_all_these_args): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ foo_tuple = [long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args] """) # noqa @@ -81,16 +81,16 @@ def foo(long_arg, cant_keep_all_these_args ] """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ foo_tuple = [short, arg] """) expected_formatted_code = textwrap.dedent("""\ foo_tuple = [short, arg] """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # There is a test for split_all_top_level_comma_separated_values, with # different expected value unformatted_code = textwrap.dedent("""\ @@ -103,8 +103,8 @@ def foo(long_arg, abc=(a, this_will_just_fit_xxxxxxx)) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingTopLevelAllArgs(self): style.SetGlobalStyle( @@ -122,8 +122,8 @@ def testSplittingTopLevelAllArgs(self): "whatever": 120 } """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Works the same way as split_all_comma_separated_values unformatted_code = textwrap.dedent("""\ def foo(long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args): @@ -136,8 +136,8 @@ def foo(long_arg, cant_keep_all_these_args): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Works the same way as split_all_comma_separated_values unformatted_code = textwrap.dedent("""\ foo_tuple = [long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args] @@ -150,8 +150,8 @@ def foo(long_arg, cant_keep_all_these_args ] """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Works the same way as split_all_comma_separated_values unformatted_code = textwrap.dedent("""\ foo_tuple = [short, arg] @@ -159,8 +159,8 @@ def foo(long_arg, expected_formatted_code = textwrap.dedent("""\ foo_tuple = [short, arg] """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # There is a test for split_all_comma_separated_values, with different # expected value unformatted_code = textwrap.dedent("""\ @@ -172,8 +172,8 @@ def foo(long_arg, this_is_a_very_long_parameter, abc=(a, this_will_just_fit_xxxxxxx)) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - actual_formatted_code = reformatter.Reformat(uwlines) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + actual_formatted_code = reformatter.Reformat(llines) self.assertEqual(40, len(actual_formatted_code.splitlines()[-1])) self.assertCodeEqual(expected_formatted_code, actual_formatted_code) @@ -187,8 +187,8 @@ def foo(long_arg, abc=(a, this_will_not_fit_xxxxxxxxx)) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Exercise the case where there's no opening bracket (for a, b) unformatted_code = textwrap.dedent("""\ @@ -199,8 +199,8 @@ def foo(long_arg, a, b = f( a_very_long_parameter, yet_another_one, and_another) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Don't require splitting before comments. unformatted_code = textwrap.dedent("""\ @@ -221,8 +221,8 @@ def foo(long_arg, 'JKL': Jkl, } """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSimpleFunctionsWithTrailingComments(self): unformatted_code = textwrap.dedent("""\ @@ -250,8 +250,8 @@ def f( # Intermediate comment xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBlankLinesBetweenTopLevelImportsAndVariables(self): unformatted_code = textwrap.dedent("""\ @@ -263,8 +263,8 @@ def testBlankLinesBetweenTopLevelImportsAndVariables(self): VAR = 'baz' """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ import foo as bar @@ -282,9 +282,9 @@ def testBlankLinesBetweenTopLevelImportsAndVariables(self): style.CreateStyleFromConfig( '{based_on_style: yapf, ' 'blank_lines_between_top_level_imports_and_variables: 2}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -296,8 +296,8 @@ def testBlankLinesBetweenTopLevelImportsAndVariables(self): import foo as bar # Some comment """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ import foo as bar @@ -311,8 +311,8 @@ class Baz(): class Baz(): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ import foo as bar @@ -326,8 +326,8 @@ def foobar(): def foobar(): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ def foobar(): @@ -339,8 +339,8 @@ def foobar(): from foo import Bar Bar.baz() """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBlankLinesAtEndOfFile(self): unformatted_code = textwrap.dedent("""\ @@ -354,8 +354,8 @@ def foobar(): # foo def foobar(): # foo pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ x = { 'a':37,'b':42, @@ -366,8 +366,8 @@ def foobar(): # foo expected_formatted_code = textwrap.dedent("""\ x = {'a': 37, 'b': 42, 'c': 927} """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testIndentBlankLines(self): unformatted_code = textwrap.dedent("""\ @@ -397,16 +397,16 @@ class foo(object):\n \n def foobar(self):\n \n pass\n \n def barfoo(se style.CreateStyleFromConfig( '{based_on_style: yapf, indent_blank_lines: true}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) unformatted_code, expected_formatted_code = (expected_formatted_code, unformatted_code) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMultipleUgliness(self): unformatted_code = textwrap.dedent("""\ @@ -445,8 +445,8 @@ def g(self, x, y=42): def f(a): return 37 + -+a[42 - x:y**3] """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testComments(self): unformatted_code = textwrap.dedent("""\ @@ -498,15 +498,15 @@ class Baz(object): class Qux(object): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSingleComment(self): code = textwrap.dedent("""\ # Thing 1 """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentsWithTrailingSpaces(self): unformatted_code = textwrap.dedent("""\ @@ -515,8 +515,8 @@ def testCommentsWithTrailingSpaces(self): # Thing 1 # Thing 2 """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testCommentsInDataLiteral(self): code = textwrap.dedent("""\ @@ -532,8 +532,8 @@ def f(): # Ending comment. }) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testEndingWhitespaceAfterSimpleStatement(self): code = textwrap.dedent("""\ @@ -541,8 +541,8 @@ def testEndingWhitespaceAfterSimpleStatement(self): # Thing 1 # Thing 2 """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDocstrings(self): unformatted_code = textwrap.dedent('''\ @@ -579,8 +579,8 @@ def qux(self): print('hello {}'.format('world')) return 42 ''') - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDocstringAndMultilineComment(self): unformatted_code = textwrap.dedent('''\ @@ -614,8 +614,8 @@ def foo(self): # comment pass ''') - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMultilineDocstringAndMultilineComment(self): unformatted_code = textwrap.dedent('''\ @@ -667,8 +667,8 @@ def foo(self): # comment pass ''') - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testTupleCommaBeforeLastParen(self): unformatted_code = textwrap.dedent("""\ @@ -677,8 +677,8 @@ def testTupleCommaBeforeLastParen(self): expected_formatted_code = textwrap.dedent("""\ a = (1,) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoBreakOutsideOfBracket(self): # FIXME(morbo): How this is formatted is not correct. But it's syntactically @@ -693,8 +693,8 @@ def f(): assert port >= minimum, 'Unexpected port %d when minimum was %d.' % (port, minimum) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBlankLinesBeforeDecorators(self): unformatted_code = textwrap.dedent("""\ @@ -714,8 +714,8 @@ class A(object): def x(self): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testCommentBetweenDecorators(self): unformatted_code = textwrap.dedent("""\ @@ -732,8 +732,8 @@ def x (self): def x(self): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testListComprehension(self): unformatted_code = textwrap.dedent("""\ @@ -745,8 +745,8 @@ def given(y): def given(y): [k for k in () if k in y] """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testListComprehensionPreferOneLine(self): unformatted_code = textwrap.dedent("""\ @@ -762,8 +762,8 @@ def given(y): long_var_name + 1 for long_var_name in () if long_var_name == 2 ] """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testListComprehensionPreferOneLineOverArithmeticSplit(self): unformatted_code = textwrap.dedent("""\ @@ -776,8 +776,8 @@ def given(used_identifiers): return (sum(len(identifier) for identifier in used_identifiers) / len(used_identifiers)) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testListComprehensionPreferThreeLinesForLineWrap(self): unformatted_code = textwrap.dedent("""\ @@ -795,8 +795,8 @@ def given(y): if long_var_name == 2 and number_two == 3 ] """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testListComprehensionPreferNoBreakForTrivialExpression(self): unformatted_code = textwrap.dedent("""\ @@ -813,8 +813,8 @@ def given(y): if long_var_name == 2 and number_two == 3 ] """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testOpeningAndClosingBrackets(self): unformatted_code = """\ @@ -831,8 +831,8 @@ def testOpeningAndClosingBrackets(self): 3, )) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSingleLineFunctions(self): unformatted_code = textwrap.dedent("""\ @@ -842,8 +842,8 @@ def foo(): return 42 def foo(): return 42 """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoQueueSeletionInMiddleOfLine(self): # If the queue isn't properly constructed, then a token in the middle of the @@ -856,8 +856,8 @@ def testNoQueueSeletionInMiddleOfLine(self): find_symbol(node.type) + "< " + " ".join( find_pattern(n) for n in node.child) + " >" """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoSpacesBetweenSubscriptsAndCalls(self): unformatted_code = textwrap.dedent("""\ @@ -866,8 +866,8 @@ def testNoSpacesBetweenSubscriptsAndCalls(self): expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaa = bbbbbbbb.ccccccccc()[42](a, 2) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoSpacesBetweenOpeningBracketAndStartingOperator(self): # Unary operator. @@ -877,8 +877,8 @@ def testNoSpacesBetweenOpeningBracketAndStartingOperator(self): expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaa = bbbbbbbb.ccccccccc[-1](-42) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Varargs and kwargs. unformatted_code = textwrap.dedent("""\ @@ -889,8 +889,8 @@ def testNoSpacesBetweenOpeningBracketAndStartingOperator(self): aaaaaaaaaa = bbbbbbbb.ccccccccc(*varargs) aaaaaaaaaa = bbbbbbbb.ccccccccc(**kwargs) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMultilineCommentReformatted(self): unformatted_code = textwrap.dedent("""\ @@ -905,8 +905,8 @@ def testMultilineCommentReformatted(self): # comment. pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDictionaryMakerFormatting(self): unformatted_code = textwrap.dedent("""\ @@ -930,8 +930,8 @@ def testDictionaryMakerFormatting(self): 'while_stmt': 'for_stmt', }) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSimpleMultilineCode(self): unformatted_code = textwrap.dedent("""\ @@ -948,8 +948,8 @@ def testSimpleMultilineCode(self): aaaaaaaaaaaaaa.bbbbbbbbbbbbbb.ccccccc(zzzzzzzzzzzz, xxxxxxxxxxx, yyyyyyyyyyyy, vvvvvvvvv) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMultilineComment(self): code = textwrap.dedent("""\ @@ -961,15 +961,15 @@ def testMultilineComment(self): # Yo man. a = 42 """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testSpaceBetweenStringAndParentheses(self): code = textwrap.dedent("""\ b = '0' ('hello') """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testMultilineString(self): code = textwrap.dedent("""\ @@ -983,8 +983,8 @@ def testMultilineString(self): a = 42 ''') """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent('''\ def f(): @@ -1004,8 +1004,8 @@ def f(): """ ''') # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSimpleMultilineWithComments(self): code = textwrap.dedent("""\ @@ -1016,8 +1016,8 @@ def testSimpleMultilineWithComments(self): # Whoa! A normal comment!! pass # Another trailing comment """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testMatchingParenSplittingMatching(self): unformatted_code = textwrap.dedent("""\ @@ -1030,8 +1030,8 @@ def f(): raise RuntimeError('unable to find insertion point for target node', (target,)) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testContinuationIndent(self): unformatted_code = textwrap.dedent('''\ @@ -1056,8 +1056,8 @@ def _ProcessArgLists(self, node): subtype=_ARGLIST_TOKEN_TO_SUBTYPE.get(child.value, format_token.Subtype.NONE)) ''') # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testTrailingCommaAndBracket(self): unformatted_code = textwrap.dedent('''\ @@ -1074,21 +1074,21 @@ def testTrailingCommaAndBracket(self): 42, ] ''') - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testI18n(self): code = textwrap.dedent("""\ N_('Some years ago - never mind how long precisely - having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world.') # A comment is here. """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) code = textwrap.dedent("""\ foo('Fake function call') #. Some years ago - never mind how long precisely - having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testI18nCommentsInDataLiteral(self): code = textwrap.dedent("""\ @@ -1101,8 +1101,8 @@ def f(): 'snork': 'bar#.*=\\\\0', }) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testClosingBracketIndent(self): code = textwrap.dedent('''\ @@ -1114,8 +1114,8 @@ def g(): yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): pass ''') # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testClosingBracketsInlinedInCall(self): unformatted_code = textwrap.dedent("""\ @@ -1146,8 +1146,8 @@ def bar(self): "porkporkpork": 5, }) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testLineWrapInForExpression(self): code = textwrap.dedent("""\ @@ -1159,8 +1159,8 @@ def x(self, node, name, n=1): node.pre_order())): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionCallContinuationLine(self): code = """\ @@ -1173,8 +1173,8 @@ def bar(self, node, name, n=1): bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb( cccc, ddddddddddddddddddddddddddddddddddddd))] """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testI18nNonFormatting(self): code = textwrap.dedent("""\ @@ -1185,16 +1185,16 @@ def __init__(self, fieldname, message=N_('Please check your email address.'), **kwargs): pass """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSpaceBetweenUnaryOpAndOpeningParen(self): code = textwrap.dedent("""\ if ~(a or b): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentBeforeFuncDef(self): code = textwrap.dedent("""\ @@ -1211,8 +1211,8 @@ def __init__(self, bbbbbbbbbbbbbbb=False): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testExcessLineCountWithDefaultKeywords(self): unformatted_code = textwrap.dedent("""\ @@ -1236,16 +1236,16 @@ def Moo(self): hhhhhhhhhhhhh=hhhhhhhhhhhhh, iiiiiii=iiiiiiiiiiiiii) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSpaceAfterNotOperator(self): code = textwrap.dedent("""\ if not (this and that): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoPenaltySplitting(self): code = textwrap.dedent("""\ @@ -1257,8 +1257,8 @@ def f(): for f in os.listdir(filename) if IsPythonFile(os.path.join(filename, f))) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testExpressionPenalties(self): code = textwrap.dedent("""\ @@ -1268,8 +1268,8 @@ def f(): (left.value == '{' and right.value == '}')): return False """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testLineDepthOfSingleLineStatement(self): unformatted_code = textwrap.dedent("""\ @@ -1291,8 +1291,8 @@ def testLineDepthOfSingleLineStatement(self): with open(a) as fd: a = fd.read() """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplitListWithTerminatingComma(self): unformatted_code = textwrap.dedent("""\ @@ -1314,8 +1314,8 @@ def testSplitListWithTerminatingComma(self): lambda a, b: 37, ] """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplitListWithInterspersedComments(self): code = textwrap.dedent("""\ @@ -1333,15 +1333,15 @@ def testSplitListWithInterspersedComments(self): lambda a, b: 37 # lambda ] """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testRelativeImportStatements(self): code = textwrap.dedent("""\ from ... import bork """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testSingleLineList(self): # A list on a single line should prefer to remain contiguous. @@ -1355,8 +1355,8 @@ def testSingleLineList(self): bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = aaaaaaaaaaa( ("...", "."), "..", "..............................................") """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBlankLinesBeforeFunctionsNotInColumnZero(self): unformatted_code = textwrap.dedent("""\ @@ -1389,8 +1389,8 @@ def timeout(seconds=1): except: pass """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoKeywordArgumentBreakage(self): code = textwrap.dedent("""\ @@ -1401,8 +1401,8 @@ def b(self): cccccccccccccccccccc=True): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testTrailerOnSingleLine(self): code = """\ @@ -1411,8 +1411,8 @@ def testTrailerOnSingleLine(self): url(r'^/login/$', 'logout_view'), url(r'^/user/(?P\\w+)/$', 'profile_view')) """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testIfConditionalParens(self): code = textwrap.dedent("""\ @@ -1424,8 +1424,8 @@ def bar(): child.value in substatement_names): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testContinuationMarkers(self): code = textwrap.dedent("""\ @@ -1435,23 +1435,23 @@ def testContinuationMarkers(self): "sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. "\\ "Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet" """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) code = textwrap.dedent("""\ from __future__ import nested_scopes, generators, division, absolute_import, with_statement, \\ print_function, unicode_literals """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) code = textwrap.dedent("""\ if aaaaaaaaa == 42 and bbbbbbbbbbbbbb == 42 and \\ cccccccc == 42: pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentsWithContinuationMarkers(self): code = textwrap.dedent("""\ @@ -1461,8 +1461,8 @@ def fn(arg): key2=arg)\\ .fn3() """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testMultipleContinuationMarkers(self): code = textwrap.dedent("""\ @@ -1470,8 +1470,8 @@ def testMultipleContinuationMarkers(self): \\ some_thing() """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testContinuationMarkerAfterStringWithContinuation(self): code = """\ @@ -1479,8 +1479,8 @@ def testContinuationMarkerAfterStringWithContinuation(self): bar' \\ .format() """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testEmptyContainers(self): code = textwrap.dedent("""\ @@ -1489,8 +1489,8 @@ def testEmptyContainers(self): 'Lorem ipsum dolor sit amet, consetetur adipiscing elit. Donec a diam lectus. ' 'Sed sit amet ipsum mauris. Maecenas congue.') """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testSplitStringsIfSurroundedByParens(self): unformatted_code = textwrap.dedent("""\ @@ -1504,16 +1504,16 @@ def testSplitStringsIfSurroundedByParens(self): 'cccccccccccccccccccccccccccccccc' 'ddddddddddddddddddddddddddddd') """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) code = textwrap.dedent("""\ a = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' \ 'bbbbbbbbbbbbbbbbbbbbbbbbbb' 'cccccccccccccccccccccccccccccccc' \ 'ddddddddddddddddddddddddddddd' """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testMultilineShebang(self): code = textwrap.dedent("""\ @@ -1532,16 +1532,16 @@ def testMultilineShebang(self): assert os.environ['FOO'] == '123' """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSplittingAroundTermOperators(self): code = textwrap.dedent("""\ a_very_long_function_call_yada_yada_etc_etc_etc(long_arg1, long_arg2 / long_arg3) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSplittingWithinSubscriptList(self): code = textwrap.dedent("""\ @@ -1550,8 +1550,8 @@ def testNoSplittingWithinSubscriptList(self): 'someotherlongkey': 2 } """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testExcessCharacters(self): code = textwrap.dedent("""\ @@ -1562,8 +1562,8 @@ def bar(self): '%s%s %s' % ('many of really', 'long strings', '+ just makes up 81') ]) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ def _(): @@ -1580,8 +1580,8 @@ def _(): if_attribute) == has_value: return True """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testDictSetGenerator(self): code = textwrap.dedent("""\ @@ -1591,8 +1591,8 @@ def testDictSetGenerator(self): if variable != 37 } """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testUnaryOpInDictionaryValue(self): code = textwrap.dedent("""\ @@ -1602,8 +1602,8 @@ def testUnaryOpInDictionaryValue(self): print(beta[-1]) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testUnaryNotOperator(self): code = textwrap.dedent("""\ @@ -1614,8 +1614,8 @@ def testUnaryNotOperator(self): remote_checksum = self.get_checksum(conn, tmp, dest, inject, not directory_prepended, source) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testRelaxArraySubscriptAffinity(self): code = """\ @@ -1630,18 +1630,18 @@ def f(self, aaaaaaaaa, bbbbbbbbbbbbb, row): bbbbbbbbbbbbb[ '..............'] = row[5] if row[5] is not None else 5 """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionCallInDict(self): code = "a = {'a': b(c=d, **e)}\n" - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionCallInNestedDict(self): code = "a = {'a': {'a': {'a': b(c=d, **e)}}}\n" - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testUnbreakableNot(self): code = textwrap.dedent("""\ @@ -1649,8 +1649,8 @@ def test(): if not "Foooooooooooooooooooooooooooooo" or "Foooooooooooooooooooooooooooooo" == "Foooooooooooooooooooooooooooooo": pass """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testSplitListWithComment(self): code = textwrap.dedent("""\ @@ -1660,8 +1660,8 @@ def testSplitListWithComment(self): 'c' # hello world ] """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testOverColumnLimit(self): unformatted_code = textwrap.dedent("""\ @@ -1687,8 +1687,8 @@ def testSomething(self): 'ccccccccccccccccccccccccccccccccccccccccccc', } """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testEndingComment(self): code = textwrap.dedent("""\ @@ -1697,8 +1697,8 @@ def testEndingComment(self): b="something requiring comment which is quite long", # comment about b (pushes line over 79) c="something else, about which comment doesn't make sense") """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testContinuationSpaceRetention(self): code = textwrap.dedent("""\ @@ -1708,8 +1708,8 @@ def fn(): fn2(arg) )) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testIfExpressionWithFunctionCall(self): code = textwrap.dedent("""\ @@ -1720,8 +1720,8 @@ def testIfExpressionWithFunctionCall(self): bbbbbbbbbbbbbbbbbbbbb=bbbbbbbbbbbbbbbbbb): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testUnformattedAfterMultilineString(self): code = textwrap.dedent("""\ @@ -1731,8 +1731,8 @@ def foo(): TEST ''' % (input_fname, output_fname) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSpacesAroundKeywordDefaultValues(self): code = textwrap.dedent("""\ @@ -1742,8 +1742,8 @@ def testNoSpacesAroundKeywordDefaultValues(self): } json = request.get_json(silent=True) or {} """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSplittingBeforeEndingSubscriptBracket(self): unformatted_code = textwrap.dedent("""\ @@ -1757,8 +1757,8 @@ def testNoSplittingBeforeEndingSubscriptBracket(self): status = cf.describe_stacks( StackName=stackname)[u'Stacks'][0][u'StackStatus'] """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoSplittingOnSingleArgument(self): unformatted_code = textwrap.dedent("""\ @@ -1779,8 +1779,8 @@ def testNoSplittingOnSingleArgument(self): re.search(r'(\\d+\\.\\d+\\.\\d+\\.)\\d+', aaaaaaa.bbbbbbbbbbbb).group(a.b) + re.search(r'\\d+\\.\\d+\\.\\d+\\.(\\d+)', ccccccc).group(c.d)) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingArraysSensibly(self): unformatted_code = textwrap.dedent("""\ @@ -1797,8 +1797,8 @@ def testSplittingArraysSensibly(self): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list( 'bbbbbbbbbbbbbbbbbbbbbbbbb').split(',') """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testComprehensionForAndIf(self): unformatted_code = textwrap.dedent("""\ @@ -1814,8 +1814,8 @@ def __repr__(self): tokens_repr = ','.join( ['{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens]) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testFunctionCallArguments(self): unformatted_code = textwrap.dedent("""\ @@ -1839,8 +1839,8 @@ def f(): _CreateCommentsFromPrefix( comment_prefix, comment_lineno, comment_column, standalone=True)) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBinaryOperators(self): unformatted_code = textwrap.dedent("""\ @@ -1851,8 +1851,8 @@ def testBinaryOperators(self): a = b**37 c = (20**-3) / (_GRID_ROWS**(code_length - 10)) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) code = textwrap.dedent("""\ def f(): @@ -1863,16 +1863,16 @@ def f(): current.value in ']}'): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testContiguousList(self): code = textwrap.dedent("""\ [retval1, retval2] = a_very_long_function(argument_1, argument2, argument_3, argument_4) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testArgsAndKwargsFormatting(self): code = textwrap.dedent("""\ @@ -1882,8 +1882,8 @@ def testArgsAndKwargsFormatting(self): *d, **e) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) code = textwrap.dedent("""\ def foo(): @@ -1893,8 +1893,8 @@ def foo(): zzz='a third long string') ] """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentColumnLimitOverflow(self): code = textwrap.dedent("""\ @@ -1906,8 +1906,8 @@ def f(): # side_effect=[(157031694470475), (157031694470475),], ) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testMultilineLambdas(self): unformatted_code = textwrap.dedent("""\ @@ -1938,9 +1938,9 @@ def succeeded(self, dddddddddddddd): style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: yapf, allow_multiline_lambdas: true}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -1971,9 +1971,9 @@ def testMultilineDictionaryKeys(self): style.SetGlobalStyle( style.CreateStyleFromConfig('{based_on_style: yapf, ' 'allow_multiline_dictionary_keys: true}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -1999,12 +1999,12 @@ def method(self): 'continuation_indent_width: 4, ' 'indent_dictionary_value: True}')) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - reformatted_code = reformatter.Reformat(uwlines) + llines = yapf_test_helper.ParseAndUnwrap(code) + reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, reformatted_code) - uwlines = yapf_test_helper.ParseAndUnwrap(reformatted_code) - reformatted_code = reformatter.Reformat(uwlines) + llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, reformatted_code) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -2026,12 +2026,12 @@ def _(): })) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - reformatted_code = reformatter.Reformat(uwlines) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) - uwlines = yapf_test_helper.ParseAndUnwrap(reformatted_code) - reformatted_code = reformatter.Reformat(uwlines) + llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -2047,8 +2047,8 @@ def mark_game_scored(gid): _connect.execute( _games.update().where(_games.c.gid == gid).values(scored=True)) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDontAddBlankLineAfterMultilineString(self): code = textwrap.dedent("""\ @@ -2057,8 +2057,8 @@ def testDontAddBlankLineAfterMultilineString(self): WHERE day in {}''' days = ",".join(days) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFormattingListComprehensions(self): code = textwrap.dedent("""\ @@ -2071,8 +2071,8 @@ def a(): ] self._heap = [x for x in self._heap if x.route and x.route[0] == choice] """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSplittingWhenBinPacking(self): code = textwrap.dedent("""\ @@ -2097,12 +2097,12 @@ def testNoSplittingWhenBinPacking(self): 'dedent_closing_brackets: True, ' 'split_before_named_assigns: False}')) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - reformatted_code = reformatter.Reformat(uwlines) + llines = yapf_test_helper.ParseAndUnwrap(code) + reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, reformatted_code) - uwlines = yapf_test_helper.ParseAndUnwrap(reformatted_code) - reformatted_code = reformatter.Reformat(uwlines) + llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, reformatted_code) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -2118,8 +2118,8 @@ def testNotSplittingAfterSubscript(self): c == d['eeeeee']).ffffff(): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingOneArgumentList(self): unformatted_code = textwrap.dedent("""\ @@ -2141,8 +2141,8 @@ def _(): boxes[id_] = np.concatenate( (points.min(axis=0), qoints.max(axis=0))) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingBeforeFirstElementListArgument(self): unformatted_code = textwrap.dedent("""\ @@ -2170,8 +2170,8 @@ def _pack_results_for_constraint_or(cls, combination, constraints): (clue for clue in combination if not clue == Verifier.UNMATCHED), constraints, InvestigationResult.OR) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingArgumentsTerminatedByComma(self): unformatted_code = textwrap.dedent("""\ @@ -2220,12 +2220,12 @@ def testSplittingArgumentsTerminatedByComma(self): '{based_on_style: yapf, ' 'split_arguments_when_comma_terminated: True}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - reformatted_code = reformatter.Reformat(uwlines) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) - uwlines = yapf_test_helper.ParseAndUnwrap(reformatted_code) - reformatted_code = reformatter.Reformat(uwlines) + llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -2236,8 +2236,8 @@ def testImportAsList(self): from toto import titi, tata, tutu from toto import (titi, tata, tutu) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDictionaryValuesOnOwnLines(self): unformatted_code = textwrap.dedent("""\ @@ -2288,8 +2288,8 @@ def testDictionaryValuesOnOwnLines(self): Check('QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ', '=', False), } """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDictionaryOnOwnLine(self): unformatted_code = textwrap.dedent("""\ @@ -2302,8 +2302,8 @@ def testDictionaryOnOwnLine(self): doc = test_utils.CreateTestDocumentViaController( content={'a': 'b'}, branch_key=branch.key, collection_key=collection.key) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ doc = test_utils.CreateTestDocumentViaController( @@ -2319,8 +2319,8 @@ def testDictionaryOnOwnLine(self): collection_key=collection.key, collection_key2=collection.key2) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNestedListsInDictionary(self): unformatted_code = textwrap.dedent("""\ @@ -2386,8 +2386,8 @@ def testNestedListsInDictionary(self): ), } """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNestedDictionary(self): unformatted_code = textwrap.dedent("""\ @@ -2414,8 +2414,8 @@ def _(): ] breadcrumbs = [{'name': 'Admin', 'url': url_for(".home")}, {'title': title}] """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDictionaryElementsOnOneLine(self): code = textwrap.dedent("""\ @@ -2434,8 +2434,8 @@ def _(): Environment.ZZZZZZZZZZZ: 'some text more text even more text yet again tex', } """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNotInParams(self): unformatted_code = textwrap.dedent("""\ @@ -2445,8 +2445,8 @@ def testNotInParams(self): list("a long line to break the line. a long line to break the brk a long lin", not True) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testNamedAssignNotAtEndOfLine(self): unformatted_code = textwrap.dedent("""\ @@ -2463,8 +2463,8 @@ def _(): filename, mode='w', encoding=encoding) as fd: pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testBlankLineBeforeClassDocstring(self): unformatted_code = textwrap.dedent('''\ @@ -2488,8 +2488,8 @@ class A: def __init__(self): pass ''') - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent('''\ class A: @@ -2520,9 +2520,9 @@ def __init__(self): '{based_on_style: yapf, ' 'blank_line_before_class_docstring: True}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -2546,8 +2546,8 @@ def foobar(): def foobar(): pass ''') - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent('''\ #!/usr/bin/env python @@ -2575,9 +2575,9 @@ def foobar(): '{based_on_style: pep8, ' 'blank_line_before_module_docstring: True}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -2593,15 +2593,15 @@ def f(): an_extremely_long_variable_name, ('a string that may be too long %s' % 'M15')) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testSubscriptExpression(self): code = textwrap.dedent("""\ foo = d[not a] """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testListWithFunctionCalls(self): unformatted_code = textwrap.dedent("""\ @@ -2627,8 +2627,8 @@ def foo(): zzz='a third long string') ] """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testEllipses(self): unformatted_code = textwrap.dedent("""\ @@ -2639,8 +2639,8 @@ def testEllipses(self): X = ... Y = X if ... else X """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testPseudoParens(self): unformatted_code = """\ @@ -2657,8 +2657,8 @@ def testPseudoParens(self): }, } """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testSplittingBeforeFirstArgumentOnFunctionCall(self): """Tests split_before_first_argument on a function call.""" @@ -2676,9 +2676,9 @@ def testSplittingBeforeFirstArgumentOnFunctionCall(self): style.CreateStyleFromConfig( '{based_on_style: yapf, split_before_first_argument: True}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -2700,9 +2700,9 @@ def _GetNumberOfSecondsFromElements( style.CreateStyleFromConfig( '{based_on_style: yapf, split_before_first_argument: True}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -2726,9 +2726,9 @@ def testSplittingBeforeFirstArgumentOnCompoundStatement(self): style.CreateStyleFromConfig( '{based_on_style: yapf, split_before_first_argument: True}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -2762,9 +2762,9 @@ def testCoalesceBracketsOnDict(self): style.CreateStyleFromConfig( '{based_on_style: yapf, coalesce_brackets: True}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -2783,8 +2783,8 @@ def testSplitAfterComment(self): style.CreateStyleFromConfig( '{based_on_style: yapf, coalesce_brackets: True, ' 'dedent_closing_brackets: true}')) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -2804,8 +2804,8 @@ def foo(self): async.run() """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -2819,8 +2819,8 @@ def testDisableEndingCommaHeuristic(self): style.CreateStyleFromConfig('{based_on_style: yapf,' ' disable_ending_comma_heuristic: True}')) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -2851,9 +2851,9 @@ def function( style.CreateStyleFromConfig('{based_on_style: yapf,' ' dedent_closing_brackets: True}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -2884,9 +2884,9 @@ def function( style.CreateStyleFromConfig('{based_on_style: yapf,' ' indent_closing_brackets: True}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -2919,9 +2919,9 @@ def function( style.CreateStyleFromConfig('{based_on_style: yapf,' ' indent_closing_brackets: True}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -2954,9 +2954,9 @@ def function(): style.CreateStyleFromConfig('{based_on_style: yapf,' ' indent_closing_brackets: True}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -2989,9 +2989,9 @@ def function(): style.CreateStyleFromConfig('{based_on_style: yapf,' ' indent_closing_brackets: True}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -3030,9 +3030,9 @@ def function(): style.CreateStyleFromConfig('{based_on_style: yapf,' ' indent_closing_brackets: True}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -3086,8 +3086,8 @@ def b(): }] } """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testForceMultilineDict_True(self): try: @@ -3095,8 +3095,8 @@ def testForceMultilineDict_True(self): style.CreateStyleFromConfig('{force_multiline_dict: true}')) unformatted_code = textwrap.dedent( "responseDict = {'childDict': {'spam': 'eggs'}}\n") - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - actual = reformatter.Reformat(uwlines) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + actual = reformatter.Reformat(llines) expected = textwrap.dedent("""\ responseDict = { 'childDict': { @@ -3116,9 +3116,9 @@ def testForceMultilineDict_False(self): responseDict = {'childDict': {'spam': 'eggs'}} """) expected_formatted_code = unformatted_code - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -3132,8 +3132,8 @@ def testWalrus(self): if (x := len([1] * 1000) > 100): print(f'{x} is pretty big') """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected, reformatter.Reformat(llines)) if __name__ == '__main__': diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index a3244443c..b3de8f9b0 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -35,8 +35,8 @@ def _create_testing_simulator_and_sink( _batch_simulator.SimulationSink]: pass """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB73279849(self): unformatted_code = """\ @@ -49,8 +49,8 @@ class A: def _(a): return 'hello'[a] """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB122455211(self): unformatted_code = """\ @@ -62,8 +62,8 @@ def testB122455211(self): sssssssssssssssssssss.pppppppppppppppp, sssssssssssssssssssss.pppppppppppppppppppppppppppp] """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB119300344(self): code = """\ @@ -73,8 +73,8 @@ def _GenerateStatsEntries( ) -> Sequence[stats_values.StatsStoreEntry]: pass """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB132886019(self): code = """\ @@ -86,8 +86,8 @@ def testB132886019(self): ]), } """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB26521719(self): code = """\ @@ -97,8 +97,8 @@ def _(self): self.stubs.Set(some_type_of_arg, 'ThisIsAStringArgument', lambda *unused_args, **unused_kwargs: fake_resolver) """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB122541552(self): code = """\ @@ -110,8 +110,8 @@ def testB122541552(self): def _(): pass """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB124415889(self): code = """\ @@ -133,8 +133,8 @@ def modules_to_install(): }) return modules """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB73166511(self): code = """\ @@ -143,8 +143,8 @@ def _(): groundtruth_age_variances = tf.maximum(groundtruth_age_variances, min_std**2) """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB118624921(self): code = """\ @@ -156,8 +156,8 @@ def _(): metric='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', bork=foo) """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB35417079(self): code = """\ @@ -171,8 +171,8 @@ def _(): 'CopybaraCopybaraCopybaraCopybaraCopybaraCopybaraCopybaraCopybaraCopybara' # copybara:strip ) """ # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB120047670(self): unformatted_code = """\ @@ -195,8 +195,8 @@ def testB120047670(self): 'PING_BLOCKED_BUGS': False, } """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB120245013(self): unformatted_code = """\ @@ -213,8 +213,8 @@ def testNoAlertForShortPeriod(self, rutabaga): self._fillInOtherFields(streamz_path, {streamz_field_of_interest: True} )] = series.Counter('1s', '+ 500x10000') """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB117841880(self): code = """\ @@ -230,8 +230,8 @@ def xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( ) -> pd.DataFrame: pass """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB111764402(self): unformatted_code = """\ @@ -244,16 +244,16 @@ def testB111764402(self): for external_id in external_ids })) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB116825060(self): code = """\ result_df = pd.DataFrame({LEARNED_CTR_COLUMN: learned_ctr}, index=df_metrics.index) """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB112711217(self): code = """\ @@ -261,8 +261,8 @@ def _(): stats['moderated'] = ~stats.moderation_reason.isin( approved_moderation_reasons) """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB112867548(self): unformatted_code = """\ @@ -283,8 +283,8 @@ def _(): httplib.ACCEPTED if process_result.has_more else httplib.OK, {'content-type': _TEXT_CONTEXT_TYPE}) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB112651423(self): unformatted_code = """\ @@ -302,8 +302,8 @@ def potato(feeditems, browse_use_case=None): 'FEEDS_LOAD_PLAYLIST_VIDEOS_FOR_ALL_ITEMS'] and item.video: continue """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB80484938(self): code = """\ @@ -345,8 +345,8 @@ def testB80484938(self): ]: pass """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB120771563(self): code = """\ @@ -372,8 +372,8 @@ def b(): }] } """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB79462249(self): code = """\ @@ -394,8 +394,8 @@ def testB79462249(self): bbbbbbbbbbbbbbbbbbbbb=2, ccccccccccccccccccc=3) """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB113210278(self): unformatted_code = """\ @@ -410,8 +410,8 @@ def _(): eeeeeeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffffffffffffffffffffff .ggggggggggggggggggggggggggggggggg.hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh()) """ # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB77923341(self): code = """\ @@ -420,8 +420,8 @@ def f(): ddddddddddd.eeeeeeeee == constants.FFFFFFFFFFFFFF): raise "yo" """ # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB77329955(self): code = """\ @@ -438,8 +438,8 @@ class _(): def _(): pass """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB65197969(self): unformatted_code = """\ @@ -457,8 +457,8 @@ def _(): seconds=max(float(time_scale), small_interval) * 1.41**min(num_attempts, 9)) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB65546221(self): unformatted_code = """\ @@ -484,8 +484,8 @@ def testB65546221(self): "debian-9-stretch", ) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30500455(self): unformatted_code = """\ @@ -501,8 +501,8 @@ def testB30500455(self): [(name, 'function#' + name) for name in INITIAL_FUNCTIONS] + [(name, 'const#' + name) for name in INITIAL_CONSTS]) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB38343525(self): code = """\ @@ -513,8 +513,8 @@ def testB38343525(self): def f(): print 1 """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB37099651(self): unformatted_code = """\ @@ -534,8 +534,8 @@ def testB37099651(self): # pylint: enable=g-long-lambda ) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB33228502(self): unformatted_code = """\ @@ -572,8 +572,8 @@ def _(): | m.Join('successes', 'total') | m.Point(m.VAL['successes'] / m.VAL['total'])))) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30394228(self): code = """\ @@ -585,8 +585,8 @@ def _(self): alert.Format(alert.body, alert=alert, threshold=threshold), alert.html_formatting) """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB65246454(self): unformatted_code = """\ @@ -605,8 +605,8 @@ def _(self): self.assertEqual({i.id for i in successful_instances}, {i.id for i in self._statuses.successful_instances}) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB67935450(self): unformatted_code = """\ @@ -646,8 +646,8 @@ def _(): m.Cond(m.VAL['start'] != 0, m.VAL['start'], m.TimestampMicros() / 1000000L))) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB66011084(self): unformatted_code = """\ @@ -678,8 +678,8 @@ def testB66011084(self): ]), } """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB67455376(self): unformatted_code = """\ @@ -689,8 +689,8 @@ def testB67455376(self): sponge_ids.extend(invocation.id() for invocation in self._client.GetInvocationsByLabels(labels)) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB35210351(self): unformatted_code = """\ @@ -719,8 +719,8 @@ def _(): GetTheAlertToIt('the_title_to_the_thing_here'), GetNotificationTemplate('your_email_here'))) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB34774905(self): unformatted_code = """\ @@ -748,15 +748,15 @@ def testB34774905(self): astn=None)) ] """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB65176185(self): code = """\ xx = zip(*[(a, b) for (a, b, c) in yy]) """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB35210166(self): unformatted_code = """\ @@ -776,8 +776,8 @@ def _(): | o.Window(m.Align('5m')) | p.GroupBy(['borg_user', 'borg_job', 'borg_cell'], q.Mean())) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB32167774(self): unformatted_code = """\ @@ -803,8 +803,8 @@ def testB32167774(self): 'is_compilation', ) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB66912275(self): unformatted_code = """\ @@ -827,8 +827,8 @@ def _(): 'fingerprint': base64.urlsafe_b64encode('invalid_fingerprint') }).execute() """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB67312284(self): code = """\ @@ -837,8 +837,8 @@ def _(): [u'to be published 2', u'to be published 1', u'to be published 0'], [el.text for el in page.first_column_tds]) """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB65241516(self): unformatted_code = """\ @@ -850,16 +850,16 @@ def testB65241516(self): TrainTraceDir(unit_key, "*", "*"), embedding_model.CHECKPOINT_FILENAME + "-*")) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB37460004(self): code = textwrap.dedent("""\ assert all(s not in (_SENTINEL, None) for s in nested_schemas ), 'Nested schemas should never contain None/_SENTINEL' """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB36806207(self): code = """\ @@ -877,8 +877,8 @@ def _(): "%.1f%%" % (np.max(linearity_values["rot_discontinuity"]) * 100.0) ]] """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB36215507(self): code = textwrap.dedent("""\ @@ -891,8 +891,8 @@ def _(): *(qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq), **(qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq)) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB35212469(self): unformatted_code = textwrap.dedent("""\ @@ -913,8 +913,8 @@ def _(): } } """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB31063453(self): unformatted_code = textwrap.dedent("""\ @@ -928,8 +928,8 @@ def _(): ((time_time() - last_modified) < FLAGS_boot_idle_timeout)): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB35021894(self): unformatted_code = textwrap.dedent("""\ @@ -955,8 +955,8 @@ def _(): 'modify': 'name/some-other-type-of-very-long-name-for-modifying' }) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB34682902(self): unformatted_code = textwrap.dedent("""\ @@ -966,8 +966,8 @@ def testB34682902(self): logging.info("Mean angular velocity norm: %.3f", np.linalg.norm(np.mean(ang_vel_arr, axis=0))) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB33842726(self): unformatted_code = textwrap.dedent("""\ @@ -982,8 +982,8 @@ def _(): hints.append(('hg tag -f -l -r %s %s # %s' % (short(ctx.node()), candidatetag, firstline))[:78]) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB32931780(self): unformatted_code = textwrap.dedent("""\ @@ -1044,8 +1044,8 @@ def testB32931780(self): } } """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB33047408(self): code = textwrap.dedent("""\ @@ -1058,8 +1058,8 @@ def _(): 'order': 'ASCENDING' }) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB32714745(self): code = textwrap.dedent("""\ @@ -1088,8 +1088,8 @@ def _BlankDefinition(): 'dirty': False, } """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB32737279(self): unformatted_code = textwrap.dedent("""\ @@ -1105,8 +1105,8 @@ def testB32737279(self): 'value' } """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB32570937(self): code = textwrap.dedent("""\ @@ -1116,8 +1116,8 @@ def _(): job_message.mall not in ('*', job_name)): return False """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB31937033(self): code = textwrap.dedent("""\ @@ -1126,8 +1126,8 @@ class _(): def __init__(self, metric, fields_cb=None): self._fields_cb = fields_cb or (lambda *unused_args, **unused_kwargs: {}) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB31911533(self): code = """\ @@ -1142,8 +1142,8 @@ class _(): def _(): pass """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB31847238(self): unformatted_code = textwrap.dedent("""\ @@ -1167,8 +1167,8 @@ def xxxxx( zzzzzzzzzzzzzz=None): # A normal comment that runs over the column limit. return 1 """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30760569(self): unformatted_code = textwrap.dedent("""\ @@ -1181,8 +1181,8 @@ def testB30760569(self): '1234567890123456789012345678901234567890' } """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB26034238(self): unformatted_code = textwrap.dedent("""\ @@ -1199,8 +1199,8 @@ def Function(self): '/aaaaaaaaa/bbbbbbbbbb/ccccc/dddd/eeeeeeeeeeeeee/ffffffffffffff' ).AndReturn(42) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30536435(self): unformatted_code = textwrap.dedent("""\ @@ -1220,8 +1220,8 @@ def main(unused_argv): bbbbbbbbb.usage, ccccccccc.within, imports.ddddddddddddddddddd(name_item.ffffffffffffffff))) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30442148(self): unformatted_code = textwrap.dedent("""\ @@ -1234,8 +1234,8 @@ def lulz(): return (some_long_module_name.SomeLongClassName.some_long_attribute_name .some_long_method_name()) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB26868213(self): unformatted_code = textwrap.dedent("""\ @@ -1270,8 +1270,8 @@ def _(): } } """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30173198(self): code = textwrap.dedent("""\ @@ -1281,8 +1281,8 @@ def _(): self.assertFalse( evaluation_runner.get_larps_in_eval_set('these_arent_the_larps')) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB29908765(self): code = textwrap.dedent("""\ @@ -1292,8 +1292,8 @@ def __repr__(self): return '' % ( self._id, self._stub._stub.rpc_channel().target()) # pylint:disable=protected-access """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB30087362(self): code = textwrap.dedent("""\ @@ -1305,8 +1305,8 @@ def _(): # This is another comment foo() """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB30087363(self): code = textwrap.dedent("""\ @@ -1317,8 +1317,8 @@ def testB30087363(self): elif True: foo() """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB29093579(self): unformatted_code = textwrap.dedent("""\ @@ -1333,8 +1333,8 @@ def _(): bbbbbbbbbbbbbb.cccccccccc[dddddddddddddddddddddddddddd .eeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffff]) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB26382315(self): code = textwrap.dedent("""\ @@ -1345,8 +1345,8 @@ def testB26382315(self): def foo(): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB27616132(self): unformatted_code = textwrap.dedent("""\ @@ -1368,8 +1368,8 @@ def testB27616132(self): mock.call(100, start_cursor=cursor_2), ]) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB27590179(self): unformatted_code = textwrap.dedent("""\ @@ -1392,8 +1392,8 @@ def testB27590179(self): self.bbb.cccccccccc(ddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee) }) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB27266946(self): unformatted_code = textwrap.dedent("""\ @@ -1406,8 +1406,8 @@ def _(): self.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb .cccccccccccccccccccccccccccccccccccc) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB25505359(self): code = textwrap.dedent("""\ @@ -1421,8 +1421,8 @@ def testB25505359(self): }] } """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB25324261(self): code = textwrap.dedent("""\ @@ -1430,8 +1430,8 @@ def testB25324261(self): for ddd in eeeeee.fffffffffff.gggggggggggggggg for cccc in ddd.specification) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB25136704(self): code = textwrap.dedent("""\ @@ -1442,16 +1442,16 @@ def test(self): 'xxxxxx': 'yyyyyy' }] = cccccc.ddd('1m', '10x1+1') """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB25165602(self): code = textwrap.dedent("""\ def f(): ids = {u: i for u, i in zip(self.aaaaa, xrange(42, 42 + len(self.aaaaaa)))} """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB25157123(self): code = textwrap.dedent("""\ @@ -1459,8 +1459,8 @@ def ListArgs(): FairlyLongMethodName([relatively_long_identifier_for_a_list], another_argument_with_a_long_identifier) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB25136820(self): unformatted_code = textwrap.dedent("""\ @@ -1479,8 +1479,8 @@ def foo(): '$bbbbbbbbbbbbbbbbbbbbbbbb', }) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB25131481(self): unformatted_code = textwrap.dedent("""\ @@ -1499,8 +1499,8 @@ def testB25131481(self): lambda x: x # do nothing }) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB23445244(self): unformatted_code = textwrap.dedent("""\ @@ -1526,8 +1526,8 @@ def foo(): FLAGS.aaaaaaaaaaaaaa + FLAGS.bbbbbbbbbbbbbbbbbbb, }) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB20559654(self): unformatted_code = textwrap.dedent("""\ @@ -1547,8 +1547,8 @@ def foo(self): aaaaaaaaaaa=True, bbbbbbbb=None) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB23943842(self): unformatted_code = textwrap.dedent("""\ @@ -1585,8 +1585,8 @@ def f(): } }) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB20551180(self): unformatted_code = textwrap.dedent("""\ @@ -1600,8 +1600,8 @@ def foo(): return (struct.pack('aaaa', bbbbbbbbbb, ccccccccccccccc, dddddddd) + eeeeeee) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB23944849(self): unformatted_code = textwrap.dedent("""\ @@ -1620,8 +1620,8 @@ def xxxxxxxxx(self, fffffffffffffff=0): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB23935890(self): unformatted_code = textwrap.dedent("""\ @@ -1636,8 +1636,8 @@ def functioni(self, aaaaaaa, bbbbbbb, cccccc, dddddddddddddd, eeeeeeeeeeeeeee): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB28414371(self): code = textwrap.dedent("""\ @@ -1661,8 +1661,8 @@ def _(): | m.jjjj() | m.ppppp(m.vvv[0] + m.vvv[1])) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20127686(self): code = textwrap.dedent("""\ @@ -1679,8 +1679,8 @@ def f(): | m.jjjj() | m.ppppp(m.VAL[0] / m.VAL[1])) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20016122(self): unformatted_code = textwrap.dedent("""\ @@ -1697,9 +1697,9 @@ def testB20016122(self): style.CreateStyleFromConfig( '{based_on_style: pep8, split_penalty_import_names: 350}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) @@ -1726,8 +1726,8 @@ def __eq__(self, other): style.CreateStyleFromConfig('{based_on_style: yapf, ' 'split_before_logical_operator: True}')) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -1743,8 +1743,8 @@ def f(): aaaaaa.bbbbbbbbbbbbbbbbbbbb[-1].cccccccccccccc.ddd().eeeeeeee( ffffffffffffff) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB20849933(self): unformatted_code = textwrap.dedent("""\ @@ -1763,8 +1763,8 @@ def main(unused_argv): '%s/cccccc/ddddddddddddddddddd.jar' % (eeeeee.FFFFFFFFFFFFFFFFFF), } """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB20813997(self): code = textwrap.dedent("""\ @@ -1772,8 +1772,8 @@ def myfunc_1(): myarray = numpy.zeros((2, 2, 2)) print(myarray[:, 1, :]) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20605036(self): code = textwrap.dedent("""\ @@ -1786,8 +1786,8 @@ def testB20605036(self): } } """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20562732(self): code = textwrap.dedent("""\ @@ -1798,8 +1798,8 @@ def testB20562732(self): 'Second item', ] """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20128830(self): code = textwrap.dedent("""\ @@ -1818,8 +1818,8 @@ def testB20128830(self): }, } """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20073838(self): code = textwrap.dedent("""\ @@ -1835,8 +1835,8 @@ def do_nothing(self, class_1_count): class_1_name=self.class_1_name, class_1_count=class_1_count)) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19626808(self): code = textwrap.dedent("""\ @@ -1844,8 +1844,8 @@ def testB19626808(self): aaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbb( 'ccccccccccc', ddddddddd='eeeee').fffffffff([ggggggggggggggggggggg]) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19547210(self): code = textwrap.dedent("""\ @@ -1858,8 +1858,8 @@ def testB19547210(self): xxxxxxxxxxxx.yyyyyyyyyyyyyy.zzzzzzzz): continue """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19377034(self): code = textwrap.dedent("""\ @@ -1868,8 +1868,8 @@ def f(): bbbbbbbbbbbbbbb.start >= bbbbbbbbbbbbbbb.end): return False """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19372573(self): code = textwrap.dedent("""\ @@ -1884,8 +1884,8 @@ def f(): try: style.SetGlobalStyle(style.CreatePEP8Style()) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -1894,8 +1894,8 @@ def testB19353268(self): a = {1, 2, 3}[x] b = {'foo': 42, 'bar': 37}['foo'] """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19287512(self): unformatted_code = textwrap.dedent("""\ @@ -1919,8 +1919,8 @@ def bar(self): -1, 'permission error'))): self.assertRaises(nnnnnnnnnnnnnnnn.ooooo, ppppp.qqqqqqqqqqqqqqqqq) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB19194420(self): code = textwrap.dedent("""\ @@ -1928,8 +1928,8 @@ def testB19194420(self): 'long argument goes here that causes the line to break', lambda arg2=0.5: arg2) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19073499(self): code = """\ @@ -1940,8 +1940,8 @@ def testB19073499(self): 'fnord': 6 })) """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB18257115(self): code = textwrap.dedent("""\ @@ -1950,8 +1950,8 @@ def testB18257115(self): self._Test(aaaa, bbbbbbb.cccccccccc, dddddddd, eeeeeeeeeee, [ffff, ggggggggggg, hhhhhhhhhhhh, iiiiii, jjjj]) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB18256666(self): code = textwrap.dedent("""\ @@ -1968,8 +1968,8 @@ def Bar(self): }, llllllllll=mmmmmm.nnnnnnnnnnnnnnnn) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB18256826(self): code = textwrap.dedent("""\ @@ -1987,8 +1987,8 @@ def testB18256826(self): elif False: pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB18255697(self): code = textwrap.dedent("""\ @@ -1998,8 +1998,8 @@ def testB18255697(self): 'YYYYYYYYYYYYYYYY': ['zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'], } """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB17534869(self): unformatted_code = textwrap.dedent("""\ @@ -2012,8 +2012,8 @@ def testB17534869(self): self.assertLess( abs(time.time() - aaaa.bbbbbbbbbbb(datetime.datetime.now())), 1) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB17489866(self): unformatted_code = textwrap.dedent("""\ @@ -2030,8 +2030,8 @@ def f(): return aaaa.bbbbbbbbb( ccccccc=dddddddddddddd({('eeee', 'ffffffff'): str(j)})) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB17133019(self): unformatted_code = textwrap.dedent("""\ @@ -2055,8 +2055,8 @@ def bbbbbbbbbb(self): "eeeeeeeee ffffffffff"), "rb") as gggggggggggggggggggg: print(gggggggggggggggggggg) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB17011869(self): unformatted_code = textwrap.dedent("""\ @@ -2082,8 +2082,8 @@ class SomeClass(object): 'DDDDDDDD': 0.4811 } """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB16783631(self): unformatted_code = textwrap.dedent("""\ @@ -2099,8 +2099,8 @@ def testB16783631(self): ddddddddddddd, eeeeeeeee=self.fffffffffffff) as gggg: pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB16572361(self): unformatted_code = textwrap.dedent("""\ @@ -2116,8 +2116,8 @@ def bar(my_dict_name): 'foo-bar-baz-biz-boo-baa-baa'].IncrementBy.assert_called_once_with( 'foo_bar_baz_boo') """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB15884241(self): unformatted_code = textwrap.dedent("""\ @@ -2140,8 +2140,8 @@ def testB15884241(self): ffffffff=[s.strip() for s in bbb[5].split(",")], gggggg=bbb[6]) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB15697268(self): unformatted_code = textwrap.dedent("""\ @@ -2165,8 +2165,8 @@ def main(unused_argv): bad_slice = ("I am a crazy, no good, string what's too long, etc." + " no really ")[:ARBITRARY_CONSTANT_A] """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB15597568(self): unformatted_code = """\ @@ -2183,8 +2183,8 @@ def testB15597568(self): (", and the process timed out." if did_time_out else ".")) % errorcode) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB15542157(self): unformatted_code = textwrap.dedent("""\ @@ -2194,8 +2194,8 @@ def testB15542157(self): aaaaaaaaaaaa = bbbb.ccccccccccccccc(dddddd.eeeeeeeeeeeeee, ffffffffffffffffff, gggggg.hhhhhhhhhhhhhhhhh) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB15438132(self): unformatted_code = textwrap.dedent("""\ @@ -2229,8 +2229,8 @@ def testB15438132(self): gggggg.hh, iiiiiiiiiiiiiiiiiii.jjjjjjjjjj.kkkkkkk, lllll.mm), nnnnnnnnnn=ooooooo.pppppppppp) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB14468247(self): unformatted_code = """\ @@ -2244,8 +2244,8 @@ def testB14468247(self): b=2, ) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB14406499(self): unformatted_code = textwrap.dedent("""\ @@ -2257,8 +2257,8 @@ def foo1(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6): pass """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB13900309(self): unformatted_code = textwrap.dedent("""\ @@ -2269,8 +2269,8 @@ def testB13900309(self): self.aaaaaaaaaaa( # A comment in the middle of it all. 948.0 / 3600, self.bbb.ccccccccccccccccccccc(dddddddddddddddd.eeee, True)) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) code = textwrap.dedent("""\ aaaaaaaaaa.bbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccccc( @@ -2278,8 +2278,8 @@ def testB13900309(self): CCCCCCC).ddddddddd( # Look! A comment is here. AAAAAAAA - (20 * 60 - 5)) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc().dddddddddddddddddddddddddd(1, 2, 3, 4) @@ -2288,8 +2288,8 @@ def testB13900309(self): aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc( ).dddddddddddddddddddddddddd(1, 2, 3, 4) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc(x).dddddddddddddddddddddddddd(1, 2, 3, 4) @@ -2298,8 +2298,8 @@ def testB13900309(self): aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc( x).dddddddddddddddddddddddddd(1, 2, 3, 4) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx).dddddddddddddddddddddddddd(1, 2, 3, 4) @@ -2308,8 +2308,8 @@ def testB13900309(self): aaaaaaaaaaaaaaaaaaaaaaaa( xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx).dddddddddddddddddddddddddd(1, 2, 3, 4) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa().bbbbbbbbbbbbbbbbbbbbbbbb().ccccccccccccccccccc().\ @@ -2320,8 +2320,8 @@ def testB13900309(self): ).dddddddddddddddddd().eeeeeeeeeeeeeeeeeeeee().fffffffffffffffff( ).gggggggggggggggggg() """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB67935687(self): code = textwrap.dedent("""\ @@ -2329,8 +2329,8 @@ def testB67935687(self): Raw('monarch.BorgTask', '/union/row_operator_action_delay'), {'borg_user': self.borg_user}) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ shelf_renderer.expand_text = text.translate_to_unicode( @@ -2342,8 +2342,8 @@ def testB67935687(self): shelf_renderer.expand_text = text.translate_to_unicode(expand_text % {'creator': creator}) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) if __name__ == '__main__': diff --git a/yapftests/reformatter_facebook_test.py b/yapftests/reformatter_facebook_test.py index 2e6b1d7db..c61f32bf5 100644 --- a/yapftests/reformatter_facebook_test.py +++ b/yapftests/reformatter_facebook_test.py @@ -38,8 +38,8 @@ def overly_long_function_name( def overly_long_function_name(just_one_arg, **kwargs): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDedentClosingBracket(self): unformatted_code = textwrap.dedent("""\ @@ -54,8 +54,8 @@ def overly_long_function_name( ): pass """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBreakAfterOpeningBracketIfContentsTooBig(self): unformatted_code = textwrap.dedent("""\ @@ -70,8 +70,8 @@ def overly_long_function_name( ): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDedentClosingBracketWithComments(self): unformatted_code = textwrap.dedent("""\ @@ -91,8 +91,8 @@ def overly_long_function_name( ): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDedentImportAsNames(self): code = textwrap.dedent("""\ @@ -103,8 +103,8 @@ def testDedentImportAsNames(self): SOME_CONSTANT_NUMBER3, ) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDedentTestListGexp(self): unformatted_code = textwrap.dedent("""\ @@ -141,8 +141,8 @@ def testDedentTestListGexp(self): ) as exception: pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBrokenIdempotency(self): # TODO(ambv): The following behaviour should be fixed. @@ -160,8 +160,8 @@ def testBrokenIdempotency(self): ) as exception: pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(pass0_code) - self.assertCodeEqual(pass1_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(pass0_code) + self.assertCodeEqual(pass1_code, reformatter.Reformat(llines)) pass2_code = textwrap.dedent("""\ try: @@ -171,8 +171,8 @@ def testBrokenIdempotency(self): ) as exception: pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(pass1_code) - self.assertCodeEqual(pass2_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(pass1_code) + self.assertCodeEqual(pass2_code, reformatter.Reformat(llines)) def testIfExprHangingIndent(self): unformatted_code = textwrap.dedent("""\ @@ -194,8 +194,8 @@ def testIfExprHangingIndent(self): ): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSimpleDedenting(self): unformatted_code = textwrap.dedent("""\ @@ -208,8 +208,8 @@ def testSimpleDedenting(self): result.reason_not_added, "current preflight is still running" ) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDedentingWithSubscripts(self): unformatted_code = textwrap.dedent("""\ @@ -231,8 +231,8 @@ def baz(cls, clues_list, effect, constraints, constraint_manager): clues_lists, effect, constraints[0], constraint_manager ) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDedentingCallsWithInnerLists(self): code = textwrap.dedent("""\ @@ -242,8 +242,8 @@ def _(): 'effect': Clue((cls.effect_time, 'apache_host'), effect_line, 40) } """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDedentingListComprehension(self): unformatted_code = textwrap.dedent("""\ @@ -320,8 +320,8 @@ def _pack_results_for_constraint_or(): ('localhost', os.path.join(path, 'node_2.log'), super_parser) ] """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMustSplitDedenting(self): code = textwrap.dedent("""\ @@ -332,8 +332,8 @@ def _(): LineSource('localhost', xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) ) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDedentIfConditional(self): code = textwrap.dedent("""\ @@ -346,8 +346,8 @@ def _(): ): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDedentSet(self): code = textwrap.dedent("""\ @@ -362,8 +362,8 @@ def _(): ] ) """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDedentingInnerScope(self): code = textwrap.dedent("""\ @@ -375,12 +375,12 @@ def _pack_results_for_constraint_or(cls, combination, constraints): constraints, InvestigationResult.OR ) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(code) - reformatted_code = reformatter.Reformat(uwlines) + llines = yapf_test_helper.ParseAndUnwrap(code) + reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, reformatted_code) - uwlines = yapf_test_helper.ParseAndUnwrap(reformatted_code) - reformatted_code = reformatter.Reformat(uwlines) + llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, reformatted_code) def testCommentWithNewlinesInPrefix(self): @@ -409,8 +409,8 @@ def foo(): print(foo()) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testIfStmtClosingBracket(self): unformatted_code = """\ @@ -424,8 +424,8 @@ def testIfStmtClosingBracket(self): ): return False """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) if __name__ == '__main__': diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index b07ae1e3a..acc218d24 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -38,8 +38,8 @@ def testIndent4(self): if a + b: pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSingleLineIfStatements(self): code = textwrap.dedent("""\ @@ -47,8 +47,8 @@ def testSingleLineIfStatements(self): elif False: b = 42 else: c = 42 """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testBlankBetweenClassAndDef(self): unformatted_code = textwrap.dedent("""\ @@ -62,8 +62,8 @@ class Foo: def joe(): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBlankBetweenDefsInClass(self): unformatted_code = textwrap.dedent('''\ @@ -87,8 +87,8 @@ def run(self): def is_running(self): return self.running ''') - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSingleWhiteBeforeTrailingComment(self): unformatted_code = textwrap.dedent("""\ @@ -99,8 +99,8 @@ def testSingleWhiteBeforeTrailingComment(self): if a + b: # comment pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSpaceBetweenEndingCommandAndClosingBracket(self): unformatted_code = textwrap.dedent("""\ @@ -111,8 +111,8 @@ def testSpaceBetweenEndingCommandAndClosingBracket(self): expected_formatted_code = textwrap.dedent("""\ a = (1, ) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testContinuedNonOutdentedLine(self): code = textwrap.dedent("""\ @@ -121,8 +121,8 @@ class eld(d): ) != self.geom_type and not self.geom_type == 'GEOMETRY': ror(code='om_type') """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testWrappingPercentExpressions(self): unformatted_code = textwrap.dedent("""\ @@ -145,8 +145,8 @@ def f(): zzzzz = '%s-%s'.ww(xxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxxxxxx + 1) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testAlignClosingBracketWithVisualIndentation(self): unformatted_code = textwrap.dedent("""\ @@ -161,8 +161,8 @@ def testAlignClosingBracketWithVisualIndentation(self): 'baz' # second comment ) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ def f(): @@ -182,8 +182,8 @@ def g(): yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): pass """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testIndentSizeChanging(self): unformatted_code = textwrap.dedent("""\ @@ -195,8 +195,8 @@ def testIndentSizeChanging(self): runtime_mins = (program_end_time - program_start_time).total_seconds() / 60.0 """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testHangingIndentCollision(self): unformatted_code = textwrap.dedent("""\ @@ -234,8 +234,8 @@ def h(): morestuff.andmore.andmore.andmore.andmore.andmore.andmore.andmore): dosomething(connection) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingBeforeLogicalOperator(self): try: @@ -264,9 +264,9 @@ def foo(): or update.message.migrate_from_chat_id or update.message.pinned_message) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) @@ -282,8 +282,8 @@ def testContiguousListEndingWithComment(self): keys.append( aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) # may be unassigned. """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingBeforeFirstArgument(self): try: @@ -301,9 +301,9 @@ def testSplittingBeforeFirstArgument(self): long_argument_name_3=3, long_argument_name_4=4) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) @@ -317,8 +317,8 @@ def foo(): df = df[(df['campaign_status'] == 'LIVE') & (df['action_status'] == 'LIVE')] """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplitListsAndDictSetMakersIfCommaTerminated(self): unformatted_code = textwrap.dedent("""\ @@ -337,8 +337,8 @@ def testSplitListsAndDictSetMakersIfCommaTerminated(self): "context_processors", ] """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplitAroundNamedAssigns(self): unformatted_code = textwrap.dedent("""\ @@ -355,8 +355,8 @@ def a(): aaaaaaaaaa=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testUnaryOperator(self): unformatted_code = textwrap.dedent("""\ @@ -371,8 +371,8 @@ def testUnaryOperator(self): if -3 < x < 3: pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoSplitBeforeDictValue(self): try: @@ -400,9 +400,9 @@ def testNoSplitBeforeDictValue(self): ), } """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ X = {'a': 1, 'b': 2, 'key': this_is_a_function_call_that_goes_over_the_column_limit_im_pretty_sure()} @@ -414,9 +414,9 @@ def testNoSplitBeforeDictValue(self): 'key': this_is_a_function_call_that_goes_over_the_column_limit_im_pretty_sure() } """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ attrs = { @@ -436,9 +436,9 @@ def testNoSplitBeforeDictValue(self): ), } """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ css_class = forms.CharField( @@ -456,9 +456,9 @@ def testNoSplitBeforeDictValue(self): ), ) """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) @@ -482,8 +482,8 @@ def _(): & (cdffile['Latitude'][:] >= select_lat - radius) & (cdffile['Latitude'][:] <= select_lat + radius)) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertEqual(expected_code, reformatter.Reformat(llines)) def testNoBlankLinesOnlyForFirstNestedObject(self): unformatted_code = '''\ @@ -516,8 +516,8 @@ def bar(self): bar docs """ ''' - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertEqual(expected_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertEqual(expected_code, reformatter.Reformat(llines)) def testSplitBeforeArithmeticOperators(self): try: @@ -534,9 +534,9 @@ def _(): raise ValueError('This is a long message that ends with an argument: ' + str(42)) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) @@ -551,8 +551,8 @@ def testListSplitting(self): (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 10), (1, 11), (1, 10), (1, 11), (10, 11)]) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testNoBlankLineBeforeNestedFuncOrClass(self): try: @@ -589,9 +589,9 @@ class nested_class(): return nested_function ''' - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) @@ -620,8 +620,8 @@ def __init__( self._cs = charset self._preprocess = preprocess """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testParamListIndentationCollision2(self): code = textwrap.dedent("""\ @@ -629,8 +629,8 @@ def simple_pass_function_with_an_extremely_long_name_and_some_arguments( argument0, argument1): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testParamListIndentationCollision3(self): code = textwrap.dedent("""\ @@ -647,8 +647,8 @@ def func2( ): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testTwoWordComparisonOperators(self): unformatted_code = textwrap.dedent("""\ @@ -661,8 +661,8 @@ def testTwoWordComparisonOperators(self): _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl not in {ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj}) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @unittest.skipUnless(not py3compat.PY3, 'Requires Python 2.7') def testAsyncAsNonKeyword(self): @@ -679,8 +679,8 @@ def foo(self): def bar(self): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines, verify=False)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines, verify=False)) def testStableInlinedDictionaryFormatting(self): unformatted_code = textwrap.dedent("""\ @@ -697,12 +697,12 @@ def _(): })) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - reformatted_code = reformatter.Reformat(uwlines) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) - uwlines = yapf_test_helper.ParseAndUnwrap(reformatted_code) - reformatted_code = reformatter.Reformat(uwlines) + llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') @@ -713,8 +713,8 @@ class MyClass(ABC): place: ... """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines, verify=False)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines, verify=False)) @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testSpaceBetweenDictColonAndElipses(self): @@ -726,8 +726,8 @@ def testSpaceBetweenDictColonAndElipses(self): {0: "...", 1: ...} """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) class TestsForSpacesInsideBrackets(yapf_test_helper.YAPFTest): @@ -797,8 +797,8 @@ def testEnabled(self): string_idx = "mystring"[ 3 ] """) - uwlines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDefault(self): style.SetGlobalStyle(style.CreatePEP8Style()) @@ -835,8 +835,8 @@ def testDefault(self): string_idx = "mystring"[3] """) - uwlines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testAwait(self): @@ -870,8 +870,8 @@ async def main(): if ( await get_html() ): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) class TestsForSpacesAroundSubscriptColon(yapf_test_helper.YAPFTest): @@ -904,8 +904,8 @@ def testEnabled(self): d1 = list4[1 : 20 :] e1 = list5[1 : 20 : 3] """) - uwlines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testWithSpaceInsideBrackets(self): style.SetGlobalStyle( @@ -925,8 +925,8 @@ def testWithSpaceInsideBrackets(self): d1 = list4[ 1 : 20 : ] e1 = list5[ 1 : 20 : 3 ] """) - uwlines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDefault(self): style.SetGlobalStyle(style.CreatePEP8Style()) @@ -942,8 +942,8 @@ def testDefault(self): d1 = list4[1:20:] e1 = list5[1:20:3] """) - uwlines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) if __name__ == '__main__': diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index dbf39309a..b5d68e86f 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -44,8 +44,8 @@ def x(aaaaaaaaaaaaaaa: int, eeeeeeeeeeeeee: set = {1, 2, 3}) -> bool: pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testTypedNameWithLongNamedArg(self): unformatted_code = textwrap.dedent("""\ @@ -57,8 +57,8 @@ def func(arg=long_function_call_that_pushes_the_line_over_eighty_characters() ) -> ReturnType: pass """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testKeywordOnlyArgSpecifier(self): unformatted_code = textwrap.dedent("""\ @@ -69,8 +69,8 @@ def foo(a, *, kw): def foo(a, *, kw): return a + kw """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testPEP448ParameterExpansion(self): @@ -86,8 +86,8 @@ def testPEP448ParameterExpansion(self): {**{**x}, **x} {'a': 1, **kw, 'b': 3, **kw2} """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testAnnotations(self): unformatted_code = textwrap.dedent("""\ @@ -98,14 +98,14 @@ def foo(a: list, b: "bar") -> dict: def foo(a: list, b: "bar") -> dict: return a + b """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testExecAsNonKeyword(self): unformatted_code = 'methods.exec( sys.modules[name])\n' expected_formatted_code = 'methods.exec(sys.modules[name])\n' - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testAsyncFunctions(self): if sys.version_info[1] < 5: @@ -126,8 +126,8 @@ async def main(): if (await get_html()): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines, verify=False)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines, verify=False)) def testNoSpacesAroundPowerOperator(self): unformatted_code = textwrap.dedent("""\ @@ -142,9 +142,9 @@ def testNoSpacesAroundPowerOperator(self): style.CreateStyleFromConfig( '{based_on_style: pep8, SPACES_AROUND_POWER_OPERATOR: True}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) @@ -162,9 +162,9 @@ def testSpacesAroundDefaultOrNamedAssign(self): '{based_on_style: pep8, ' 'SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN: True}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) @@ -185,8 +185,8 @@ def foo(x: int = 42): def foo2(x: 'int' = 42): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMatrixMultiplication(self): unformatted_code = textwrap.dedent("""\ @@ -195,15 +195,15 @@ def testMatrixMultiplication(self): expected_formatted_code = textwrap.dedent("""\ a = b @ c """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoneKeyword(self): code = """\ None.__ne__() """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testAsyncWithPrecedingComment(self): if sys.version_info[1] < 5: @@ -230,8 +230,8 @@ async def bar(): async def foo(): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testAsyncFunctionsNested(self): if sys.version_info[1] < 5: @@ -242,8 +242,8 @@ async def outer(): async def inner(): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testKeepTypesIntact(self): if sys.version_info[1] < 5: @@ -260,8 +260,8 @@ def _ReduceAbstractContainers( ) -> List[automation_converter.PyiCollectionAbc]: pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testContinuationIndentWithAsync(self): if sys.version_info[1] < 5: @@ -278,8 +278,8 @@ async def start_websocket(): r"ws://a_really_long_long_long_long_long_long_url") as ws: pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingArguments(self): if sys.version_info[1] < 5: @@ -345,9 +345,9 @@ def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): 'split_arguments_when_comma_terminated: true, ' 'split_before_first_argument: true}')) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) @@ -373,8 +373,8 @@ def foo(self): **foofoofoo }) """ - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMultilineFormatString(self): if sys.version_info[1] < 6: @@ -386,8 +386,8 @@ def testMultilineFormatString(self): # yapf: enable """ # https://github.com/google/yapf/issues/513 - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testEllipses(self): if sys.version_info[1] < 6: @@ -397,8 +397,8 @@ def dirichlet(x12345678901234567890123456789012345678901234567890=...) -> None: return """ # https://github.com/google/yapf/issues/533 - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionTypedReturnNextLine(self): code = """\ @@ -408,8 +408,8 @@ def _GenerateStatsEntries( ) -> Sequence[ssssssssssss.SSSSSSSSSSSSSSS]: pass """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionTypedReturnSameLine(self): code = """\ @@ -417,8 +417,8 @@ def rrrrrrrrrrrrrrrrrrrrrr( ccccccccccccccccccccccc: Tuple[Text, Text]) -> List[Tuple[Text, Text]]: pass """ - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testAsyncForElseNotIndentedInsideBody(self): if sys.version_info[1] < 5: @@ -433,8 +433,8 @@ async def fn(): else: pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testForElseInAsyncNotMixedWithAsyncFor(self): if sys.version_info[1] < 5: @@ -446,8 +446,8 @@ async def fn(): else: pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testParameterListIndentationConflicts(self): unformatted_code = textwrap.dedent("""\ @@ -465,8 +465,8 @@ def raw_message( # pylint: disable=too-many-arguments forward_from=None): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) if __name__ == '__main__': diff --git a/yapftests/reformatter_style_config_test.py b/yapftests/reformatter_style_config_test.py index 9c258ca1e..c5726cb30 100644 --- a/yapftests/reformatter_style_config_test.py +++ b/yapftests/reformatter_style_config_test.py @@ -38,9 +38,9 @@ def testSetGlobalStyle(self): for i in range(5): print('bar') """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) style.DEFAULT_STYLE = self.current_style @@ -53,8 +53,8 @@ def testSetGlobalStyle(self): for i in range(5): print('bar') """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testOperatorNoSpaceStyle(self): try: @@ -71,9 +71,9 @@ def testOperatorNoSpaceStyle(self): b = '0'*1 """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) style.DEFAULT_STYLE = self.current_style @@ -114,9 +114,9 @@ def testOperatorPrecedenceStyle(self): k = (1*2*3) + (4*5*6*7*8) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines)) + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) style.DEFAULT_STYLE = self.current_style @@ -156,8 +156,8 @@ def testNoSplitBeforeFirstArgumentStyle1(self): plt.plot(veryverylongvariablename, veryverylongvariablename, marker="x", color="r") """) # noqa - uwlines = yapf_test_helper.ParseAndUnwrap(formatted_code) - self.assertCodeEqual(formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(formatted_code) + self.assertCodeEqual(formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) style.DEFAULT_STYLE = self.current_style @@ -187,8 +187,8 @@ def testNoSplitBeforeFirstArgumentStyle2(self): marker="x", color="r") """) - uwlines = yapf_test_helper.ParseAndUnwrap(formatted_code) - self.assertCodeEqual(formatted_code, reformatter.Reformat(uwlines)) + llines = yapf_test_helper.ParseAndUnwrap(formatted_code) + self.assertCodeEqual(formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) style.DEFAULT_STYLE = self.current_style diff --git a/yapftests/reformatter_verify_test.py b/yapftests/reformatter_verify_test.py index c10cb8692..33ba3a614 100644 --- a/yapftests/reformatter_verify_test.py +++ b/yapftests/reformatter_verify_test.py @@ -36,10 +36,10 @@ def testVerifyException(self): class ABC(metaclass=type): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) with self.assertRaises(verifier.InternalError): - reformatter.Reformat(uwlines, verify=True) - reformatter.Reformat(uwlines) # verify should be False by default. + reformatter.Reformat(llines, verify=True) + reformatter.Reformat(llines) # verify should be False by default. def testNoVerify(self): unformatted_code = textwrap.dedent("""\ @@ -50,9 +50,9 @@ class ABC(metaclass=type): class ABC(metaclass=type): pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines, verify=False)) + reformatter.Reformat(llines, verify=False)) def testVerifyFutureImport(self): unformatted_code = textwrap.dedent("""\ @@ -64,9 +64,9 @@ def call_my_function(the_function): if __name__ == "__main__": call_my_function(print) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) with self.assertRaises(verifier.InternalError): - reformatter.Reformat(uwlines, verify=True) + reformatter.Reformat(llines, verify=True) expected_formatted_code = textwrap.dedent("""\ from __future__ import print_function @@ -79,9 +79,9 @@ def call_my_function(the_function): if __name__ == "__main__": call_my_function(print) """) - uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(uwlines, verify=False)) + reformatter.Reformat(llines, verify=False)) def testContinuationLineShouldBeDistinguished(self): code = textwrap.dedent("""\ @@ -92,8 +92,8 @@ def bar(self): self.generators + self.next_batch) == 1: pass """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(uwlines, verify=False)) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines, verify=False)) if __name__ == '__main__': diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index 66be68eea..76510611c 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -25,18 +25,18 @@ class SubtypeAssignerTest(yapf_test_helper.YAPFTest): - def _CheckFormatTokenSubtypes(self, uwlines, list_of_expected): - """Check that the tokens in the UnwrappedLines have the expected subtypes. + def _CheckFormatTokenSubtypes(self, llines, list_of_expected): + """Check that the tokens in the LogicalLines have the expected subtypes. Args: - uwlines: list of UnwrappedLine. + llines: list of LogicalLine. list_of_expected: list of (name, subtype) pairs. Non-semantic tokens are filtered out from the expected values. """ actual = [] - for uwl in uwlines: + for lline in llines: filtered_values = [(ft.value, ft.subtypes) - for ft in uwl.tokens + for ft in lline.tokens if ft.name not in pytree_utils.NONSEMANTIC_TOKENS] if filtered_values: actual.append(filtered_values) @@ -49,8 +49,8 @@ def testFuncDefDefaultAssign(self): def foo(a=37, *b, **c): return -x[:42] """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckFormatTokenSubtypes(llines, [ [ ('def', {subtypes.NONE}), ('foo', {subtypes.FUNC_DEF}), @@ -109,8 +109,8 @@ def testFuncCallWithDefaultAssign(self): code = textwrap.dedent(r""" foo(x, a='hello world') """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckFormatTokenSubtypes(llines, [ [ ('foo', {subtypes.NONE}), ('(', {subtypes.NONE}), @@ -134,8 +134,8 @@ def testSetComprehension(self): def foo(strs): return {s.lower() for s in strs} """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckFormatTokenSubtypes(llines, [ [ ('def', {subtypes.NONE}), ('foo', {subtypes.FUNC_DEF}), @@ -171,8 +171,8 @@ def testUnaryNotOperator(self): code = textwrap.dedent("""\ not a """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes(uwlines, + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckFormatTokenSubtypes(llines, [[('not', {subtypes.UNARY_OPERATOR}), ('a', {subtypes.NONE})]]) @@ -180,8 +180,8 @@ def testBitwiseOperators(self): code = textwrap.dedent("""\ x = ((a | (b ^ 3) & c) << 3) >> 1 """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckFormatTokenSubtypes(llines, [ [ ('x', {subtypes.NONE}), ('=', {subtypes.ASSIGN_OPERATOR}), @@ -209,8 +209,8 @@ def testArithmeticOperators(self): code = textwrap.dedent("""\ x = ((a + (b - 3) * (1 % c) @ d) / 3) // 1 """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckFormatTokenSubtypes(llines, [ [ ('x', {subtypes.NONE}), ('=', {subtypes.ASSIGN_OPERATOR}), @@ -250,8 +250,8 @@ def testSubscriptColon(self): code = textwrap.dedent("""\ x[0:42:1] """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckFormatTokenSubtypes(llines, [ [ ('x', {subtypes.NONE}), ('[', {subtypes.SUBSCRIPT_BRACKET}), @@ -268,8 +268,8 @@ def testFunctionCallWithStarExpression(self): code = textwrap.dedent("""\ [a, *b] """) - uwlines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes(uwlines, [ + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckFormatTokenSubtypes(llines, [ [ ('[', {subtypes.NONE}), ('a', {subtypes.NONE}), diff --git a/yapftests/yapf_test_helper.py b/yapftests/yapf_test_helper.py index df89b7013..3d1da126c 100644 --- a/yapftests/yapf_test_helper.py +++ b/yapftests/yapf_test_helper.py @@ -64,7 +64,7 @@ def assertCodeEqual(self, expected_code, code): def ParseAndUnwrap(code, dumptree=False): - """Produces unwrapped lines from the given code. + """Produces logical lines from the given code. Parses the code into a tree, performs comment splicing and runs the unwrapper. @@ -75,7 +75,7 @@ def ParseAndUnwrap(code, dumptree=False): to stderr. Useful for debugging. Returns: - List of unwrapped lines. + List of logical lines. """ tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) @@ -88,8 +88,8 @@ def ParseAndUnwrap(code, dumptree=False): if dumptree: pytree_visitor.DumpPyTree(tree, target_stream=sys.stderr) - uwlines = pytree_unwrapper.UnwrapPyTree(tree) - for uwl in uwlines: - uwl.CalculateFormattingInformation() + llines = pytree_unwrapper.UnwrapPyTree(tree) + for lline in llines: + lline.CalculateFormattingInformation() - return uwlines + return llines From 714e362fdc3e03510e1da4258d760cbefff51bac Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 25 Dec 2021 23:12:34 -0600 Subject: [PATCH 525/719] Reformatting. --- yapf/yapflib/reformatter.py | 9 ++++----- yapftests/subtype_assigner_test.py | 5 ++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 724289484..b6e6a1304 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -67,8 +67,8 @@ def Reformat(llines, verify=False, lines=None): if prev_line and prev_line.disable: # Keep the vertical spacing between a disabled and enabled formatting # region. - _RetainRequiredVerticalSpacingBetweenTokens(lline.first, - prev_line.last, lines) + _RetainRequiredVerticalSpacingBetweenTokens(lline.first, prev_line.last, + lines) if any(tok.is_comment for tok in lline.tokens): _RetainVerticalSpacingBeforeComments(lline) @@ -84,7 +84,7 @@ def Reformat(llines, verify=False, lines=None): _EmitLineUnformatted(state) elif _CanPlaceOnSingleLine(lline) and not any(tok.must_break_before - for tok in lline.tokens): + for tok in lline.tokens): # The logical line fits on one line. while state.next_token: state.AddTokenToState(newline=False, dry_run=False) @@ -749,8 +749,7 @@ def _SingleOrMergedLines(lines): next_line = lines[index + 1] for tok in next_line.tokens: lines[index].AppendToken(tok) - if (len(next_line.tokens) == 1 and - next_line.first.is_multiline_string): + if (len(next_line.tokens) == 1 and next_line.first.is_multiline_string): # This may be a multiline shebang. In that case, we want to retain the # formatting. Otherwise, it could mess up the shell script's syntax. lines[index].disable = True diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index 76510611c..145a96e28 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -172,9 +172,8 @@ def testUnaryNotOperator(self): not a """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes(llines, - [[('not', {subtypes.UNARY_OPERATOR}), - ('a', {subtypes.NONE})]]) + self._CheckFormatTokenSubtypes(llines, [[('not', {subtypes.UNARY_OPERATOR}), + ('a', {subtypes.NONE})]]) def testBitwiseOperators(self): code = textwrap.dedent("""\ From 1aa86c374001d2763cf7c446235855045b4c5222 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 26 Dec 2021 00:49:04 -0600 Subject: [PATCH 526/719] Bump version to 0.32.0 --- CHANGELOG | 2 +- yapf/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ba56ac20b..4e625200f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.32.0] UNRELEASED +## [0.32.0] 2021-12-26 ### Added - Look at the 'pyproject.toml' file to see if it contains ignore file information for YAPF. diff --git a/yapf/__init__.py b/yapf/__init__.py index d09d4c774..0c2fb952c 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.31.0' +__version__ = '0.32.0' def main(argv): From 7974bd2bf6bb5822d21e7ef32f9ea26132a6fdec Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 26 Dec 2021 01:48:20 -0600 Subject: [PATCH 527/719] Fix RST formatting. --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 12286a9dd..087f2ab36 100644 --- a/README.rst +++ b/README.rst @@ -135,9 +135,9 @@ If ``--diff`` is supplied, YAPF returns zero when no changes were necessary, non otherwise (including program error). You can use this in a CI workflow to test that code has been YAPF-formatted. ---------------------------------------------- +--------------------------------------------------------------- Excluding files from formatting (.yapfignore or pyproject.toml) ---------------------------------------------- +--------------------------------------------------------------- In addition to exclude patterns provided on commandline, YAPF looks for additional patterns specified in a file named ``.yapfignore`` or ``pyproject.toml`` located in the From bfdbf804527c05479d15b4e01cb3726e5523db23 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 27 Dec 2021 12:28:46 -0800 Subject: [PATCH 528/719] [file_resources] use "tokenize.detect_encoding" for Python3+ Python3's version of "detect_encoding" is similar to lib2to3's version. --- yapf/yapflib/file_resources.py | 6 ++---- yapf/yapflib/py3compat.py | 6 ++++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 972f48381..b5e2612bd 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -21,8 +21,6 @@ import os import re -from lib2to3.pgen2 import tokenize - from yapf.yapflib import errors from yapf.yapflib import py3compat from yapf.yapflib import style @@ -264,7 +262,7 @@ def IsPythonFile(filename): try: with open(filename, 'rb') as fd: - encoding = tokenize.detect_encoding(fd.readline)[0] + encoding = py3compat.detect_encoding(fd.readline)[0] # Check for correctness of encoding. with py3compat.open_with_encoding( @@ -291,4 +289,4 @@ def IsPythonFile(filename): def FileEncoding(filename): """Return the file's encoding.""" with open(filename, 'rb') as fd: - return tokenize.detect_encoding(fd.readline)[0] + return py3compat.detect_encoding(fd.readline)[0] diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py index 8f1547696..0dff5e194 100644 --- a/yapf/yapflib/py3compat.py +++ b/yapf/yapflib/py3compat.py @@ -47,6 +47,9 @@ def raw_input(): # Mappings from strings to booleans (such as '1' to True, 'false' to False, # etc.) CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser.BOOLEAN_STATES + + import tokenize + detect_encoding = tokenize.detect_encoding else: import __builtin__ import cStringIO @@ -70,6 +73,9 @@ def fake_wrapper(user_function): import ConfigParser as configparser CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser._boolean_states # pylint: disable=protected-access # noqa + from lib2to3.pgen2 import tokenize + detect_encoding = tokenize.detect_encoding + def EncodeAndWriteToStdout(s, encoding='utf-8'): """Encode the given string and emit to stdout. From 17c3e69b12e59d36a027ac53898e4e597e39a5e6 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 27 Dec 2021 12:44:38 -0800 Subject: [PATCH 529/719] [imports] remove unused imports --- yapf/yapflib/format_decision_state.py | 1 - yapf/yapflib/object_state.py | 1 - yapf/yapflib/pytree_unwrapper.py | 1 - yapf/yapflib/reformatter.py | 2 +- yapf/yapflib/split_penalty.py | 1 - yapf/yapflib/subtype_assigner.py | 1 - yapf/yapflib/yapf_api.py | 3 --- 7 files changed, 1 insertion(+), 9 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 74d086175..cbf11b7dc 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -26,7 +26,6 @@ FormatDecisionState: main class exported by this module. """ -from yapf.yapflib import format_token from yapf.yapflib import logical_line from yapf.yapflib import object_state from yapf.yapflib import split_penalty diff --git a/yapf/yapflib/object_state.py b/yapf/yapflib/object_state.py index 07925efa8..ec259e682 100644 --- a/yapf/yapflib/object_state.py +++ b/yapf/yapflib/object_state.py @@ -22,7 +22,6 @@ from __future__ import division from __future__ import print_function -from yapf.yapflib import format_token from yapf.yapflib import py3compat from yapf.yapflib import style from yapf.yapflib import subtypes diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/yapflib/pytree_unwrapper.py index 1b05b0ee2..c3965e84e 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/yapflib/pytree_unwrapper.py @@ -31,7 +31,6 @@ from lib2to3 import pytree from lib2to3.pgen2 import token as grammar_token -from yapf.yapflib import format_token from yapf.yapflib import logical_line from yapf.yapflib import object_state from yapf.yapflib import pytree_utils diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index b6e6a1304..8730b9623 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -20,6 +20,7 @@ """ from __future__ import unicode_literals + import collections import heapq import re @@ -30,7 +31,6 @@ from yapf.yapflib import format_decision_state from yapf.yapflib import format_token from yapf.yapflib import line_joiner -from yapf.yapflib import pytree_utils from yapf.yapflib import style from yapf.yapflib import verifier diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 643ae24f3..821b39390 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -18,7 +18,6 @@ from lib2to3 import pytree from lib2to3.pgen2 import token as grammar_token -from yapf.yapflib import format_token from yapf.yapflib import py3compat from yapf.yapflib import pytree_utils from yapf.yapflib import pytree_visitor diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 7b45586b5..0128f28b0 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -28,7 +28,6 @@ from lib2to3.pgen2 import token as grammar_token from lib2to3.pygram import python_symbols as syms -from yapf.yapflib import format_token from yapf.yapflib import pytree_utils from yapf.yapflib import pytree_visitor from yapf.yapflib import style diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 09c31bcdb..9b2d70d97 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -36,9 +36,6 @@ import re import sys -from lib2to3.pgen2 import parse -from lib2to3.pgen2 import tokenize - from yapf.yapflib import blank_line_calculator from yapf.yapflib import comment_splicer from yapf.yapflib import continuation_splicer From c477857368a239610eb11c35c2dc2aa02c3038ba Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 27 Dec 2021 13:04:22 -0800 Subject: [PATCH 530/719] [pytree] moved 'pytree' parsing tools into its own subdirectory --- CHANGELOG | 4 ++++ yapf/pytree/__init__.py | 13 +++++++++++++ yapf/{yapflib => pytree}/pytree_unwrapper.py | 4 ++-- yapf/{yapflib => pytree}/pytree_utils.py | 0 yapf/{yapflib => pytree}/pytree_visitor.py | 2 +- yapf/yapflib/blank_line_calculator.py | 4 ++-- yapf/yapflib/comment_splicer.py | 2 +- yapf/yapflib/format_token.py | 2 +- yapf/yapflib/identify_container.py | 4 ++-- yapf/yapflib/logical_line.py | 2 +- yapf/yapflib/split_penalty.py | 4 ++-- yapf/yapflib/subtype_assigner.py | 4 ++-- yapf/yapflib/yapf_api.py | 4 ++-- yapftests/comment_splicer_test.py | 2 +- yapftests/format_decision_state_test.py | 2 +- yapftests/pytree_unwrapper_test.py | 2 +- yapftests/pytree_utils_test.py | 2 +- yapftests/pytree_visitor_test.py | 4 ++-- yapftests/split_penalty_test.py | 4 ++-- yapftests/subtype_assigner_test.py | 2 +- yapftests/yapf_test_helper.py | 6 +++--- 21 files changed, 45 insertions(+), 28 deletions(-) create mode 100644 yapf/pytree/__init__.py rename yapf/{yapflib => pytree}/pytree_unwrapper.py (99%) rename yapf/{yapflib => pytree}/pytree_utils.py (100%) rename yapf/{yapflib => pytree}/pytree_visitor.py (99%) diff --git a/CHANGELOG b/CHANGELOG index 4e625200f..1394619cb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.40.0] UNRELEASED +### Changes +- Moved 'pytree' parsing tools into its own subdirectory. + ## [0.32.0] 2021-12-26 ### Added - Look at the 'pyproject.toml' file to see if it contains ignore file information diff --git a/yapf/pytree/__init__.py b/yapf/pytree/__init__.py new file mode 100644 index 000000000..8aa1c83c4 --- /dev/null +++ b/yapf/pytree/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2021 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/yapf/yapflib/pytree_unwrapper.py b/yapf/pytree/pytree_unwrapper.py similarity index 99% rename from yapf/yapflib/pytree_unwrapper.py rename to yapf/pytree/pytree_unwrapper.py index c3965e84e..3ae6cd661 100644 --- a/yapf/yapflib/pytree_unwrapper.py +++ b/yapf/pytree/pytree_unwrapper.py @@ -31,10 +31,10 @@ from lib2to3 import pytree from lib2to3.pgen2 import token as grammar_token +from yapf.pytree import pytree_utils +from yapf.pytree import pytree_visitor from yapf.yapflib import logical_line from yapf.yapflib import object_state -from yapf.yapflib import pytree_utils -from yapf.yapflib import pytree_visitor from yapf.yapflib import split_penalty from yapf.yapflib import style from yapf.yapflib import subtypes diff --git a/yapf/yapflib/pytree_utils.py b/yapf/pytree/pytree_utils.py similarity index 100% rename from yapf/yapflib/pytree_utils.py rename to yapf/pytree/pytree_utils.py diff --git a/yapf/yapflib/pytree_visitor.py b/yapf/pytree/pytree_visitor.py similarity index 99% rename from yapf/yapflib/pytree_visitor.py rename to yapf/pytree/pytree_visitor.py index a39331cc3..314431e84 100644 --- a/yapf/yapflib/pytree_visitor.py +++ b/yapf/pytree/pytree_visitor.py @@ -28,7 +28,7 @@ from lib2to3 import pytree -from yapf.yapflib import pytree_utils +from yapf.pytree import pytree_utils class PyTreeVisitor(object): diff --git a/yapf/yapflib/blank_line_calculator.py b/yapf/yapflib/blank_line_calculator.py index 3d78646ea..9d218bf97 100644 --- a/yapf/yapflib/blank_line_calculator.py +++ b/yapf/yapflib/blank_line_calculator.py @@ -24,9 +24,9 @@ from lib2to3.pgen2 import token as grammar_token +from yapf.pytree import pytree_utils +from yapf.pytree import pytree_visitor from yapf.yapflib import py3compat -from yapf.yapflib import pytree_utils -from yapf.yapflib import pytree_visitor from yapf.yapflib import style _NO_BLANK_LINES = 1 diff --git a/yapf/yapflib/comment_splicer.py b/yapf/yapflib/comment_splicer.py index 535711b21..ae5ffe66f 100644 --- a/yapf/yapflib/comment_splicer.py +++ b/yapf/yapflib/comment_splicer.py @@ -25,7 +25,7 @@ from lib2to3 import pytree from lib2to3.pgen2 import token -from yapf.yapflib import pytree_utils +from yapf.pytree import pytree_utils def SpliceComments(tree): diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 487f3a948..d01a7bc42 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -21,8 +21,8 @@ from lib2to3.pgen2 import token +from yapf.pytree import pytree_utils from yapf.yapflib import py3compat -from yapf.yapflib import pytree_utils from yapf.yapflib import style from yapf.yapflib import subtypes diff --git a/yapf/yapflib/identify_container.py b/yapf/yapflib/identify_container.py index 888dbbb54..d027cc5d4 100644 --- a/yapf/yapflib/identify_container.py +++ b/yapf/yapflib/identify_container.py @@ -21,8 +21,8 @@ from lib2to3.pgen2 import token as grammar_token -from yapf.yapflib import pytree_utils -from yapf.yapflib import pytree_visitor +from yapf.pytree import pytree_utils +from yapf.pytree import pytree_visitor def IdentifyContainers(tree): diff --git a/yapf/yapflib/logical_line.py b/yapf/yapflib/logical_line.py index 5723440d8..b91cfef80 100644 --- a/yapf/yapflib/logical_line.py +++ b/yapf/yapflib/logical_line.py @@ -19,9 +19,9 @@ perform the wrapping required to comply with the style guide. """ +from yapf.pytree import pytree_utils from yapf.yapflib import format_token from yapf.yapflib import py3compat -from yapf.yapflib import pytree_utils from yapf.yapflib import split_penalty from yapf.yapflib import style from yapf.yapflib import subtypes diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 821b39390..5104d2dc9 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -18,9 +18,9 @@ from lib2to3 import pytree from lib2to3.pgen2 import token as grammar_token +from yapf.pytree import pytree_utils +from yapf.pytree import pytree_visitor from yapf.yapflib import py3compat -from yapf.yapflib import pytree_utils -from yapf.yapflib import pytree_visitor from yapf.yapflib import style from yapf.yapflib import subtypes diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py index 0128f28b0..dd3ea3d1e 100644 --- a/yapf/yapflib/subtype_assigner.py +++ b/yapf/yapflib/subtype_assigner.py @@ -28,8 +28,8 @@ from lib2to3.pgen2 import token as grammar_token from lib2to3.pygram import python_symbols as syms -from yapf.yapflib import pytree_utils -from yapf.yapflib import pytree_visitor +from yapf.pytree import pytree_utils +from yapf.pytree import pytree_visitor from yapf.yapflib import style from yapf.yapflib import subtypes diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 9b2d70d97..804c9d547 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -36,6 +36,8 @@ import re import sys +from yapf.pytree import pytree_unwrapper +from yapf.pytree import pytree_utils from yapf.yapflib import blank_line_calculator from yapf.yapflib import comment_splicer from yapf.yapflib import continuation_splicer @@ -43,8 +45,6 @@ from yapf.yapflib import file_resources from yapf.yapflib import identify_container from yapf.yapflib import py3compat -from yapf.yapflib import pytree_unwrapper -from yapf.yapflib import pytree_utils from yapf.yapflib import reformatter from yapf.yapflib import split_penalty from yapf.yapflib import style diff --git a/yapftests/comment_splicer_test.py b/yapftests/comment_splicer_test.py index aacc8882c..58bae9e08 100644 --- a/yapftests/comment_splicer_test.py +++ b/yapftests/comment_splicer_test.py @@ -16,9 +16,9 @@ import textwrap import unittest +from yapf.pytree import pytree_utils from yapf.yapflib import comment_splicer from yapf.yapflib import py3compat -from yapf.yapflib import pytree_utils class CommentSplicerTest(unittest.TestCase): diff --git a/yapftests/format_decision_state_test.py b/yapftests/format_decision_state_test.py index 9d6226738..3bff578da 100644 --- a/yapftests/format_decision_state_test.py +++ b/yapftests/format_decision_state_test.py @@ -16,9 +16,9 @@ import textwrap import unittest +from yapf.pytree import pytree_utils from yapf.yapflib import format_decision_state from yapf.yapflib import logical_line -from yapf.yapflib import pytree_utils from yapf.yapflib import style from yapftests import yapf_test_helper diff --git a/yapftests/pytree_unwrapper_test.py b/yapftests/pytree_unwrapper_test.py index b6ab80977..525278def 100644 --- a/yapftests/pytree_unwrapper_test.py +++ b/yapftests/pytree_unwrapper_test.py @@ -16,7 +16,7 @@ import textwrap import unittest -from yapf.yapflib import pytree_utils +from yapf.pytree import pytree_utils from yapftests import yapf_test_helper diff --git a/yapftests/pytree_utils_test.py b/yapftests/pytree_utils_test.py index 3b9fde7f0..c175f833e 100644 --- a/yapftests/pytree_utils_test.py +++ b/yapftests/pytree_utils_test.py @@ -19,7 +19,7 @@ from lib2to3 import pytree from lib2to3.pgen2 import token -from yapf.yapflib import pytree_utils +from yapf.pytree import pytree_utils # More direct access to the symbol->number mapping living within the grammar # module. diff --git a/yapftests/pytree_visitor_test.py b/yapftests/pytree_visitor_test.py index 1908249d4..45a83b113 100644 --- a/yapftests/pytree_visitor_test.py +++ b/yapftests/pytree_visitor_test.py @@ -15,9 +15,9 @@ import unittest +from yapf.pytree import pytree_utils +from yapf.pytree import pytree_visitor from yapf.yapflib import py3compat -from yapf.yapflib import pytree_utils -from yapf.yapflib import pytree_visitor class _NodeNameCollector(pytree_visitor.PyTreeVisitor): diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index 4d551291e..1c4713292 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -19,8 +19,8 @@ from lib2to3 import pytree -from yapf.yapflib import pytree_utils -from yapf.yapflib import pytree_visitor +from yapf.pytree import pytree_utils +from yapf.pytree import pytree_visitor from yapf.yapflib import split_penalty from yapf.yapflib import style diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index 145a96e28..8616169c9 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -16,8 +16,8 @@ import textwrap import unittest +from yapf.pytree import pytree_utils from yapf.yapflib import format_token -from yapf.yapflib import pytree_utils from yapf.yapflib import subtypes from yapftests import yapf_test_helper diff --git a/yapftests/yapf_test_helper.py b/yapftests/yapf_test_helper.py index 3d1da126c..5c084c6ff 100644 --- a/yapftests/yapf_test_helper.py +++ b/yapftests/yapf_test_helper.py @@ -17,14 +17,14 @@ import sys import unittest +from yapf.pytree import pytree_unwrapper +from yapf.pytree import pytree_utils +from yapf.pytree import pytree_visitor from yapf.yapflib import blank_line_calculator from yapf.yapflib import comment_splicer from yapf.yapflib import continuation_splicer from yapf.yapflib import identify_container from yapf.yapflib import py3compat -from yapf.yapflib import pytree_unwrapper -from yapf.yapflib import pytree_utils -from yapf.yapflib import pytree_visitor from yapf.yapflib import split_penalty from yapf.yapflib import style from yapf.yapflib import subtype_assigner From ec86bc28f02386b45858ede5c5b5f4dbf820ec85 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 1 Jan 2022 17:00:17 -0800 Subject: [PATCH 531/719] Move pytree-specific visitors to appropriate subdirectory --- yapf/{yapflib => pytree}/blank_line_calculator.py | 0 yapf/{yapflib => pytree}/comment_splicer.py | 0 yapf/{yapflib => pytree}/continuation_splicer.py | 0 yapf/pytree/pytree_unwrapper.py | 2 +- yapf/{yapflib => pytree}/split_penalty.py | 0 yapf/{yapflib => pytree}/subtype_assigner.py | 0 yapf/yapflib/format_decision_state.py | 2 +- yapf/yapflib/logical_line.py | 2 +- yapf/yapflib/yapf_api.py | 10 +++++----- yapftests/comment_splicer_test.py | 3 ++- yapftests/format_decision_state_test.py | 1 + yapftests/logical_line_test.py | 2 +- yapftests/split_penalty_test.py | 2 +- yapftests/yapf_test_helper.py | 10 +++++----- 14 files changed, 18 insertions(+), 16 deletions(-) rename yapf/{yapflib => pytree}/blank_line_calculator.py (100%) rename yapf/{yapflib => pytree}/comment_splicer.py (100%) rename yapf/{yapflib => pytree}/continuation_splicer.py (100%) rename yapf/{yapflib => pytree}/split_penalty.py (100%) rename yapf/{yapflib => pytree}/subtype_assigner.py (100%) diff --git a/yapf/yapflib/blank_line_calculator.py b/yapf/pytree/blank_line_calculator.py similarity index 100% rename from yapf/yapflib/blank_line_calculator.py rename to yapf/pytree/blank_line_calculator.py diff --git a/yapf/yapflib/comment_splicer.py b/yapf/pytree/comment_splicer.py similarity index 100% rename from yapf/yapflib/comment_splicer.py rename to yapf/pytree/comment_splicer.py diff --git a/yapf/yapflib/continuation_splicer.py b/yapf/pytree/continuation_splicer.py similarity index 100% rename from yapf/yapflib/continuation_splicer.py rename to yapf/pytree/continuation_splicer.py diff --git a/yapf/pytree/pytree_unwrapper.py b/yapf/pytree/pytree_unwrapper.py index 3ae6cd661..f519c2de9 100644 --- a/yapf/pytree/pytree_unwrapper.py +++ b/yapf/pytree/pytree_unwrapper.py @@ -33,9 +33,9 @@ from yapf.pytree import pytree_utils from yapf.pytree import pytree_visitor +from yapf.pytree import split_penalty from yapf.yapflib import logical_line from yapf.yapflib import object_state -from yapf.yapflib import split_penalty from yapf.yapflib import style from yapf.yapflib import subtypes diff --git a/yapf/yapflib/split_penalty.py b/yapf/pytree/split_penalty.py similarity index 100% rename from yapf/yapflib/split_penalty.py rename to yapf/pytree/split_penalty.py diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/pytree/subtype_assigner.py similarity index 100% rename from yapf/yapflib/subtype_assigner.py rename to yapf/pytree/subtype_assigner.py diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index cbf11b7dc..c299d1c85 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -26,9 +26,9 @@ FormatDecisionState: main class exported by this module. """ +from yapf.pytree import split_penalty from yapf.yapflib import logical_line from yapf.yapflib import object_state -from yapf.yapflib import split_penalty from yapf.yapflib import style from yapf.yapflib import subtypes diff --git a/yapf/yapflib/logical_line.py b/yapf/yapflib/logical_line.py index b91cfef80..9440b185c 100644 --- a/yapf/yapflib/logical_line.py +++ b/yapf/yapflib/logical_line.py @@ -20,9 +20,9 @@ """ from yapf.pytree import pytree_utils +from yapf.pytree import split_penalty from yapf.yapflib import format_token from yapf.yapflib import py3compat -from yapf.yapflib import split_penalty from yapf.yapflib import style from yapf.yapflib import subtypes diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 804c9d547..37b13fc8c 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -38,17 +38,17 @@ from yapf.pytree import pytree_unwrapper from yapf.pytree import pytree_utils -from yapf.yapflib import blank_line_calculator -from yapf.yapflib import comment_splicer -from yapf.yapflib import continuation_splicer +from yapf.pytree import blank_line_calculator +from yapf.pytree import comment_splicer +from yapf.pytree import continuation_splicer +from yapf.pytree import split_penalty +from yapf.pytree import subtype_assigner from yapf.yapflib import errors from yapf.yapflib import file_resources from yapf.yapflib import identify_container from yapf.yapflib import py3compat from yapf.yapflib import reformatter -from yapf.yapflib import split_penalty from yapf.yapflib import style -from yapf.yapflib import subtype_assigner def FormatFile(filename, diff --git a/yapftests/comment_splicer_test.py b/yapftests/comment_splicer_test.py index 58bae9e08..2e0141bd4 100644 --- a/yapftests/comment_splicer_test.py +++ b/yapftests/comment_splicer_test.py @@ -17,7 +17,8 @@ import unittest from yapf.pytree import pytree_utils -from yapf.yapflib import comment_splicer +from yapf.pytree import comment_splicer + from yapf.yapflib import py3compat diff --git a/yapftests/format_decision_state_test.py b/yapftests/format_decision_state_test.py index 3bff578da..63961f332 100644 --- a/yapftests/format_decision_state_test.py +++ b/yapftests/format_decision_state_test.py @@ -17,6 +17,7 @@ import unittest from yapf.pytree import pytree_utils + from yapf.yapflib import format_decision_state from yapf.yapflib import logical_line from yapf.yapflib import style diff --git a/yapftests/logical_line_test.py b/yapftests/logical_line_test.py index 6876efe0f..c799ff000 100644 --- a/yapftests/logical_line_test.py +++ b/yapftests/logical_line_test.py @@ -19,9 +19,9 @@ from lib2to3 import pytree from lib2to3.pgen2 import token +from yapf.pytree import split_penalty from yapf.yapflib import format_token from yapf.yapflib import logical_line -from yapf.yapflib import split_penalty from yapftests import yapf_test_helper diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index 1c4713292..f7474a398 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -21,7 +21,7 @@ from yapf.pytree import pytree_utils from yapf.pytree import pytree_visitor -from yapf.yapflib import split_penalty +from yapf.pytree import split_penalty from yapf.yapflib import style from yapftests import yapf_test_helper diff --git a/yapftests/yapf_test_helper.py b/yapftests/yapf_test_helper.py index 5c084c6ff..cb56ec865 100644 --- a/yapftests/yapf_test_helper.py +++ b/yapftests/yapf_test_helper.py @@ -17,17 +17,17 @@ import sys import unittest +from yapf.pytree import blank_line_calculator +from yapf.pytree import comment_splicer +from yapf.pytree import continuation_splicer from yapf.pytree import pytree_unwrapper from yapf.pytree import pytree_utils from yapf.pytree import pytree_visitor -from yapf.yapflib import blank_line_calculator -from yapf.yapflib import comment_splicer -from yapf.yapflib import continuation_splicer +from yapf.pytree import split_penalty +from yapf.pytree import subtype_assigner from yapf.yapflib import identify_container from yapf.yapflib import py3compat -from yapf.yapflib import split_penalty from yapf.yapflib import style -from yapf.yapflib import subtype_assigner class YAPFTest(unittest.TestCase): From c4262724e01ff5e360c10339fdbfade824ceb6b6 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 1 Jan 2022 17:21:09 -0800 Subject: [PATCH 532/719] Remove "AppendNode", which wasn't that useful --- yapf/pytree/pytree_unwrapper.py | 3 ++- yapf/yapflib/format_token.py | 9 +++------ yapf/yapflib/logical_line.py | 10 ---------- yapftests/logical_line_test.py | 6 ------ 4 files changed, 5 insertions(+), 23 deletions(-) diff --git a/yapf/pytree/pytree_unwrapper.py b/yapf/pytree/pytree_unwrapper.py index f519c2de9..02fb8125f 100644 --- a/yapf/pytree/pytree_unwrapper.py +++ b/yapf/pytree/pytree_unwrapper.py @@ -34,6 +34,7 @@ from yapf.pytree import pytree_utils from yapf.pytree import pytree_visitor from yapf.pytree import split_penalty +from yapf.yapflib import format_token from yapf.yapflib import logical_line from yapf.yapflib import object_state from yapf.yapflib import style @@ -293,7 +294,7 @@ def DefaultLeafVisit(self, leaf): self._StartNewLine() elif leaf.type != grammar_token.COMMENT or leaf.value.strip(): # Add non-whitespace tokens and comments that aren't empty. - self._cur_logical_line.AppendNode(leaf) + self._cur_logical_line.AppendToken(format_token.FormatToken(leaf)) _BRACKET_MATCH = {')': '(', '}': '{', ']': '['} diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index d01a7bc42..4bac8418d 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -11,10 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -"""Pytree nodes with extra formatting information. - -This is a thin wrapper around a pytree.Leaf node. -""" +"""Enhanced token information for formatting.""" import keyword import re @@ -48,13 +45,13 @@ def _TabbedContinuationAlignPadding(spaces, align_style, tab_width): class FormatToken(object): - """A wrapper around pytree Leaf nodes. + """Enhanced token information for formatting. This represents the token plus additional information useful for reformatting the code. Attributes: - node: The PyTree node this token represents. + node: The original token node. next_token: The token in the logical line after this token or None if this is the last token in the logical line. previous_token: The token in the logical line before this token or None if diff --git a/yapf/yapflib/logical_line.py b/yapf/yapflib/logical_line.py index 9440b185c..f4f3ce6da 100644 --- a/yapf/yapflib/logical_line.py +++ b/yapf/yapflib/logical_line.py @@ -135,16 +135,6 @@ def AppendToken(self, token): self.last.next_token = token self._tokens.append(token) - def AppendNode(self, node): - """Convenience method to append a pytree node directly. - - Wraps the node with a FormatToken. - - Arguments: - node: the node to append - """ - self.AppendToken(format_token.FormatToken(node)) - @property def first(self): """Returns the first non-whitespace token.""" diff --git a/yapftests/logical_line_test.py b/yapftests/logical_line_test.py index c799ff000..ca921d225 100644 --- a/yapftests/logical_line_test.py +++ b/yapftests/logical_line_test.py @@ -54,12 +54,6 @@ def testAppendToken(self): lline.AppendToken(_MakeFormatTokenLeaf(token.RPAR, ')')) self.assertEqual(['LPAR', 'RPAR'], [tok.name for tok in lline.tokens]) - def testAppendNode(self): - lline = logical_line.LogicalLine(0) - lline.AppendNode(pytree.Leaf(token.LPAR, '(')) - lline.AppendNode(pytree.Leaf(token.RPAR, ')')) - self.assertEqual(['LPAR', 'RPAR'], [tok.name for tok in lline.tokens]) - class LogicalLineFormattingInformationTest(yapf_test_helper.YAPFTest): From 4abc6944a6f737eedd4444db6eae15b400a99f25 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 1 Jan 2022 17:22:18 -0800 Subject: [PATCH 533/719] Use OpensScope/ClosesScope instead of testing token's text --- yapf/pytree/pytree_unwrapper.py | 11 +++++++---- yapf/pytree/pytree_utils.py | 3 --- yapf/yapflib/format_token.py | 7 +++++-- yapf/yapflib/logical_line.py | 22 ++++++++++------------ 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/yapf/pytree/pytree_unwrapper.py b/yapf/pytree/pytree_unwrapper.py index 02fb8125f..39dceac5f 100644 --- a/yapf/pytree/pytree_unwrapper.py +++ b/yapf/pytree/pytree_unwrapper.py @@ -40,6 +40,9 @@ from yapf.yapflib import style from yapf.yapflib import subtypes +_OPENING_BRACKETS = frozenset({'(', '[', '{'}) +_CLOSING_BRACKETS = frozenset({')', ']', '}'}) + def UnwrapPyTree(tree): """Create and return a list of logical lines from the given pytree. @@ -312,9 +315,9 @@ def _MatchBrackets(line): """ bracket_stack = [] for token in line.tokens: - if token.value in pytree_utils.OPENING_BRACKETS: + if token.value in _OPENING_BRACKETS: bracket_stack.append(token) - elif token.value in pytree_utils.CLOSING_BRACKETS: + elif token.value in _CLOSING_BRACKETS: bracket_stack[-1].matching_bracket = token token.matching_bracket = bracket_stack[-1] bracket_stack.pop() @@ -373,9 +376,9 @@ def _AdjustSplitPenalty(line): pytree_utils.SetNodeAnnotation(token.node, pytree_utils.Annotation.SPLIT_PENALTY, split_penalty.UNBREAKABLE) - if token.value in pytree_utils.OPENING_BRACKETS: + if token.value in _OPENING_BRACKETS: bracket_level += 1 - elif token.value in pytree_utils.CLOSING_BRACKETS: + elif token.value in _CLOSING_BRACKETS: bracket_level -= 1 diff --git a/yapf/pytree/pytree_utils.py b/yapf/pytree/pytree_utils.py index 876203208..66a54e617 100644 --- a/yapf/pytree/pytree_utils.py +++ b/yapf/pytree/pytree_utils.py @@ -39,9 +39,6 @@ # unwrapper. NONSEMANTIC_TOKENS = frozenset(['DEDENT', 'INDENT', 'NEWLINE', 'ENDMARKER']) -OPENING_BRACKETS = frozenset({'(', '[', '{'}) -CLOSING_BRACKETS = frozenset({')', ']', '}'}) - class Annotation(object): """Annotation names associated with pytrees.""" diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 4bac8418d..2c38e969d 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -25,6 +25,9 @@ CONTINUATION = token.N_TOKENS +_OPENING_BRACKETS = frozenset({'(', '[', '{'}) +_CLOSING_BRACKETS = frozenset({')', ']', '}'}) + def _TabbedContinuationAlignPadding(spaces, align_style, tab_width): """Build padding string for continuation alignment in tabbed indentation. @@ -207,10 +210,10 @@ def RetainHorizontalSpacing(self, first_column, depth): self.spaces_required_before = cur_column - (prev_column + prev_len) def OpensScope(self): - return self.value in pytree_utils.OPENING_BRACKETS + return self.value in _OPENING_BRACKETS def ClosesScope(self): - return self.value in pytree_utils.CLOSING_BRACKETS + return self.value in _CLOSING_BRACKETS def AddSubtype(self, subtype): self.subtypes.add(subtype) diff --git a/yapf/yapflib/logical_line.py b/yapf/yapflib/logical_line.py index f4f3ce6da..53c345ab0 100644 --- a/yapf/yapflib/logical_line.py +++ b/yapf/yapflib/logical_line.py @@ -302,9 +302,9 @@ def _SpaceRequiredBetween(left, right, is_line_disabled): return True if style.Get('SPACE_INSIDE_BRACKETS'): # Supersede the "no space before a colon or comma" check. - if lval in pytree_utils.OPENING_BRACKETS and rval == ':': + if left.OpensScope() and rval == ':': return True - if rval in pytree_utils.CLOSING_BRACKETS and lval == ':': + if right.ClosesScope() and lval == ':': return True if (style.Get('SPACES_AROUND_SUBSCRIPT_COLON') and (_IsSubscriptColonAndValuePair(left, right) or @@ -355,7 +355,7 @@ def _SpaceRequiredBetween(left, right, is_line_disabled): # A string followed by something other than a subscript, closing bracket, # dot, or a binary op should have a space after it. return True - if rval in pytree_utils.CLOSING_BRACKETS: + if right.ClosesScope(): # A string followed by closing brackets should have a space after it # depending on SPACE_INSIDE_BRACKETS. A string followed by opening # brackets, however, should not. @@ -439,28 +439,26 @@ def _SpaceRequiredBetween(left, right, is_line_disabled): (rval == ')' and _IsDictListTupleDelimiterTok(right, is_opening=False)))): return True - if (lval in pytree_utils.OPENING_BRACKETS and - rval in pytree_utils.OPENING_BRACKETS): + if left.OpensScope() and right.OpensScope(): # Nested objects' opening brackets shouldn't be separated, unless enabled # by SPACE_INSIDE_BRACKETS. return style.Get('SPACE_INSIDE_BRACKETS') - if (lval in pytree_utils.CLOSING_BRACKETS and - rval in pytree_utils.CLOSING_BRACKETS): + if left.ClosesScope() and right.ClosesScope(): # Nested objects' closing brackets shouldn't be separated, unless enabled # by SPACE_INSIDE_BRACKETS. return style.Get('SPACE_INSIDE_BRACKETS') - if lval in pytree_utils.CLOSING_BRACKETS and rval in '([': + if left.ClosesScope() and rval in '([': # A call, set, dictionary, or subscript that has a call or subscript after # it shouldn't have a space between them. return False - if lval in pytree_utils.OPENING_BRACKETS and _IsIdNumberStringToken(right): + if left.OpensScope() and _IsIdNumberStringToken(right): # Don't separate the opening bracket from the first item, unless enabled # by SPACE_INSIDE_BRACKETS. return style.Get('SPACE_INSIDE_BRACKETS') if left.is_name and rval in '([': # Don't separate a call or array access from the name. return False - if rval in pytree_utils.CLOSING_BRACKETS: + if right.ClosesScope(): # Don't separate the closing bracket from the last item, unless enabled # by SPACE_INSIDE_BRACKETS. # FIXME(morbo): This might be too permissive. @@ -468,11 +466,11 @@ def _SpaceRequiredBetween(left, right, is_line_disabled): if lval == 'print' and rval == '(': # Special support for the 'print' function. return False - if lval in pytree_utils.OPENING_BRACKETS and _IsUnaryOperator(right): + if left.OpensScope() and _IsUnaryOperator(right): # Don't separate a unary operator from the opening bracket, unless enabled # by SPACE_INSIDE_BRACKETS. return style.Get('SPACE_INSIDE_BRACKETS') - if (lval in pytree_utils.OPENING_BRACKETS and + if (left.OpensScope() and (subtypes.VARARGS_STAR in right.subtypes or subtypes.KWARGS_STAR_STAR in right.subtypes)): # Don't separate a '*' or '**' from the opening bracket, unless enabled From 732e5b93961dcf815093e84df848c8fd47a84b31 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sun, 2 Jan 2022 03:54:34 +0200 Subject: [PATCH 534/719] Add support for Python 3.10 (#986) * Add support for Python 3.10 * YAPF supports Python 2.7 and 3.6.4+ * Add support for Python 3.10 --- .github/workflows/ci.yml | 2 +- CHANGELOG | 1 + setup.py | 4 ++++ tox.ini | 2 +- yapf/yapflib/yapf_api.py | 4 ++-- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 280af4335..c219c3860 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [2.7, 3.7, 3.8, 3.9] + python-version: ["2.7", "3.7", "3.8", "3.9", "3.10"] os: [ubuntu-latest, macos-latest] steps: diff --git a/CHANGELOG b/CHANGELOG index 1394619cb..fb38ff58e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,7 @@ ## [0.40.0] UNRELEASED ### Changes - Moved 'pytree' parsing tools into its own subdirectory. +- Add support for Python 3.10. ## [0.32.0] 2021-12-26 ### Added diff --git a/setup.py b/setup.py index 70e57da68..8b00835ab 100644 --- a/setup.py +++ b/setup.py @@ -61,6 +61,10 @@ def run(self): 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Quality Assurance', ], diff --git a/tox.ini b/tox.ini index f42b884f0..5134916dc 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist=py27,py34,py35,py36,py37,py38 +envlist=py27,py36,py37,py38,py39,py310 [testenv] commands= diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 37b13fc8c..c17451434 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -198,12 +198,12 @@ def FormatCode(unformatted_source, def _CheckPythonVersion(): # pragma: no cover - errmsg = 'yapf is only supported for Python 2.7 or 3.4+' + errmsg = 'yapf is only supported for Python 2.7 or 3.6+' if sys.version_info[0] == 2: if sys.version_info[1] < 7: raise RuntimeError(errmsg) elif sys.version_info[0] == 3: - if sys.version_info[1] < 4: + if sys.version_info[1] < 6: raise RuntimeError(errmsg) From b8db953d55d64c40f5d8bdfad4762c6b72cfbd30 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 3 Jan 2022 18:49:56 -0800 Subject: [PATCH 535/719] Reformat --- yapf/yapflib/logical_line.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/yapf/yapflib/logical_line.py b/yapf/yapflib/logical_line.py index 53c345ab0..8c84b7ba8 100644 --- a/yapf/yapflib/logical_line.py +++ b/yapf/yapflib/logical_line.py @@ -470,9 +470,8 @@ def _SpaceRequiredBetween(left, right, is_line_disabled): # Don't separate a unary operator from the opening bracket, unless enabled # by SPACE_INSIDE_BRACKETS. return style.Get('SPACE_INSIDE_BRACKETS') - if (left.OpensScope() and - (subtypes.VARARGS_STAR in right.subtypes or - subtypes.KWARGS_STAR_STAR in right.subtypes)): + if (left.OpensScope() and (subtypes.VARARGS_STAR in right.subtypes or + subtypes.KWARGS_STAR_STAR in right.subtypes)): # Don't separate a '*' or '**' from the opening bracket, unless enabled # by SPACE_INSIDE_BRACKETS. return style.Get('SPACE_INSIDE_BRACKETS') From 577d43f977d18d5fe7d879d62d508d40b7723386 Mon Sep 17 00:00:00 2001 From: Nuri Jung Date: Wed, 12 Jan 2022 04:25:35 +0900 Subject: [PATCH 536/719] Split line before all comparison operators (#988) Split line before all comparison operators --- CHANGELOG | 2 ++ yapf/pytree/split_penalty.py | 5 ++++- yapftests/reformatter_basic_test.py | 25 +++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index fb38ff58e..1bfa7f627 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,8 @@ ### Changes - Moved 'pytree' parsing tools into its own subdirectory. - Add support for Python 3.10. +### Fixed +- Split line before all comparison operators. ## [0.32.0] 2021-12-26 ### Added diff --git a/yapf/pytree/split_penalty.py b/yapf/pytree/split_penalty.py index 5104d2dc9..b53ffbf85 100644 --- a/yapf/pytree/split_penalty.py +++ b/yapf/pytree/split_penalty.py @@ -603,6 +603,9 @@ def _RecAnnotate(tree, annotate_name, annotate_value): pytree_utils.SetNodeAnnotation(tree, annotate_name, annotate_value) +_COMP_OPS = frozenset({'==', '!=', '<=', '<', '>', '>=', '<>', 'in', 'is'}) + + def _StronglyConnectedCompOp(op): if (len(op.children[1].children) == 2 and pytree_utils.NodeName(op.children[1]) == 'comp_op'): @@ -613,7 +616,7 @@ def _StronglyConnectedCompOp(op): pytree_utils.LastLeafNode(op.children[1]).value == 'not'): return True if (isinstance(op.children[1], pytree.Leaf) and - op.children[1].value in {'==', 'in'}): + op.children[1].value in _COMP_OPS): return True return False diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 5037f1110..599f131dc 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1543,6 +1543,31 @@ def testNoSplittingAroundTermOperators(self): llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) + def testNoSplittingAroundCompOperators(self): + code = textwrap.dedent("""\ + c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa is not bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) + c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa in bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) + c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa not in bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) + + c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa is bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) + c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa <= bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) + """) + expected_code = textwrap.dedent("""\ + c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + is not bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) + c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + in bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) + c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + not in bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) + + c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + is bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) + c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + <= bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) + """) + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) + def testNoSplittingWithinSubscriptList(self): code = textwrap.dedent("""\ somequitelongvariablename.somemember[(a, b)] = { From 480339e67508e2f5425d7dd35f85add90c641cc0 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 25 Dec 2021 02:21:06 -0600 Subject: [PATCH 537/719] Add the beginnings of a simple Python parser. It parses Python code into a list of logical lines, represented by LogicalLine objects. A "logical line" produced by Python's "tokenizer" module ends with a tokenize.NEWLINE, rather than a tokenize.NL, making it easy to parse. This uses Python's tokenizer module to generate the tokens. As such, YAPF must be run with the appropriate Python version---Python 2.7 for Python2 code, Python 3.x for Python3 code, etc. It then uses Python's native "ast" module to assign subtypes, calculate split penalties, etc. --- CHANGELOG | 2 + yapf/pyparser/__init__.py | 13 + yapf/pyparser/pyparser.py | 143 ++++ yapf/pyparser/pyparser_utils.py | 94 +++ yapf/pyparser/pyparser_visitor.py.tmpl | 645 ++++++++++++++++++ yapf/pyparser/split_penalty_visitor.py | 891 +++++++++++++++++++++++++ yapf/yapflib/format_token.py | 5 +- yapf/yapflib/py3compat.py | 10 +- yapf/yapflib/split_penalty.py | 28 + 9 files changed, 1828 insertions(+), 3 deletions(-) create mode 100644 yapf/pyparser/__init__.py create mode 100644 yapf/pyparser/pyparser.py create mode 100644 yapf/pyparser/pyparser_utils.py create mode 100644 yapf/pyparser/pyparser_visitor.py.tmpl create mode 100644 yapf/pyparser/split_penalty_visitor.py create mode 100644 yapf/yapflib/split_penalty.py diff --git a/CHANGELOG b/CHANGELOG index 1bfa7f627..8487ada55 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,8 @@ # This project adheres to [Semantic Versioning](http://semver.org/). ## [0.40.0] UNRELEASED +### Added +- Add a new Python parser to generate logical lines. ### Changes - Moved 'pytree' parsing tools into its own subdirectory. - Add support for Python 3.10. diff --git a/yapf/pyparser/__init__.py b/yapf/pyparser/__init__.py new file mode 100644 index 000000000..1b6cc8061 --- /dev/null +++ b/yapf/pyparser/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2022 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/yapf/pyparser/pyparser.py b/yapf/pyparser/pyparser.py new file mode 100644 index 000000000..bec1cc3b1 --- /dev/null +++ b/yapf/pyparser/pyparser.py @@ -0,0 +1,143 @@ +# Copyright 2022 Bill Wendling, All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Simple Python Parser + +Parse Python code into a list of logical lines, represented by LogicalLine +objects. This uses Python's tokenizer to generate the tokens. As such, YAPF must +be run with the appropriate Python version---Python 2.7 for Python2 code, Python +3.x for Python3 code, etc. + +This parser uses Python's native "tokenizer" module to generate a list of tokens +for the source code. It then uses Python's native "ast" module to assign +subtypes, calculate split penalties, etc. + +A "logical line" produced by Python's "tokenizer" module ends with a +tokenize.NEWLINE, rather than a tokenize.NL, making it easy to separate them +out. + + ParseCode(): parse the code producing a list of logical lines. +""" + +# TODO: Call from yapf_api.FormatCode. + +import ast +import os +import token +import tokenize + +from yapf.pyparser import split_penalty_visitor +from yapf.yapflib import format_token +from yapf.yapflib import logical_line +from yapf.yapflib import py3compat +from yapf.yapflib import style +from yapf.yapflib import subtypes + +CONTINUATION = token.N_TOKENS + + +def ParseCode(unformatted_source, filename=''): + """Parse a string of Python code into logical lines. + + This provides an alternative entry point to YAPF. + + Arguments: + unformatted_source: (unicode) The code to format. + filename: (unicode) The name of the file being reformatted. + + Returns: + A list of LogicalLines. + + Raises: + An exception is raised if there's an error during AST parsing. + """ + if not unformatted_source.endswith(os.linesep): + unformatted_source += os.linesep + + try: + ast_tree = ast.parse(unformatted_source, filename) + readline = py3compat.StringIO(unformatted_source).readline + tokens = tokenize.generate_tokens(readline) + except Exception as e: + raise + + logical_lines = _CreateLogicalLines(tokens) + + # Process the logical lines. + split_penalty_visitor.SplitPenalty(logical_lines).visit(ast_tree) + return logical_lines + + +def _CreateLogicalLines(tokens): + """Separate tokens into logical lines. + + Arguments: + tokens: (list of tokenizer.TokenInfo) Tokens generated by tokenizer. + + Returns: + A list of LogicalLines. + """ + logical_lines = [] + cur_logical_line = [] + prev_tok = None + depth = 0 + + for tok in tokens: + tok = py3compat.TokenInfo(*tok) + if tok.type == tokenize.NEWLINE: + # End of a logical line. + logical_lines.append(logical_line.LogicalLine(depth, cur_logical_line)) + cur_logical_line = [] + prev_tok = None + elif tok.type == tokenize.INDENT: + depth += 1 + elif tok.type == tokenize.DEDENT: + depth -= 1 + elif tok.type not in {tokenize.NL, tokenize.ENDMARKER}: + if (prev_tok and prev_tok.line.rstrip().endswith('\\') and + prev_tok.start[0] < tok.start[0]): + # Insert a token for a line continuation. + ctok = py3compat.TokenInfo( + type=CONTINUATION, + string='\\', + start=(prev_tok.start[0], prev_tok.start[1] + 1), + end=(prev_tok.end[0], prev_tok.end[0] + 2), + line=prev_tok.line) + ctok.lineno = ctok.start[0] + ctok.column = ctok.start[1] + ctok.value = '\\' + cur_logical_line.append(format_token.FormatToken(ctok, 'CONTINUATION')) + tok.lineno = tok.start[0] + tok.column = tok.start[1] + tok.value = tok.string + cur_logical_line.append( + format_token.FormatToken(tok, token.tok_name[tok.type])) + prev_tok = tok + + # Link the FormatTokens in each line together to for a doubly linked list. + for line in logical_lines: + previous = line.first + bracket_stack = [previous] if previous.OpensScope() else [] + for tok in line.tokens[1:]: + tok.previous_token = previous + previous.next_token = tok + previous = tok + + # Set up the "matching_bracket" attribute. + if tok.OpensScope(): + bracket_stack.append(tok) + elif tok.ClosesScope(): + bracket_stack[-1].matching_bracket = tok + tok.matching_bracket = bracket_stack.pop() + + return logical_lines diff --git a/yapf/pyparser/pyparser_utils.py b/yapf/pyparser/pyparser_utils.py new file mode 100644 index 000000000..cbc3d503d --- /dev/null +++ b/yapf/pyparser/pyparser_utils.py @@ -0,0 +1,94 @@ +# Copyright 2022 Bill Wendling, All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""PyParser-related utilities. + +This module collects various utilities related to the parse trees produced by +the pyparser. + + FindTokensInRange: produces a list of tokens from the logical lines within a + range. + GetTokensInSubRange: produces a sublist of tokens from a current token list + within a range. + GetTokenIndex: Get the index of a token. + GetNextTokenIndex: Get the index of the next token after a given position. + GetPrevTokenIndex: Get the index of the previous token before a given + position. +""" + +import ast + + +def FindTokensInRange(logical_lines, node): + """Get a list of tokens within the range [start, end).""" + start = (node.lineno, node.col_offset) + end = (node.end_lineno, node.end_col_offset) + tokens = [] + for line in logical_lines: + if line.start > end: + break + if line.start <= start or line.end >= end: + tokens.extend(GetTokensInSubRange(line.tokens, start, end)) + return tokens + + +def GetTokensInSubRange(tokens, start, end): + """Get a subset of tokens within the range [start, end).""" + tokens_in_range = [] + for tok in tokens: + tok_range = (tok.lineno, tok.column) + if tok_range >= start and tok_range < end: + tokens_in_range.append(tok) + return tokens_in_range + + +def GetTokenIndex(tokens, pos): + """Get the index of the token at 'pos.'""" + index = 0 + while index < len(tokens): + if (tokens[index].lineno, tokens[index].column) == pos: + break + index += 1 + return index + + +def GetNextTokenIndex(tokens, pos): + """Get the index of the next token after 'pos.'""" + index = 0 + while index < len(tokens): + if (tokens[index].lineno, tokens[index].column) >= pos: + break + index += 1 + return index + + +def GetPrevTokenIndex(tokens, pos): + """Get the index of the previous token before 'pos.'""" + index = 1 + while index < len(tokens): + if (tokens[index].lineno, tokens[index].column) >= pos: + break + index += 1 + return index - 1 + + +def TokenStart(node): + return (node.lineno, node.col_offset) + + +def TokenEnd(node): + return (node.end_lineno, node.end_col_offset) + + +def AstDump(node): + print(ast.dump(node, include_attributes=True, indent=4)) diff --git a/yapf/pyparser/pyparser_visitor.py.tmpl b/yapf/pyparser/pyparser_visitor.py.tmpl new file mode 100644 index 000000000..503cf2bee --- /dev/null +++ b/yapf/pyparser/pyparser_visitor.py.tmpl @@ -0,0 +1,645 @@ +# Copyright 2022 Bill Wendling, All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""AST visitor template. + +This is a template for a pyparser visitor. Example use: + + import ast + + from yapf.pyparser import pyparser_visitor + + def parse_code(source, filename): + ast_tree = ast.parse(source, filename) + readline = py3compat.StringIO(source).readline + tokens = tokenize.generate_tokens(readline) + logical_lines = _CreateLogicalLines(tokens) + + pyparser_visitor.Visitor(logical_lines).visit(ast_tree) +""" + +import ast + + +# This is a skeleton of an AST visitor. +class Visitor(ast.NodeVisitor): + """Compute split penalties between tokens.""" + + def __init__(self, logical_lines): + super(Visitor, self).__init__() + self.logical_lines = logical_lines + + ############################################################################ + # Statements # + ############################################################################ + + def visit_FunctionDef(self, node): + # FunctionDef(name=Name, + # args=arguments( + # posonlyargs=[], + # args=[], + # vararg=[], + # kwonlyargs=[], + # kw_defaults=[], + # defaults=[]), + # body=[...], + # decorator_list=[Expr_1, Expr_2, ..., Expr_n], + # keywords=[]) + return self.generic_visit(node) + + def visit_AsyncFunctionDef(self, node): + # AsyncFunctionDef(name=Name, + # args=arguments( + # posonlyargs=[], + # args=[], + # vararg=[], + # kwonlyargs=[], + # kw_defaults=[], + # defaults=[]), + # body=[...], + # decorator_list=[Expr_1, Expr_2, ..., Expr_n], + # keywords=[]) + return self.generic_visit(node) + + def visit_ClassDef(self, node): + # ClassDef(name=Name, + # bases=[Expr_1, Expr_2, ..., Expr_n], + # keywords=[], + # body=[], + # decorator_list=[Expr_1, Expr_2, ..., Expr_m]) + return self.generic_visit(node) + + def visit_Return(self, node): + # Return(value=Expr) + return self.generic_visit(node) + + def visit_Delete(self, node): + # Delete(targets=[Expr_1, Expr_2, ..., Expr_n]) + return self.generic_visit(node) + + def visit_Assign(self, node): + # Assign(targets=[Expr_1, Expr_2, ..., Expr_n], + # value=Expr) + return self.generic_visit(node) + + def visit_AugAssign(self, node): + # AugAssign(target=Name, + # op=Add(), + # value=Expr) + return self.generic_visit(node) + + def visit_AnnAssign(self, node): + # AnnAssign(target=Name, + # annotation=TypeName, + # value=Expr, + # simple=number) + return self.generic_visit(node) + + def visit_For(self, node): + # For(target=Expr, + # iter=Expr, + # body=[...], + # orelse=[...]) + return self.generic_visit(node) + + def visit_AsyncFor(self, node): + # AsyncFor(target=Expr, + # iter=Expr, + # body=[...], + # orelse=[...]) + return self.generic_visit(node) + + def visit_While(self, node): + # While(test=Expr, + # body=[...], + # orelse=[...]) + return self.generic_visit(node) + + def visit_If(self, node): + # If(test=Expr, + # body=[...], + # orelse=[...]) + return self.generic_visit(node) + + def visit_With(self, node): + # With(items=[withitem_1, withitem_2, ..., withitem_n], + # body=[...]) + return self.generic_visit(node) + + def visit_AsyncWith(self, node): + # AsyncWith(items=[withitem_1, withitem_2, ..., withitem_n], + # body=[...]) + return self.generic_visit(node) + + def visit_Match(self, node): + # Match(subject=Expr, + # cases=[ + # match_case( + # pattern=pattern, + # guard=Expr, + # body=[...]), + # ... + # ]) + return self.generic_visit(node) + + def visit_Raise(self, node): + # Raise(exc=Expr) + return self.generic_visit(node) + + def visit_Try(self, node): + # Try(body=[...], + # handlers=[ExceptHandler_1, ExceptHandler_2, ..., ExceptHandler_b], + # orelse=[...], + # finalbody=[...]) + return self.generic_visit(node) + + def visit_Assert(self, node): + # Assert(test=Expr) + return self.generic_visit(node) + + def visit_Import(self, node): + # Import(names=[ + # alias( + # name=Identifier, + # asname=Identifier), + # ... + # ]) + return self.generic_visit(node) + + def visit_ImportFrom(self, node): + # ImportFrom(module=Identifier, + # names=[ + # alias( + # name=Identifier, + # asname=Identifier), + # ... + # ], + # level=num + return self.generic_visit(node) + + def visit_Global(self, node): + # Global(names=[Identifier_1, Identifier_2, ..., Identifier_n]) + return self.generic_visit(node) + + def visit_Nonlocal(self, node): + # Nonlocal(names=[Identifier_1, Identifier_2, ..., Identifier_n]) + return self.generic_visit(node) + + def visit_Expr(self, node): + # Expr(value=Expr) + return self.generic_visit(node) + + def visit_Pass(self, node): + # Pass() + return self.generic_visit(node) + + def visit_Break(self, node): + # Break() + return self.generic_visit(node) + + def visit_Continue(self, node): + # Continue() + return self.generic_visit(node) + + ############################################################################ + # Expressions # + ############################################################################ + + def visit_BoolOp(self, node): + # BoolOp(op=And | Or, + # values=[Expr_1, Expr_2, ..., Expr_n]) + return self.generic_visit(node) + + def visit_NamedExpr(self, node): + # NamedExpr(target=Name, + # value=Expr) + return self.generic_visit(node) + + def visit_BinOp(self, node): + # BinOp(left=LExpr + # op=Add | Sub | Mult | MatMult | Div | Mod | Pow | LShift | + # RShift | BitOr | BitXor | BitAnd | FloorDiv + # right=RExpr) + return self.generic_visit(node) + + def visit_UnaryOp(self, node): + # UnaryOp(op=Not | USub | UAdd | Invert, + # operand=Expr) + return self.generic_visit(node) + + def visit_Lambda(self, node): + # Lambda(args=arguments( + # posonlyargs=[], + # args=[ + # arg(arg='a'), + # arg(arg='b')], + # kwonlyargs=[], + # kw_defaults=[], + # defaults=[]), + # body=Expr) + return self.generic_visit(node) + + def visit_IfExp(self, node): + # IfExp(test=TestExpr, + # body=BodyExpr, + # orelse=OrElseExpr) + return self.generic_visit(node) + + def visit_Dict(self, node): + # Dict(keys=[Expr_1, Expr_2, ..., Expr_n], + # values=[Expr_1, Expr_2, ..., Expr_n]) + return self.generic_visit(node) + + def visit_Set(self, node): + # Set(elts=[Expr_1, Expr_2, ..., Expr_n]) + return self.generic_visit(node) + + def visit_ListComp(self, node): + # ListComp(elt=Expr, + # generators=[ + # comprehension( + # target=Expr, + # iter=Expr, + # ifs=[Expr_1, Expr_2, ..., Expr_n], + # is_async=0), + # ... + # ]) + return self.generic_visit(node) + + def visit_SetComp(self, node): + # SetComp(elt=Expr, + # generators=[ + # comprehension( + # target=Expr, + # iter=Expr, + # ifs=[Expr_1, Expr_2, ..., Expr_n], + # is_async=0), + # ... + # ]) + return self.generic_visit(node) + + def visit_DictComp(self, node): + # DictComp(key=KeyExpr, + # value=ValExpr, + # generators=[ + # comprehension( + # target=TargetExpr + # iter=IterExpr, + # ifs=[Expr_1, Expr_2, ..., Expr_n]), + # is_async=0)], + # ... + # ]) + return self.generic_visit(node) + + def visit_GeneratorExp(self, node): + # GeneratorExp(elt=Expr, + # generators=[ + # comprehension( + # target=Expr, + # iter=Expr, + # ifs=[Expr_1, Expr_2, ..., Expr_n], + # is_async=0), + # ... + # ]) + return self.generic_visit(node) + + def visit_Await(self, node): + # Await(value=Expr) + return self.generic_visit(node) + + def visit_Yield(self, node): + # Yield(value=Expr) + return self.generic_visit(node) + + def visit_YieldFrom(self, node): + # YieldFrom(value=Expr) + return self.generic_visit(node) + + def visit_Compare(self, node): + # Compare(left=LExpr, + # ops=[Op_1, Op_2, ..., Op_n], + # comparators=[Expr_1, Expr_2, ..., Expr_n]) + return self.generic_visit(node) + + def visit_Call(self, node): + # Call(func=Expr, + # args=[Expr_1, Expr_2, ..., Expr_n], + # keywords=[ + # keyword( + # arg='d', + # value=Expr), + # ... + # ]) + return self.generic_visit(node) + + def visit_FormattedValue(self, node): + # FormattedValue(value=Expr, + # conversion=-1, + # format_spec=FSExpr) + return self.generic_visit(node) + + def visit_JoinedStr(self, node): + # JoinedStr(values=[Expr_1, Expr_2, ..., Expr_n]) + return self.generic_visit(node) + + def visit_Constant(self, node): + # Constant(value=Expr) + return self.generic_visit(node) + + def visit_Attribute(self, node): + # Attribute(value=Expr, + # attr=Identifier) + return self.generic_visit(node) + + def visit_Subscript(self, node): + # Subscript(value=VExpr, + # slice=SExpr) + return self.generic_visit(node) + + def visit_Starred(self, node): + # Starred(value=Expr) + return self.generic_visit(node) + + def visit_Name(self, node): + # Name(id=Identifier) + return self.generic_visit(node) + + def visit_List(self, node): + # List(elts=[Expr_1, Expr_2, ..., Expr_n]) + return self.generic_visit(node) + + def visit_Tuple(self, node): + # Tuple(elts=[Expr_1, Expr_2, ..., Expr_n]) + return self.generic_visit(node) + + def visit_Slice(self, node): + # Slice(lower=Expr, + # upper=Expr, + # step=Expr) + return self.generic_visit(node) + + ############################################################################ + # Expression Context # + ############################################################################ + + def visit_Load(self, node): + # Load() + return self.generic_visit(node) + + def visit_Store(self, node): + # Store() + return self.generic_visit(node) + + def visit_Del(self, node): + # Del() + return self.generic_visit(node) + + ############################################################################ + # Boolean Operators # + ############################################################################ + + def visit_And(self, node): + # And() + return self.generic_visit(node) + + def visit_Or(self, node): + # Or() + return self.generic_visit(node) + + ############################################################################ + # Binary Operators # + ############################################################################ + + def visit_Add(self, node): + # Add() + return self.generic_visit(node) + + def visit_Sub(self, node): + # Sub() + return self.generic_visit(node) + + def visit_Mult(self, node): + # Mult() + return self.generic_visit(node) + + def visit_MatMult(self, node): + # MatMult() + return self.generic_visit(node) + + def visit_Div(self, node): + # Div() + return self.generic_visit(node) + + def visit_Mod(self, node): + # Mod() + return self.generic_visit(node) + + def visit_Pow(self, node): + # Pow() + return self.generic_visit(node) + + def visit_LShift(self, node): + # LShift() + return self.generic_visit(node) + + def visit_RShift(self, node): + # RShift() + return self.generic_visit(node) + + def visit_BitOr(self, node): + # BitOr() + return self.generic_visit(node) + + def visit_BitXor(self, node): + # BitXor() + return self.generic_visit(node) + + def visit_BitAnd(self, node): + # BitAnd() + return self.generic_visit(node) + + def visit_FloorDiv(self, node): + # FloorDiv() + return self.generic_visit(node) + + ############################################################################ + # Unary Operators # + ############################################################################ + + def visit_Invert(self, node): + # Invert() + return self.generic_visit(node) + + def visit_Not(self, node): + # Not() + return self.generic_visit(node) + + def visit_UAdd(self, node): + # UAdd() + return self.generic_visit(node) + + def visit_USub(self, node): + # USub() + return self.generic_visit(node) + + ############################################################################ + # Comparison Operators # + ############################################################################ + + def visit_Eq(self, node): + # Eq() + return self.generic_visit(node) + + def visit_NotEq(self, node): + # NotEq() + return self.generic_visit(node) + + def visit_Lt(self, node): + # Lt() + return self.generic_visit(node) + + def visit_LtE(self, node): + # LtE() + return self.generic_visit(node) + + def visit_Gt(self, node): + # Gt() + return self.generic_visit(node) + + def visit_GtE(self, node): + # GtE() + return self.generic_visit(node) + + def visit_Is(self, node): + # Is() + return self.generic_visit(node) + + def visit_IsNot(self, node): + # IsNot() + return self.generic_visit(node) + + def visit_In(self, node): + # In() + return self.generic_visit(node) + + def visit_NotIn(self, node): + # NotIn() + return self.generic_visit(node) + + ############################################################################ + # Exception Handler # + ############################################################################ + + def visit_ExceptionHandler(self, node): + # ExceptHandler(type=Expr, + # name=Identifier, + # body=[...]) + return self.generic_visit(node) + + ############################################################################ + # Matching Patterns # + ############################################################################ + + def visit_MatchValue(self, node): + # MatchValue(value=Expr) + return self.generic_visit(node) + + def visit_MatchSingleton(self, node): + # MatchSingleton(value=Constant) + return self.generic_visit(node) + + def visit_MatchSequence(self, node): + # MatchSequence(patterns=[pattern_1, pattern_2, ..., pattern_n]) + return self.generic_visit(node) + + def visit_MatchMapping(self, node): + # MatchMapping(keys=[Expr_1, Expr_2, ..., Expr_n], + # patterns=[pattern_1, pattern_2, ..., pattern_m], + # rest=Identifier) + return self.generic_visit(node) + + def visit_MatchClass(self, node): + # MatchClass(cls=Expr, + # patterns=[pattern_1, pattern_2, ...], + # kwd_attrs=[Identifier_1, Identifier_2, ...], + # kwd_patterns=[pattern_1, pattern_2, ...]) + return self.generic_visit(node) + + def visit_MatchStar(self, node): + # MatchStar(name=Identifier) + return self.generic_visit(node) + + def visit_MatchAs(self, node): + # MatchAs(pattern=pattern, + # name=Identifier) + return self.generic_visit(node) + + def visit_MatchOr(self, node): + # MatchOr(patterns=[pattern_1, pattern_2, ...]) + return self.generic_visit(node) + + ############################################################################ + # Type Ignore # + ############################################################################ + + def visit_TypeIgnore(self, node): + # TypeIgnore(tag=string) + return self.generic_visit(node) + + ############################################################################ + # Miscellaneous # + ############################################################################ + + def visit_comprehension(self, node): + # comprehension(target=Expr, + # iter=Expr, + # ifs=[Expr_1, Expr_2, ..., Expr_n], + # is_async=0) + return self.generic_visit(node) + + def visit_arguments(self, node): + # arguments(posonlyargs=[], + # args=[], + # vararg=arg, + # kwonlyargs=[], + # kw_defaults=[], + # kwarg=arg, + # defaults=[]), + return self.generic_visit(node) + + def visit_arg(self, node): + # arg(arg=Identifier, + # annotation=Expr, + # type_comment='') + return self.generic_visit(node) + + def visit_keyword(self, node): + # keyword(arg=Identifier, + # value=Expr) + return self.generic_visit(node) + + def visit_alias(self, node): + # alias(name=Identifier, + # asname=Identifier) + return self.generic_visit(node) + + def visit_withitem(self, node): + # withitem(context_expr=Expr, + # optional_vars=Expr) + return self.generic_visit(node) + + def visit_match_case(self, node): + # match_case(pattern=pattern, + # guard=Expr, + # body=[...]) + return self.generic_visit(node) diff --git a/yapf/pyparser/split_penalty_visitor.py b/yapf/pyparser/split_penalty_visitor.py new file mode 100644 index 000000000..f886fd3af --- /dev/null +++ b/yapf/pyparser/split_penalty_visitor.py @@ -0,0 +1,891 @@ +# Copyright 2022 Bill Wendling, All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import ast + +from yapf.pyparser import pyparser_utils as pyutils +from yapf.yapflib import split_penalty +from yapf.yapflib import style +from yapf.yapflib import subtypes + + +# This is a skeleton of an AST visitor. +class SplitPenalty(ast.NodeVisitor): + """Compute split penalties between tokens.""" + + def __init__(self, logical_lines): + super(SplitPenalty, self).__init__() + self.logical_lines = logical_lines + + # We never want to split before a colon or comma. + for logical_line in logical_lines: + for token in logical_line.tokens: + if token.value in frozenset({',', ':'}): + token.split_penalty = split_penalty.UNBREAKABLE + + def _GetTokens(self, node): + return pyutils.FindTokensInRange(self.logical_lines, node) + + ############################################################################ + # Statements # + ############################################################################ + + def visit_FunctionDef(self, node): + # FunctionDef(name=Name, + # args=arguments( + # posonlyargs=[], + # args=[], + # vararg=[], + # kwonlyargs=[], + # kw_defaults=[], + # defaults=[]), + # body=[...], + # decorator_list=[Expr_1, Expr_2, ..., Expr_n], + # keywords=[]) + for decorator in node.decorator_list: + # Don't split after the '@'. + tokens = self._GetTokens(decorator) + tokens[0].split_penalty = split_penalty.UNBREAKABLE + + tokens = self._GetTokens(node) + + if node.returns: + start_index = pyutils.GetTokenIndex(tokens, + pyutils.TokenStart(node.returns)) + _IncreasePenalty(tokens[start_index - 1:start_index + 1], + split_penalty.VERY_STRONGLY_CONNECTED) + end_index = pyutils.GetTokenIndex(tokens, + pyutils.TokenEnd(node.returns)) + _IncreasePenalty(tokens[start_index + 1:end_index], + split_penalty.STRONGLY_CONNECTED) + + return self.generic_visit(node) + + def visit_AsyncFunctionDef(self, node): + # AsyncFunctionDef(name=Name, + # args=arguments( + # posonlyargs=[], + # args=[], + # vararg=[], + # kwonlyargs=[], + # kw_defaults=[], + # defaults=[]), + # body=[...], + # decorator_list=[Expr_1, Expr_2, ..., Expr_n], + # keywords=[]) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1], split_penalty.UNBREAKABLE) + return self.visit_FunctionDef(node) + + def visit_ClassDef(self, node): + # ClassDef(name=Name, + # bases=[Expr_1, Expr_2, ..., Expr_n], + # keywords=[], + # body=[], + # decorator_list=[Expr_1, Expr_2, ..., Expr_m]) + for base in node.bases: + tokens = self._GetTokens(base) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + + for decorator in node.decorator_list: + # Don't split after the '@'. + tokens = self._GetTokens(decorator) + tokens[0].split_penalty = split_penalty.UNBREAKABLE + + return self.generic_visit(node) + + def visit_Return(self, node): + # Return(value=Expr) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + return self.generic_visit(node) + + def visit_Delete(self, node): + # Delete(targets=[Expr_1, Expr_2, ..., Expr_n]) + for target in node.targets: + tokens = self._GetTokens(target) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + return self.generic_visit(node) + + def visit_Assign(self, node): + # Assign(targets=[Expr_1, Expr_2, ..., Expr_n], + # value=Expr) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + return self.generic_visit(node) + + def visit_AugAssign(self, node): + # AugAssign(target=Name, + # op=Add(), + # value=Expr) + return self.generic_visit(node) + + def visit_AnnAssign(self, node): + # AnnAssign(target=Expr, + # annotation=TypeName, + # value=Expr, + # simple=number) + return self.generic_visit(node) + + def visit_For(self, node): + # For(target=Expr, + # iter=Expr, + # body=[...], + # orelse=[...]) + return self.generic_visit(node) + + def visit_AsyncFor(self, node): + # AsyncFor(target=Expr, + # iter=Expr, + # body=[...], + # orelse=[...]) + return self.generic_visit(node) + + def visit_While(self, node): + # While(test=Expr, + # body=[...], + # orelse=[...]) + return self.generic_visit(node) + + def visit_If(self, node): + # If(test=Expr, + # body=[...], + # orelse=[...]) + return self.generic_visit(node) + + def visit_With(self, node): + # With(items=[withitem_1, withitem_2, ..., withitem_n], + # body=[...]) + return self.generic_visit(node) + + def visit_AsyncWith(self, node): + # AsyncWith(items=[withitem_1, withitem_2, ..., withitem_n], + # body=[...]) + return self.generic_visit(node) + + def visit_Match(self, node): + # Match(subject=Expr, + # cases=[ + # match_case( + # pattern=pattern, + # guard=Expr, + # body=[...]), + # ... + # ]) + return self.generic_visit(node) + + def visit_Raise(self, node): + # Raise(exc=Expr) + return self.generic_visit(node) + + def visit_Try(self, node): + # Try(body=[...], + # handlers=[ExceptHandler_1, ExceptHandler_2, ..., ExceptHandler_b], + # orelse=[...], + # finalbody=[...]) + return self.generic_visit(node) + + def visit_Assert(self, node): + # Assert(test=Expr) + return self.generic_visit(node) + + def visit_Import(self, node): + # Import(names=[ + # alias( + # name=Identifier, + # asname=Identifier), + # ... + # ]) + return self.generic_visit(node) + + def visit_ImportFrom(self, node): + # ImportFrom(module=Identifier, + # names=[ + # alias( + # name=Identifier, + # asname=Identifier), + # ... + # ], + # level=num + return self.generic_visit(node) + + def visit_Global(self, node): + # Global(names=[Identifier_1, Identifier_2, ..., Identifier_n]) + return self.generic_visit(node) + + def visit_Nonlocal(self, node): + # Nonlocal(names=[Identifier_1, Identifier_2, ..., Identifier_n]) + return self.generic_visit(node) + + def visit_Expr(self, node): + # Expr(value=Expr) + return self.generic_visit(node) + + def visit_Pass(self, node): + # Pass() + return self.generic_visit(node) + + def visit_Break(self, node): + # Break() + return self.generic_visit(node) + + def visit_Continue(self, node): + # Continue() + return self.generic_visit(node) + + ############################################################################ + # Expressions # + ############################################################################ + + def visit_BoolOp(self, node): + # BoolOp(op=And | Or, + # values=[Expr_1, Expr_2, ..., Expr_n]) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + + # Lower the split penalty to allow splitting before or after the logical + # operator. + split_before_operator = style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR') + operator_indices = [ + pyutils.GetNextTokenIndex(tokens, pyutils.TokenEnd(value)) + for value in node.values[:-1] + ] + for operator_index in operator_indices: + if not split_before_operator: + operator_index += 1 + _DecreasePenalty(tokens[operator_index], split_penalty.EXPR * 2) + + return self.generic_visit(node) + + def visit_NamedExpr(self, node): + # NamedExpr(target=Name, + # value=Expr) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + return self.generic_visit(node) + + def visit_BinOp(self, node): + # BinOp(left=LExpr + # op=Add | Sub | Mult | MatMult | Div | Mod | Pow | LShift | + # RShift | BitOr | BitXor | BitAnd | FloorDiv + # right=RExpr) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + + # Lower the split penalty to allow splitting before or after the arithmetic + # operator. + operator_index = pyutils.GetNextTokenIndex(tokens, + pyutils.TokenEnd(node.left)) + if not style.Get('SPLIT_BEFORE_ARITHMETIC_OPERATOR'): + operator_index += 1 + _DecreasePenalty(tokens[operator_index], split_penalty.EXPR * 2) + return self.generic_visit(node) + + def visit_UnaryOp(self, node): + # UnaryOp(op=Not | USub | UAdd | Invert, + # operand=Expr) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + _IncreasePenalty(tokens[1], + style.Get('SPLIT_PENALTY_AFTER_UNARY_OPERATOR')) + return self.generic_visit(node) + + def visit_Lambda(self, node): + # Lambda(args=arguments( + # posonlyargs=[arg(...), arg(...), ..., arg(...)], + # args=[arg(...), arg(...), ..., arg(...)], + # kwonlyargs=[arg(...), arg(...), ..., arg(...)], + # kw_defaults=[arg(...), arg(...), ..., arg(...)], + # defaults=[arg(...), arg(...), ..., arg(...)]), + # body=Expr) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.LAMBDA) + if style.Get('ALLOW_MULTILINE_LAMBDAS'): + tokens = self._GetTokens(node.body) + _DecreasePenalty(tokens[1], split_penalty.LAMBDA) + return self.generic_visit(node) + + def visit_IfExp(self, node): + # IfExp(test=TestExpr, + # body=BodyExpr, + # orelse=OrElseExpr) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + return self.generic_visit(node) + + def visit_Dict(self, node): + # Dict(keys=[Expr_1, Expr_2, ..., Expr_n], + # values=[Expr_1, Expr_2, ..., Expr_n]) + tokens = self._GetTokens(node) + + # The keys should be on a single line if at all possible. + for key in node.keys: + subrange = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(key), pyutils.TokenEnd(key)) + _IncreasePenalty(subrange[1:], split_penalty.DICT_KEY_EXPR) + + for value in node.values: + subrange = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(value), pyutils.TokenEnd(value)) + _IncreasePenalty(subrange[1:], split_penalty.DICT_VALUE_EXPR) + return self.generic_visit(node) + + def visit_Set(self, node): + # Set(elts=[Expr_1, Expr_2, ..., Expr_n]) + tokens = self._GetTokens(node) + for element in node.elts: + subrange = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(element), pyutils.TokenEnd(element)) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + return self.generic_visit(node) + + def visit_ListComp(self, node): + # ListComp(elt=Expr, + # generators=[ + # comprehension( + # target=Expr, + # iter=Expr, + # ifs=[Expr_1, Expr_2, ..., Expr_n], + # is_async=0), + # ... + # ]) + tokens = self._GetTokens(node) + element = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(node.elt), pyutils.TokenEnd(node.elt)) + _IncreasePenalty(element[1:], split_penalty.EXPR) + + for comp in node.generators: + subrange = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(comp.iter), pyutils.TokenEnd(comp.iter)) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + + for if_expr in comp.ifs: + subrange = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(if_expr), pyutils.TokenEnd(if_expr)) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + return self.generic_visit(node) + + def visit_SetComp(self, node): + # SetComp(elt=Expr, + # generators=[ + # comprehension( + # target=Expr, + # iter=Expr, + # ifs=[Expr_1, Expr_2, ..., Expr_n], + # is_async=0), + # ... + # ]) + tokens = self._GetTokens(node) + element = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(node.elt), pyutils.TokenEnd(node.elt)) + _IncreasePenalty(element[1:], split_penalty.EXPR) + + for comp in node.generators: + subrange = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(comp.iter), pyutils.TokenEnd(comp.iter)) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + + for if_expr in comp.ifs: + subrange = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(if_expr), pyutils.TokenEnd(if_expr)) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + return self.generic_visit(node) + + def visit_DictComp(self, node): + # DictComp(key=KeyExpr, + # value=ValExpr, + # generators=[ + # comprehension( + # target=TargetExpr + # iter=IterExpr, + # ifs=[Expr_1, Expr_2, ..., Expr_n]), + # is_async=0)], + # ... + # ]) + tokens = self._GetTokens(node) + key = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(node.key), pyutils.TokenEnd(node.key)) + _IncreasePenalty(key[1:], split_penalty.EXPR) + + value = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(node.value), pyutils.TokenEnd(node.value)) + _IncreasePenalty(value[1:], split_penalty.EXPR) + + for comp in node.generators: + subrange = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(comp.iter), pyutils.TokenEnd(comp.iter)) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + + for if_expr in comp.ifs: + subrange = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(if_expr), pyutils.TokenEnd(if_expr)) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + return self.generic_visit(node) + + def visit_GeneratorExp(self, node): + # GeneratorExp(elt=Expr, + # generators=[ + # comprehension( + # target=Expr, + # iter=Expr, + # ifs=[Expr_1, Expr_2, ..., Expr_n], + # is_async=0), + # ... + # ]) + tokens = self._GetTokens(node) + element = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(node.elt), pyutils.TokenEnd(node.elt)) + _IncreasePenalty(element[1:], split_penalty.EXPR) + + for comp in node.generators: + subrange = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(comp.iter), pyutils.TokenEnd(comp.iter)) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + + for if_expr in comp.ifs: + subrange = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(if_expr), pyutils.TokenEnd(if_expr)) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + return self.generic_visit(node) + + def visit_Await(self, node): + # Await(value=Expr) + tokens = self._GetTokens(node) + _IncreasePenalty(element[1:], split_penalty.EXPR) + return self.generic_visit(node) + + def visit_Yield(self, node): + # Yield(value=Expr) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + return self.generic_visit(node) + + def visit_YieldFrom(self, node): + # YieldFrom(value=Expr) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + tokens[2].split_penalty = split_penalty.UNBREAKABLE + return self.generic_visit(node) + + def visit_Compare(self, node): + # Compare(left=LExpr, + # ops=[Op_1, Op_2, ..., Op_n], + # comparators=[Expr_1, Expr_2, ..., Expr_n]) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + + operator_indices = [ + pyutils.GetNextTokenIndex(tokens, pyutils.TokenEnd(node.left)) + ] + [ + pyutils.GetNextTokenIndex(tokens, pyutils.TokenEnd(comparator)) + for comparator in node.comparators[:-1] + ] + split_before = style.Get('SPLIT_BEFORE_ARITHMETIC_OPERATOR') + for operator_index in operator_indices: + if not split_before: + operator_index += 1 + _DecreasePenalty(tokens[operator_index], split_penalty.EXPR * 2) + return self.generic_visit(node) + + def visit_Call(self, node): + # Call(func=Expr, + # args=[Expr_1, Expr_2, ..., Expr_n], + # keywords=[ + # keyword( + # arg='d', + # value=Expr), + # ... + # ]) + tokens = self._GetTokens(node) + + # Don't never split before the opening parenthesis. + paren_index = pyutils.GetNextTokenIndex(tokens, + pyutils.TokenEnd(node.func)) + _IncreasePenalty(tokens[paren_index], split_penalty.UNBREAKABLE) + + for arg in node.args: + subrange = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(arg), pyutils.TokenEnd(arg)) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + return self.generic_visit(node) + + def visit_FormattedValue(self, node): + # FormattedValue(value=Expr, + # conversion=-1) + return self.generic_visit(node) + + def visit_JoinedStr(self, node): + # JoinedStr(values=[Expr_1, Expr_2, ..., Expr_n]) + return self.generic_visit(node) + + def visit_Constant(self, node): + # Constant(value=Expr) + return self.generic_visit(node) + + def visit_Attribute(self, node): + # Attribute(value=Expr, + # attr=Identifier) + tokens = self._GetTokens(node) + split_before = style.Get('SPLIT_BEFORE_DOT') + dot_indices = pyutils.GetNextTokenIndex(tokens, + pyutils.TokenEnd(node.value)) + if not split_before: + dot_indices += 1 + _IncreasePenalty(tokens[dot_indices], split_penalty.VERY_STRONGLY_CONNECTED) + return self.generic_visit(node) + + def visit_Subscript(self, node): + # Subscript(value=ValueExpr, + # slice=SliceExpr) + tokens = self._GetTokens(node) + + # Don't split before the opening bracket of a subscript. + bracket_index = pyutils.GetNextTokenIndex(tokens, + pyutils.TokenEnd(node.value)) + _IncreasePenalty(tokens[bracket_index], split_penalty.UNBREAKABLE) + return self.generic_visit(node) + + def visit_Starred(self, node): + # Starred(value=Expr) + return self.generic_visit(node) + + def visit_Name(self, node): + # Name(id=Identifier) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.UNBREAKABLE) + return self.generic_visit(node) + + def visit_List(self, node): + # List(elts=[Expr_1, Expr_2, ..., Expr_n]) + tokens = self._GetTokens(node) + for element in node.elts: + subrange = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(element), pyutils.TokenEnd(element)) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) + return self.generic_visit(node) + + def visit_Tuple(self, node): + # Tuple(elts=[Expr_1, Expr_2, ..., Expr_n]) + tokens = self._GetTokens(node) + for element in node.elts: + subrange = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(element), pyutils.TokenEnd(element)) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) + return self.generic_visit(node) + + def visit_Slice(self, node): + # Slice(lower=Expr, + # upper=Expr, + # step=Expr) + tokens = self._GetTokens(node) + + if hasattr(node, 'lower'): + subrange = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(node.lower), pyutils.TokenEnd(node.lower)) + _IncreasePenalty(subrange, split_penalty.EXPR) + _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) + + if hasattr(node, 'upper'): + colon_index = pyutils.GetPrevTokenIndex(tokens, + pyutils.TokenStart(node.upper)) + _IncreasePenalty(tokens[colon_index], split_penalty.UNBREAKABLE) + subrange = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(node.upper), pyutils.TokenEnd(node.upper)) + _IncreasePenalty(subrange, split_penalty.EXPR) + _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) + + if hasattr(node, 'step'): + colon_index = pyutils.GetPrevTokenIndex(tokens, + pyutils.TokenStart(node.step)) + _IncreasePenalty(tokens[colon_index], split_penalty.UNBREAKABLE) + subrange = pyutils.GetTokensInSubRange( + tokens, pyutils.TokenStart(node.step), pyutils.TokenEnd(node.step)) + _IncreasePenalty(subrange, split_penalty.EXPR) + _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) + + return self.generic_visit(node) + + ############################################################################ + # Expression Context # + ############################################################################ + + def visit_Load(self, node): + # Load() + return self.generic_visit(node) + + def visit_Store(self, node): + # Store() + return self.generic_visit(node) + + def visit_Del(self, node): + # Del() + return self.generic_visit(node) + + ############################################################################ + # Boolean Operators # + ############################################################################ + + def visit_And(self, node): + # And() + return self.generic_visit(node) + + def visit_Or(self, node): + # Or() + return self.generic_visit(node) + + ############################################################################ + # Binary Operators # + ############################################################################ + + def visit_Add(self, node): + # Add() + return self.generic_visit(node) + + def visit_Sub(self, node): + # Sub() + return self.generic_visit(node) + + def visit_Mult(self, node): + # Mult() + return self.generic_visit(node) + + def visit_MatMult(self, node): + # MatMult() + return self.generic_visit(node) + + def visit_Div(self, node): + # Div() + return self.generic_visit(node) + + def visit_Mod(self, node): + # Mod() + return self.generic_visit(node) + + def visit_Pow(self, node): + # Pow() + return self.generic_visit(node) + + def visit_LShift(self, node): + # LShift() + return self.generic_visit(node) + + def visit_RShift(self, node): + # RShift() + return self.generic_visit(node) + + def visit_BitOr(self, node): + # BitOr() + return self.generic_visit(node) + + def visit_BitXor(self, node): + # BitXor() + return self.generic_visit(node) + + def visit_BitAnd(self, node): + # BitAnd() + return self.generic_visit(node) + + def visit_FloorDiv(self, node): + # FloorDiv() + return self.generic_visit(node) + + ############################################################################ + # Unary Operators # + ############################################################################ + + def visit_Invert(self, node): + # Invert() + return self.generic_visit(node) + + def visit_Not(self, node): + # Not() + return self.generic_visit(node) + + def visit_UAdd(self, node): + # UAdd() + return self.generic_visit(node) + + def visit_USub(self, node): + # USub() + return self.generic_visit(node) + + ############################################################################ + # Comparison Operators # + ############################################################################ + + def visit_Eq(self, node): + # Eq() + return self.generic_visit(node) + + def visit_NotEq(self, node): + # NotEq() + return self.generic_visit(node) + + def visit_Lt(self, node): + # Lt() + return self.generic_visit(node) + + def visit_LtE(self, node): + # LtE() + return self.generic_visit(node) + + def visit_Gt(self, node): + # Gt() + return self.generic_visit(node) + + def visit_GtE(self, node): + # GtE() + return self.generic_visit(node) + + def visit_Is(self, node): + # Is() + return self.generic_visit(node) + + def visit_IsNot(self, node): + # IsNot() + return self.generic_visit(node) + + def visit_In(self, node): + # In() + return self.generic_visit(node) + + def visit_NotIn(self, node): + # NotIn() + return self.generic_visit(node) + + ############################################################################ + # Exception Handler # + ############################################################################ + + def visit_ExceptionHandler(self, node): + # ExceptHandler(type=Expr, + # name=Identifier, + # body=[...]) + return self.generic_visit(node) + + ############################################################################ + # Matching Patterns # + ############################################################################ + + def visit_MatchValue(self, node): + # MatchValue(value=Expr) + return self.generic_visit(node) + + def visit_MatchSingleton(self, node): + # MatchSingleton(value=Constant) + return self.generic_visit(node) + + def visit_MatchSequence(self, node): + # MatchSequence(patterns=[pattern_1, pattern_2, ..., pattern_n]) + return self.generic_visit(node) + + def visit_MatchMapping(self, node): + # MatchMapping(keys=[Expr_1, Expr_2, ..., Expr_n], + # patterns=[pattern_1, pattern_2, ..., pattern_m], + # rest=Identifier) + return self.generic_visit(node) + + def visit_MatchClass(self, node): + # MatchClass(cls=Expr, + # patterns=[pattern_1, pattern_2, ...], + # kwd_attrs=[Identifier_1, Identifier_2, ...], + # kwd_patterns=[pattern_1, pattern_2, ...]) + return self.generic_visit(node) + + def visit_MatchStar(self, node): + # MatchStar(name=Identifier) + return self.generic_visit(node) + + def visit_MatchAs(self, node): + # MatchAs(pattern=pattern, + # name=Identifier) + return self.generic_visit(node) + + def visit_MatchOr(self, node): + # MatchOr(patterns=[pattern_1, pattern_2, ...]) + return self.generic_visit(node) + + ############################################################################ + # Type Ignore # + ############################################################################ + + def visit_TypeIgnore(self, node): + # TypeIgnore(tag=string) + return self.generic_visit(node) + + ############################################################################ + # Miscellaneous # + ############################################################################ + + def visit_comprehension(self, node): + # comprehension(target=Expr, + # iter=Expr, + # ifs=[Expr_1, Expr_2, ..., Expr_n], + # is_async=0) + return self.generic_visit(node) + + def visit_arguments(self, node): + # arguments(posonlyargs=[arg_1, arg_2, ..., arg_a], + # args=[arg_1, arg_2, ..., arg_b], + # vararg=arg, + # kwonlyargs=[arg_1, arg_2, ..., arg_c], + # kw_defaults=[arg_1, arg_2, ..., arg_d], + # kwarg=arg, + # defaults=[Expr_1, Expr_2, ..., Expr_n]) + return self.generic_visit(node) + + def visit_arg(self, node): + # arg(arg=Identifier, + # annotation=Expr, + # type_comment='') + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.ARGUMENT) + return self.generic_visit(node) + + def visit_keyword(self, node): + # keyword(arg=Identifier, + # value=Expr) + return self.generic_visit(node) + + def visit_alias(self, node): + # alias(name=Identifier, + # asname=Identifier) + return self.generic_visit(node) + + def visit_withitem(self, node): + # withitem(context_expr=Expr, + # optional_vars=Expr) + return self.generic_visit(node) + + def visit_match_case(self, node): + # match_case(pattern=pattern, + # guard=Expr, + # body=[...]) + return self.generic_visit(node) + + +def _IncreasePenalty(tokens, amt): + if not isinstance(tokens, list): + tokens = [tokens] + for token in tokens: + token.split_penalty += amt + + +def _DecreasePenalty(tokens, amt): + if not isinstance(tokens, list): + tokens = [tokens] + for token in tokens: + token.split_penalty -= amt diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 2c38e969d..58c30f1ad 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -83,11 +83,12 @@ class FormatToken(object): newlines: The number of newlines needed before this token. """ - def __init__(self, node): + def __init__(self, node, node_name=None): """Constructor. Arguments: node: (pytree.Leaf) The node that's being wrapped. + none_name: (string) The name of the node. """ self.node = node self.next_token = None @@ -108,7 +109,7 @@ def __init__(self, node): self.type = node.type self.column = node.column self.lineno = node.lineno - self.name = pytree_utils.NodeName(node) + self.name = pytree_utils.NodeName(node) if not node_name else node_name self.spaces_required_before = 0 if self.is_comment: diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py index 0dff5e194..e4cb9788f 100644 --- a/yapf/yapflib/py3compat.py +++ b/yapf/yapflib/py3compat.py @@ -50,9 +50,12 @@ def raw_input(): import tokenize detect_encoding = tokenize.detect_encoding + TokenInfo = tokenize.TokenInfo else: import __builtin__ import cStringIO + from itertools import ifilter + StringIO = BytesIO = cStringIO.StringIO open_with_encoding = io.open @@ -67,7 +70,6 @@ def fake_wrapper(user_function): range = xrange # noqa: F821 - from itertools import ifilter raw_input = raw_input import ConfigParser as configparser @@ -76,6 +78,12 @@ def fake_wrapper(user_function): from lib2to3.pgen2 import tokenize detect_encoding = tokenize.detect_encoding + import collections + + class TokenInfo( + collections.namedtuple('TokenInfo', 'type string start end line')): + pass + def EncodeAndWriteToStdout(s, encoding='utf-8'): """Encode the given string and emit to stdout. diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py new file mode 100644 index 000000000..3d2b9f79a --- /dev/null +++ b/yapf/yapflib/split_penalty.py @@ -0,0 +1,28 @@ +# Copyright 2022 Bill Wendling, All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +UNBREAKABLE = 1000**3 + +DOTTED_NAME = 4000 +VERY_STRONGLY_CONNECTED = 3500 +STRONGLY_CONNECTED = 3000 + +EXPR = 1000 + +ARGUMENT = 2500 + +DICT_KEY_EXPR = 2000 +DICT_VALUE_EXPR = 1100 + +LAMBDA = 10000 From 4574823591e2acf384c956642a362f8b9224995c Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 11 Jan 2022 11:34:52 -0800 Subject: [PATCH 538/719] Mark test target as "noqa" --- yapftests/reformatter_basic_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 599f131dc..1102a6f06 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1551,7 +1551,7 @@ def testNoSplittingAroundCompOperators(self): c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa is bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa <= bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) - """) + """) # noqa expected_code = textwrap.dedent("""\ c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa is not bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) From eb6c0d226bb185b62e4413b2c804e990bf127a3a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 11 Jan 2022 13:22:48 -0800 Subject: [PATCH 539/719] Use correct variable --- yapf/pyparser/split_penalty_visitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/pyparser/split_penalty_visitor.py b/yapf/pyparser/split_penalty_visitor.py index f886fd3af..7fbe4e8c0 100644 --- a/yapf/pyparser/split_penalty_visitor.py +++ b/yapf/pyparser/split_penalty_visitor.py @@ -462,7 +462,7 @@ def visit_GeneratorExp(self, node): def visit_Await(self, node): # Await(value=Expr) tokens = self._GetTokens(node) - _IncreasePenalty(element[1:], split_penalty.EXPR) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) return self.generic_visit(node) def visit_Yield(self, node): From ec16864e133b831015ab5b4cbc2e3a5be97b3313 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 11 Jan 2022 13:24:36 -0800 Subject: [PATCH 540/719] Remove unused variable --- yapf/pyparser/pyparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/pyparser/pyparser.py b/yapf/pyparser/pyparser.py index bec1cc3b1..7c6eecee3 100644 --- a/yapf/pyparser/pyparser.py +++ b/yapf/pyparser/pyparser.py @@ -68,7 +68,7 @@ def ParseCode(unformatted_source, filename=''): ast_tree = ast.parse(unformatted_source, filename) readline = py3compat.StringIO(unformatted_source).readline tokens = tokenize.generate_tokens(readline) - except Exception as e: + except Exception: raise logical_lines = _CreateLogicalLines(tokens) From 4a8507a2c1fe9468f6f1c79fdd5f508a9ce78b6a Mon Sep 17 00:00:00 2001 From: Mauricio Herrera Cuadra Date: Tue, 8 Feb 2022 11:27:53 -0800 Subject: [PATCH 541/719] Added pyproject extra to install toml package as an optional dependency (#964) * Add toml package as a dependency * Make toml an optional dependency via new pyproject extra --- CHANGELOG | 1 + setup.py | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 8487ada55..5ac3e6329 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -27,6 +27,7 @@ - Rename "unwrapped_line" module to "logical_line." - Rename "UnwrappedLine" class to "LogicalLine." ### Fixed +- Added pyproject extra to install toml package as an optional dependency. - Enable `BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF` knob for "pep8" style, so method definitions inside a class are surrounded by a single blank line as prescribed by PEP8. diff --git a/setup.py b/setup.py index 8b00835ab..86e938471 100644 --- a/setup.py +++ b/setup.py @@ -77,4 +77,7 @@ def run(self): cmdclass={ 'test': RunTests, }, + extras_require={ + 'pyproject': ['toml'], + }, ) From 20f0ca695de2749cb54b49f1db342dc0b67dc468 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 10 Feb 2022 23:29:48 -0800 Subject: [PATCH 542/719] Fix tests --- yapftests/reformatter_basic_test.py | 27 +++++++++++++++---------- yapftests/reformatter_buganizer_test.py | 4 ++-- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 1102a6f06..657d1e246 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1553,17 +1553,22 @@ def testNoSplittingAroundCompOperators(self): c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa <= bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) """) # noqa expected_code = textwrap.dedent("""\ - c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - is not bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) - c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - in bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) - c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - not in bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) - - c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - is bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) - c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - <= bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) + c = ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + is not bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) + c = ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + in bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) + c = ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + not in bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) + + c = ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + is bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) + c = ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + <= bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index b3de8f9b0..54a62b588 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -2221,8 +2221,8 @@ def testB15438132(self): # This is a comment in the middle of it all. kkkkkkk.llllllllll.mmmmmmmmmmmmm = True if (aaaaaa.bbbbb.ccccccccccccc != ddddddd.eeeeeeeeee.fffffffffffff or - eeeeee.fffff.ggggggggggggggggggggggggggg() != - hhhhhhh.iiiiiiiiii.jjjjjjjjjjjj): + eeeeee.fffff.ggggggggggggggggggggggggggg() + != hhhhhhh.iiiiiiiiii.jjjjjjjjjjjj): aaaaaaaa.bbbbbbbbbbbb( aaaaaa.bbbbb.cc, dddddddddddd=eeeeeeeeeeeeeeeeeee.fffffffffffffffff( From 322e5bfbd3a400dae7b7002aa278dc0712671864 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 26 Feb 2022 12:54:01 -0800 Subject: [PATCH 543/719] Fixup missing locations --- yapf/pyparser/pyparser.py | 1 + 1 file changed, 1 insertion(+) diff --git a/yapf/pyparser/pyparser.py b/yapf/pyparser/pyparser.py index 7c6eecee3..61cf45ed7 100644 --- a/yapf/pyparser/pyparser.py +++ b/yapf/pyparser/pyparser.py @@ -74,6 +74,7 @@ def ParseCode(unformatted_source, filename=''): logical_lines = _CreateLogicalLines(tokens) # Process the logical lines. + ast.fix_missing_locations(ast_tree) split_penalty_visitor.SplitPenalty(logical_lines).visit(ast_tree) return logical_lines From 44b1bd30e6194eea7b88e9aaaf0c9f6a8e7167f0 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 26 Feb 2022 12:54:42 -0800 Subject: [PATCH 544/719] Comment the method and move "import ast" into the debugging code --- yapf/pyparser/pyparser_utils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/yapf/pyparser/pyparser_utils.py b/yapf/pyparser/pyparser_utils.py index cbc3d503d..55e36b2d3 100644 --- a/yapf/pyparser/pyparser_utils.py +++ b/yapf/pyparser/pyparser_utils.py @@ -24,10 +24,10 @@ GetNextTokenIndex: Get the index of the next token after a given position. GetPrevTokenIndex: Get the index of the previous token before a given position. + TokenStart: Convenience function to return the token's start as a tuple. + TokenEnd: Convenience function to return the token's end as a tuple. """ -import ast - def FindTokensInRange(logical_lines, node): """Get a list of tokens within the range [start, end).""" @@ -91,4 +91,6 @@ def TokenEnd(node): def AstDump(node): + """Debugging code.""" + import ast print(ast.dump(node, include_attributes=True, indent=4)) From b04a4ef4273960c8e38f390580026d0a331b8d1b Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 26 Feb 2022 13:00:16 -0800 Subject: [PATCH 545/719] Reformat --- yapf/pyparser/split_penalty_visitor.py | 110 ++++++++++++++----------- 1 file changed, 60 insertions(+), 50 deletions(-) diff --git a/yapf/pyparser/split_penalty_visitor.py b/yapf/pyparser/split_penalty_visitor.py index 7fbe4e8c0..a2f771abc 100644 --- a/yapf/pyparser/split_penalty_visitor.py +++ b/yapf/pyparser/split_penalty_visitor.py @@ -31,8 +31,8 @@ def __init__(self, logical_lines): # We never want to split before a colon or comma. for logical_line in logical_lines: for token in logical_line.tokens: - if token.value in frozenset({',', ':'}): - token.split_penalty = split_penalty.UNBREAKABLE + if token.value in frozenset({',', ':'}): + token.split_penalty = split_penalty.UNBREAKABLE def _GetTokens(self, node): return pyutils.FindTokensInRange(self.logical_lines, node) @@ -65,8 +65,7 @@ def visit_FunctionDef(self, node): pyutils.TokenStart(node.returns)) _IncreasePenalty(tokens[start_index - 1:start_index + 1], split_penalty.VERY_STRONGLY_CONNECTED) - end_index = pyutils.GetTokenIndex(tokens, - pyutils.TokenEnd(node.returns)) + end_index = pyutils.GetTokenIndex(tokens, pyutils.TokenEnd(node.returns)) _IncreasePenalty(tokens[start_index + 1:end_index], split_penalty.STRONGLY_CONNECTED) @@ -297,8 +296,7 @@ def visit_UnaryOp(self, node): # operand=Expr) tokens = self._GetTokens(node) _IncreasePenalty(tokens[1:], split_penalty.EXPR) - _IncreasePenalty(tokens[1], - style.Get('SPLIT_PENALTY_AFTER_UNARY_OPERATOR')) + _IncreasePenalty(tokens[1], style.Get('SPLIT_PENALTY_AFTER_UNARY_OPERATOR')) return self.generic_visit(node) def visit_Lambda(self, node): @@ -331,13 +329,13 @@ def visit_Dict(self, node): # The keys should be on a single line if at all possible. for key in node.keys: - subrange = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(key), pyutils.TokenEnd(key)) + subrange = pyutils.GetTokensInSubRange(tokens, pyutils.TokenStart(key), + pyutils.TokenEnd(key)) _IncreasePenalty(subrange[1:], split_penalty.DICT_KEY_EXPR) for value in node.values: - subrange = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(value), pyutils.TokenEnd(value)) + subrange = pyutils.GetTokensInSubRange(tokens, pyutils.TokenStart(value), + pyutils.TokenEnd(value)) _IncreasePenalty(subrange[1:], split_penalty.DICT_VALUE_EXPR) return self.generic_visit(node) @@ -345,8 +343,9 @@ def visit_Set(self, node): # Set(elts=[Expr_1, Expr_2, ..., Expr_n]) tokens = self._GetTokens(node) for element in node.elts: - subrange = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(element), pyutils.TokenEnd(element)) + subrange = pyutils.GetTokensInSubRange(tokens, + pyutils.TokenStart(element), + pyutils.TokenEnd(element)) _IncreasePenalty(subrange[1:], split_penalty.EXPR) return self.generic_visit(node) @@ -361,18 +360,20 @@ def visit_ListComp(self, node): # ... # ]) tokens = self._GetTokens(node) - element = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(node.elt), pyutils.TokenEnd(node.elt)) + element = pyutils.GetTokensInSubRange(tokens, pyutils.TokenStart(node.elt), + pyutils.TokenEnd(node.elt)) _IncreasePenalty(element[1:], split_penalty.EXPR) for comp in node.generators: - subrange = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(comp.iter), pyutils.TokenEnd(comp.iter)) + subrange = pyutils.GetTokensInSubRange(tokens, + pyutils.TokenStart(comp.iter), + pyutils.TokenEnd(comp.iter)) _IncreasePenalty(subrange[1:], split_penalty.EXPR) for if_expr in comp.ifs: - subrange = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(if_expr), pyutils.TokenEnd(if_expr)) + subrange = pyutils.GetTokensInSubRange(tokens, + pyutils.TokenStart(if_expr), + pyutils.TokenEnd(if_expr)) _IncreasePenalty(subrange[1:], split_penalty.EXPR) return self.generic_visit(node) @@ -387,18 +388,20 @@ def visit_SetComp(self, node): # ... # ]) tokens = self._GetTokens(node) - element = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(node.elt), pyutils.TokenEnd(node.elt)) + element = pyutils.GetTokensInSubRange(tokens, pyutils.TokenStart(node.elt), + pyutils.TokenEnd(node.elt)) _IncreasePenalty(element[1:], split_penalty.EXPR) for comp in node.generators: - subrange = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(comp.iter), pyutils.TokenEnd(comp.iter)) + subrange = pyutils.GetTokensInSubRange(tokens, + pyutils.TokenStart(comp.iter), + pyutils.TokenEnd(comp.iter)) _IncreasePenalty(subrange[1:], split_penalty.EXPR) for if_expr in comp.ifs: - subrange = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(if_expr), pyutils.TokenEnd(if_expr)) + subrange = pyutils.GetTokensInSubRange(tokens, + pyutils.TokenStart(if_expr), + pyutils.TokenEnd(if_expr)) _IncreasePenalty(subrange[1:], split_penalty.EXPR) return self.generic_visit(node) @@ -414,22 +417,24 @@ def visit_DictComp(self, node): # ... # ]) tokens = self._GetTokens(node) - key = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(node.key), pyutils.TokenEnd(node.key)) + key = pyutils.GetTokensInSubRange(tokens, pyutils.TokenStart(node.key), + pyutils.TokenEnd(node.key)) _IncreasePenalty(key[1:], split_penalty.EXPR) - value = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(node.value), pyutils.TokenEnd(node.value)) + value = pyutils.GetTokensInSubRange(tokens, pyutils.TokenStart(node.value), + pyutils.TokenEnd(node.value)) _IncreasePenalty(value[1:], split_penalty.EXPR) for comp in node.generators: - subrange = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(comp.iter), pyutils.TokenEnd(comp.iter)) + subrange = pyutils.GetTokensInSubRange(tokens, + pyutils.TokenStart(comp.iter), + pyutils.TokenEnd(comp.iter)) _IncreasePenalty(subrange[1:], split_penalty.EXPR) for if_expr in comp.ifs: - subrange = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(if_expr), pyutils.TokenEnd(if_expr)) + subrange = pyutils.GetTokensInSubRange(tokens, + pyutils.TokenStart(if_expr), + pyutils.TokenEnd(if_expr)) _IncreasePenalty(subrange[1:], split_penalty.EXPR) return self.generic_visit(node) @@ -444,18 +449,20 @@ def visit_GeneratorExp(self, node): # ... # ]) tokens = self._GetTokens(node) - element = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(node.elt), pyutils.TokenEnd(node.elt)) + element = pyutils.GetTokensInSubRange(tokens, pyutils.TokenStart(node.elt), + pyutils.TokenEnd(node.elt)) _IncreasePenalty(element[1:], split_penalty.EXPR) for comp in node.generators: - subrange = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(comp.iter), pyutils.TokenEnd(comp.iter)) + subrange = pyutils.GetTokensInSubRange(tokens, + pyutils.TokenStart(comp.iter), + pyutils.TokenEnd(comp.iter)) _IncreasePenalty(subrange[1:], split_penalty.EXPR) for if_expr in comp.ifs: - subrange = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(if_expr), pyutils.TokenEnd(if_expr)) + subrange = pyutils.GetTokensInSubRange(tokens, + pyutils.TokenStart(if_expr), + pyutils.TokenEnd(if_expr)) _IncreasePenalty(subrange[1:], split_penalty.EXPR) return self.generic_visit(node) @@ -510,13 +517,12 @@ def visit_Call(self, node): tokens = self._GetTokens(node) # Don't never split before the opening parenthesis. - paren_index = pyutils.GetNextTokenIndex(tokens, - pyutils.TokenEnd(node.func)) + paren_index = pyutils.GetNextTokenIndex(tokens, pyutils.TokenEnd(node.func)) _IncreasePenalty(tokens[paren_index], split_penalty.UNBREAKABLE) for arg in node.args: - subrange = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(arg), pyutils.TokenEnd(arg)) + subrange = pyutils.GetTokensInSubRange(tokens, pyutils.TokenStart(arg), + pyutils.TokenEnd(arg)) _IncreasePenalty(subrange[1:], split_penalty.EXPR) return self.generic_visit(node) @@ -570,8 +576,9 @@ def visit_List(self, node): # List(elts=[Expr_1, Expr_2, ..., Expr_n]) tokens = self._GetTokens(node) for element in node.elts: - subrange = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(element), pyutils.TokenEnd(element)) + subrange = pyutils.GetTokensInSubRange(tokens, + pyutils.TokenStart(element), + pyutils.TokenEnd(element)) _IncreasePenalty(subrange[1:], split_penalty.EXPR) _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) return self.generic_visit(node) @@ -580,8 +587,9 @@ def visit_Tuple(self, node): # Tuple(elts=[Expr_1, Expr_2, ..., Expr_n]) tokens = self._GetTokens(node) for element in node.elts: - subrange = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(element), pyutils.TokenEnd(element)) + subrange = pyutils.GetTokensInSubRange(tokens, + pyutils.TokenStart(element), + pyutils.TokenEnd(element)) _IncreasePenalty(subrange[1:], split_penalty.EXPR) _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) return self.generic_visit(node) @@ -602,8 +610,9 @@ def visit_Slice(self, node): colon_index = pyutils.GetPrevTokenIndex(tokens, pyutils.TokenStart(node.upper)) _IncreasePenalty(tokens[colon_index], split_penalty.UNBREAKABLE) - subrange = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(node.upper), pyutils.TokenEnd(node.upper)) + subrange = pyutils.GetTokensInSubRange(tokens, + pyutils.TokenStart(node.upper), + pyutils.TokenEnd(node.upper)) _IncreasePenalty(subrange, split_penalty.EXPR) _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) @@ -611,8 +620,9 @@ def visit_Slice(self, node): colon_index = pyutils.GetPrevTokenIndex(tokens, pyutils.TokenStart(node.step)) _IncreasePenalty(tokens[colon_index], split_penalty.UNBREAKABLE) - subrange = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(node.step), pyutils.TokenEnd(node.step)) + subrange = pyutils.GetTokensInSubRange(tokens, + pyutils.TokenStart(node.step), + pyutils.TokenEnd(node.step)) _IncreasePenalty(subrange, split_penalty.EXPR) _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) From f94ecb1183c459e05933b171ce982b4be20dfe00 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 26 Feb 2022 13:01:10 -0800 Subject: [PATCH 546/719] Don't try to reformat formatted values --- yapf/pyparser/split_penalty_visitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/pyparser/split_penalty_visitor.py b/yapf/pyparser/split_penalty_visitor.py index a2f771abc..916866bd4 100644 --- a/yapf/pyparser/split_penalty_visitor.py +++ b/yapf/pyparser/split_penalty_visitor.py @@ -529,7 +529,7 @@ def visit_Call(self, node): def visit_FormattedValue(self, node): # FormattedValue(value=Expr, # conversion=-1) - return self.generic_visit(node) + return node # Ignore formatted values. def visit_JoinedStr(self, node): # JoinedStr(values=[Expr_1, Expr_2, ..., Expr_n]) From c6069b8fd69fea7b3133aa94b450a34ba0ffdd96 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 26 Feb 2022 13:01:31 -0800 Subject: [PATCH 547/719] Make sure the things we're formatted exist --- yapf/pyparser/split_penalty_visitor.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/yapf/pyparser/split_penalty_visitor.py b/yapf/pyparser/split_penalty_visitor.py index 916866bd4..9954d0269 100644 --- a/yapf/pyparser/split_penalty_visitor.py +++ b/yapf/pyparser/split_penalty_visitor.py @@ -600,13 +600,14 @@ def visit_Slice(self, node): # step=Expr) tokens = self._GetTokens(node) - if hasattr(node, 'lower'): - subrange = pyutils.GetTokensInSubRange( - tokens, pyutils.TokenStart(node.lower), pyutils.TokenEnd(node.lower)) + if hasattr(node, 'lower') and node.lower: + subrange = pyutils.GetTokensInSubRange(tokens, + pyutils.TokenStart(node.lower), + pyutils.TokenEnd(node.lower)) _IncreasePenalty(subrange, split_penalty.EXPR) _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) - if hasattr(node, 'upper'): + if hasattr(node, 'upper') and node.upper: colon_index = pyutils.GetPrevTokenIndex(tokens, pyutils.TokenStart(node.upper)) _IncreasePenalty(tokens[colon_index], split_penalty.UNBREAKABLE) @@ -616,7 +617,7 @@ def visit_Slice(self, node): _IncreasePenalty(subrange, split_penalty.EXPR) _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) - if hasattr(node, 'step'): + if hasattr(node, 'step') and node.step: colon_index = pyutils.GetPrevTokenIndex(tokens, pyutils.TokenStart(node.step)) _IncreasePenalty(tokens[colon_index], split_penalty.UNBREAKABLE) From 32c2c67981f5aac71dc3816712696890e6c16e10 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 26 Feb 2022 13:32:36 -0800 Subject: [PATCH 548/719] Fix some minor wording and capitalization. --- README.rst | 30 ++++++++++++++++-------------- yapf/__init__.py | 2 +- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/README.rst b/README.rst index 087f2ab36..5734a5d76 100644 --- a/README.rst +++ b/README.rst @@ -90,21 +90,22 @@ Usage Options:: - usage: yapf [-h] [-v] [-d | -i] [-r | -l START-END] [-e PATTERN] + usage: yapf [-h] [-v] [-d | -i | -q] [-r | -l START-END] [-e PATTERN] [--style STYLE] [--style-help] [--no-local-style] [-p] [-vv] - [files [files ...]] + [files ...] Formatter for Python code. positional arguments: - files + files reads from stdin when no files are specified. optional arguments: -h, --help show this help message and exit - -v, --version show version number and exit + -v, --version show program's version number and exit -d, --diff print the diff for the fixed source -i, --in-place make changes to files in place + -q, --quiet output nothing and set return value -r, --recursive run recursively over directories -l START-END, --lines START-END range of lines to reformat, one-based @@ -112,17 +113,18 @@ Options:: patterns for files to exclude from formatting --style STYLE specify formatting style: either a style name (for example "pep8" or "google"), or the name of a file - with style settings. The default is pep8 unless a + with style settings. The default is pep8 unless a .style.yapf or setup.cfg or pyproject.toml file - located in the same directory as the source or one of - its parent directories (for stdin, the current + located in the same directory as the source or one + of its parent directories (for stdin, the current directory is used). - --style-help show style settings and exit; this output can be saved - to .style.yapf to make your settings permanent + --style-help show style settings and exit; this output can be + saved to .style.yapf to make your settings + permanent --no-local-style don't search for local style definition - -p, --parallel Run yapf in parallel when formatting multiple files. - Requires concurrent.futures in Python 2.X - -vv, --verbose Print out file names while processing + -p, --parallel run YAPF in parallel when formatting multiple + files. Requires concurrent.futures in Python 2.X + -vv, --verbose print out file names while processing ------------ @@ -273,7 +275,7 @@ and reformat it into: Example as a module =================== -The two main APIs for calling yapf are ``FormatCode`` and ``FormatFile``, these +The two main APIs for calling YAPF are ``FormatCode`` and ``FormatFile``, these share several arguments which are described below: .. code-block:: python @@ -383,7 +385,7 @@ Options:: located in the same directory as the source or one of its parent directories (for stdin, the current directory is used). - --binary BINARY location of binary to use for yapf + --binary BINARY location of binary to use for YAPF Knobs ===== diff --git a/yapf/__init__.py b/yapf/__init__.py index 0c2fb952c..94e445b59 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -342,7 +342,7 @@ def _BuildParser(): '-p', '--parallel', action='store_true', - help=('run yapf in parallel when formatting multiple files. Requires ' + help=('run YAPF in parallel when formatting multiple files. Requires ' 'concurrent.futures in Python 2.X')) parser.add_argument( '-vv', From 2a08bd806af47ced506511438a6da2965ad8d8a5 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 26 Feb 2022 14:02:43 -0800 Subject: [PATCH 549/719] Explain the "decorator" code a bit better --- yapf/pyparser/split_penalty_visitor.py | 38 ++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/yapf/pyparser/split_penalty_visitor.py b/yapf/pyparser/split_penalty_visitor.py index 9954d0269..220190be7 100644 --- a/yapf/pyparser/split_penalty_visitor.py +++ b/yapf/pyparser/split_penalty_visitor.py @@ -51,11 +51,13 @@ def visit_FunctionDef(self, node): # kw_defaults=[], # defaults=[]), # body=[...], - # decorator_list=[Expr_1, Expr_2, ..., Expr_n], + # decorator_list=[Call_1, Call_2, ..., Call_n], # keywords=[]) for decorator in node.decorator_list: - # Don't split after the '@'. + # The decorator token list begins after the '@'. The body of the decorator + # is formatted like a normal "call." tokens = self._GetTokens(decorator) + # Don't split after the '@'. tokens[0].split_penalty = split_penalty.UNBREAKABLE tokens = self._GetTokens(node) @@ -85,6 +87,7 @@ def visit_AsyncFunctionDef(self, node): # keywords=[]) tokens = self._GetTokens(node) _IncreasePenalty(tokens[1], split_penalty.UNBREAKABLE) + return self.visit_FunctionDef(node) def visit_ClassDef(self, node): @@ -108,6 +111,7 @@ def visit_Return(self, node): # Return(value=Expr) tokens = self._GetTokens(node) _IncreasePenalty(tokens[1:], split_penalty.EXPR) + return self.generic_visit(node) def visit_Delete(self, node): @@ -115,6 +119,7 @@ def visit_Delete(self, node): for target in node.targets: tokens = self._GetTokens(target) _IncreasePenalty(tokens[1:], split_penalty.EXPR) + return self.generic_visit(node) def visit_Assign(self, node): @@ -122,6 +127,7 @@ def visit_Assign(self, node): # value=Expr) tokens = self._GetTokens(node) _IncreasePenalty(tokens[1:], split_penalty.EXPR) + return self.generic_visit(node) def visit_AugAssign(self, node): @@ -272,6 +278,7 @@ def visit_NamedExpr(self, node): # value=Expr) tokens = self._GetTokens(node) _IncreasePenalty(tokens[1:], split_penalty.EXPR) + return self.generic_visit(node) def visit_BinOp(self, node): @@ -288,7 +295,9 @@ def visit_BinOp(self, node): pyutils.TokenEnd(node.left)) if not style.Get('SPLIT_BEFORE_ARITHMETIC_OPERATOR'): operator_index += 1 + _DecreasePenalty(tokens[operator_index], split_penalty.EXPR * 2) + return self.generic_visit(node) def visit_UnaryOp(self, node): @@ -297,6 +306,7 @@ def visit_UnaryOp(self, node): tokens = self._GetTokens(node) _IncreasePenalty(tokens[1:], split_penalty.EXPR) _IncreasePenalty(tokens[1], style.Get('SPLIT_PENALTY_AFTER_UNARY_OPERATOR')) + return self.generic_visit(node) def visit_Lambda(self, node): @@ -309,9 +319,11 @@ def visit_Lambda(self, node): # body=Expr) tokens = self._GetTokens(node) _IncreasePenalty(tokens[1:], split_penalty.LAMBDA) + if style.Get('ALLOW_MULTILINE_LAMBDAS'): tokens = self._GetTokens(node.body) _DecreasePenalty(tokens[1], split_penalty.LAMBDA) + return self.generic_visit(node) def visit_IfExp(self, node): @@ -320,6 +332,7 @@ def visit_IfExp(self, node): # orelse=OrElseExpr) tokens = self._GetTokens(node) _IncreasePenalty(tokens[1:], split_penalty.EXPR) + return self.generic_visit(node) def visit_Dict(self, node): @@ -337,6 +350,7 @@ def visit_Dict(self, node): subrange = pyutils.GetTokensInSubRange(tokens, pyutils.TokenStart(value), pyutils.TokenEnd(value)) _IncreasePenalty(subrange[1:], split_penalty.DICT_VALUE_EXPR) + return self.generic_visit(node) def visit_Set(self, node): @@ -347,6 +361,7 @@ def visit_Set(self, node): pyutils.TokenStart(element), pyutils.TokenEnd(element)) _IncreasePenalty(subrange[1:], split_penalty.EXPR) + return self.generic_visit(node) def visit_ListComp(self, node): @@ -375,6 +390,7 @@ def visit_ListComp(self, node): pyutils.TokenStart(if_expr), pyutils.TokenEnd(if_expr)) _IncreasePenalty(subrange[1:], split_penalty.EXPR) + return self.generic_visit(node) def visit_SetComp(self, node): @@ -403,6 +419,7 @@ def visit_SetComp(self, node): pyutils.TokenStart(if_expr), pyutils.TokenEnd(if_expr)) _IncreasePenalty(subrange[1:], split_penalty.EXPR) + return self.generic_visit(node) def visit_DictComp(self, node): @@ -436,6 +453,7 @@ def visit_DictComp(self, node): pyutils.TokenStart(if_expr), pyutils.TokenEnd(if_expr)) _IncreasePenalty(subrange[1:], split_penalty.EXPR) + return self.generic_visit(node) def visit_GeneratorExp(self, node): @@ -464,18 +482,21 @@ def visit_GeneratorExp(self, node): pyutils.TokenStart(if_expr), pyutils.TokenEnd(if_expr)) _IncreasePenalty(subrange[1:], split_penalty.EXPR) + return self.generic_visit(node) def visit_Await(self, node): # Await(value=Expr) tokens = self._GetTokens(node) _IncreasePenalty(tokens[1:], split_penalty.EXPR) + return self.generic_visit(node) def visit_Yield(self, node): # Yield(value=Expr) tokens = self._GetTokens(node) _IncreasePenalty(tokens[1:], split_penalty.EXPR) + return self.generic_visit(node) def visit_YieldFrom(self, node): @@ -483,6 +504,7 @@ def visit_YieldFrom(self, node): tokens = self._GetTokens(node) _IncreasePenalty(tokens[1:], split_penalty.EXPR) tokens[2].split_penalty = split_penalty.UNBREAKABLE + return self.generic_visit(node) def visit_Compare(self, node): @@ -499,10 +521,12 @@ def visit_Compare(self, node): for comparator in node.comparators[:-1] ] split_before = style.Get('SPLIT_BEFORE_ARITHMETIC_OPERATOR') + for operator_index in operator_indices: if not split_before: operator_index += 1 _DecreasePenalty(tokens[operator_index], split_penalty.EXPR * 2) + return self.generic_visit(node) def visit_Call(self, node): @@ -524,6 +548,7 @@ def visit_Call(self, node): subrange = pyutils.GetTokensInSubRange(tokens, pyutils.TokenStart(arg), pyutils.TokenEnd(arg)) _IncreasePenalty(subrange[1:], split_penalty.EXPR) + return self.generic_visit(node) def visit_FormattedValue(self, node): @@ -546,9 +571,11 @@ def visit_Attribute(self, node): split_before = style.Get('SPLIT_BEFORE_DOT') dot_indices = pyutils.GetNextTokenIndex(tokens, pyutils.TokenEnd(node.value)) + if not split_before: dot_indices += 1 _IncreasePenalty(tokens[dot_indices], split_penalty.VERY_STRONGLY_CONNECTED) + return self.generic_visit(node) def visit_Subscript(self, node): @@ -560,6 +587,7 @@ def visit_Subscript(self, node): bracket_index = pyutils.GetNextTokenIndex(tokens, pyutils.TokenEnd(node.value)) _IncreasePenalty(tokens[bracket_index], split_penalty.UNBREAKABLE) + return self.generic_visit(node) def visit_Starred(self, node): @@ -570,28 +598,33 @@ def visit_Name(self, node): # Name(id=Identifier) tokens = self._GetTokens(node) _IncreasePenalty(tokens[1:], split_penalty.UNBREAKABLE) + return self.generic_visit(node) def visit_List(self, node): # List(elts=[Expr_1, Expr_2, ..., Expr_n]) tokens = self._GetTokens(node) + for element in node.elts: subrange = pyutils.GetTokensInSubRange(tokens, pyutils.TokenStart(element), pyutils.TokenEnd(element)) _IncreasePenalty(subrange[1:], split_penalty.EXPR) _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) + return self.generic_visit(node) def visit_Tuple(self, node): # Tuple(elts=[Expr_1, Expr_2, ..., Expr_n]) tokens = self._GetTokens(node) + for element in node.elts: subrange = pyutils.GetTokensInSubRange(tokens, pyutils.TokenStart(element), pyutils.TokenEnd(element)) _IncreasePenalty(subrange[1:], split_penalty.EXPR) _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) + return self.generic_visit(node) def visit_Slice(self, node): @@ -864,6 +897,7 @@ def visit_arg(self, node): # type_comment='') tokens = self._GetTokens(node) _IncreasePenalty(tokens[1:], split_penalty.ARGUMENT) + return self.generic_visit(node) def visit_keyword(self, node): From 4c7f3defb66a3d5fab3d8673b117fe3691717ebb Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 26 Feb 2022 14:03:26 -0800 Subject: [PATCH 550/719] Use "for ... enumerate(...)" instead of the awkward "for" loop --- yapf/pyparser/pyparser_utils.py | 37 +++++++++++++++++---------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/yapf/pyparser/pyparser_utils.py b/yapf/pyparser/pyparser_utils.py index 55e36b2d3..cd0d84da4 100644 --- a/yapf/pyparser/pyparser_utils.py +++ b/yapf/pyparser/pyparser_utils.py @@ -34,52 +34,53 @@ def FindTokensInRange(logical_lines, node): start = (node.lineno, node.col_offset) end = (node.end_lineno, node.end_col_offset) tokens = [] + for line in logical_lines: if line.start > end: break if line.start <= start or line.end >= end: tokens.extend(GetTokensInSubRange(line.tokens, start, end)) + return tokens def GetTokensInSubRange(tokens, start, end): """Get a subset of tokens within the range [start, end).""" tokens_in_range = [] + for tok in tokens: tok_range = (tok.lineno, tok.column) if tok_range >= start and tok_range < end: tokens_in_range.append(tok) + return tokens_in_range def GetTokenIndex(tokens, pos): """Get the index of the token at 'pos.'""" - index = 0 - while index < len(tokens): - if (tokens[index].lineno, tokens[index].column) == pos: - break - index += 1 - return index + for index, token in enumerate(tokens): + if (token.lineno, token.column) == pos: + return index + + return None def GetNextTokenIndex(tokens, pos): """Get the index of the next token after 'pos.'""" - index = 0 - while index < len(tokens): - if (tokens[index].lineno, tokens[index].column) >= pos: - break - index += 1 - return index + for index, token in enumerate(tokens): + if (token.lineno, token.column) >= pos: + return index + + return None def GetPrevTokenIndex(tokens, pos): """Get the index of the previous token before 'pos.'""" - index = 1 - while index < len(tokens): - if (tokens[index].lineno, tokens[index].column) >= pos: - break - index += 1 - return index - 1 + for index, token in enumerate(tokens): + if index > 0 and (token.lineno, token.column) >= pos: + return index - 1 + + return None def TokenStart(node): From 5317beeb84e93247285fd5a70b86d9802d1b1ade Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 26 Feb 2022 15:24:25 -0800 Subject: [PATCH 551/719] Clean up API so that we don't have to pass in start and end tuples --- yapf/pyparser/pyparser_utils.py | 30 ++++---- yapf/pyparser/split_penalty_visitor.py | 96 +++++++++----------------- 2 files changed, 51 insertions(+), 75 deletions(-) diff --git a/yapf/pyparser/pyparser_utils.py b/yapf/pyparser/pyparser_utils.py index cd0d84da4..72d8f0805 100644 --- a/yapf/pyparser/pyparser_utils.py +++ b/yapf/pyparser/pyparser_utils.py @@ -16,7 +16,7 @@ This module collects various utilities related to the parse trees produced by the pyparser. - FindTokensInRange: produces a list of tokens from the logical lines within a + GetNodeTokens: produces a list of tokens from the logical lines within a range. GetTokensInSubRange: produces a sublist of tokens from a current token list within a range. @@ -29,23 +29,25 @@ """ -def FindTokensInRange(logical_lines, node): - """Get a list of tokens within the range [start, end).""" - start = (node.lineno, node.col_offset) - end = (node.end_lineno, node.end_col_offset) +def GetTokens(logical_lines, node): + """Get a list of tokens within the node's range from the logical lines.""" + start = TokenStart(node) + end = TokenEnd(node) tokens = [] for line in logical_lines: if line.start > end: break if line.start <= start or line.end >= end: - tokens.extend(GetTokensInSubRange(line.tokens, start, end)) + tokens.extend(GetTokensInSubRange(line.tokens, node)) return tokens -def GetTokensInSubRange(tokens, start, end): - """Get a subset of tokens within the range [start, end).""" +def GetTokensInSubRange(tokens, node): + """Get a subset of tokens representing the node.""" + start = TokenStart(node) + end = TokenEnd(node) tokens_in_range = [] for tok in tokens: @@ -57,7 +59,7 @@ def GetTokensInSubRange(tokens, start, end): def GetTokenIndex(tokens, pos): - """Get the index of the token at 'pos.'""" + """Get the index of the token at pos.""" for index, token in enumerate(tokens): if (token.lineno, token.column) == pos: return index @@ -66,7 +68,7 @@ def GetTokenIndex(tokens, pos): def GetNextTokenIndex(tokens, pos): - """Get the index of the next token after 'pos.'""" + """Get the index of the next token after pos.""" for index, token in enumerate(tokens): if (token.lineno, token.column) >= pos: return index @@ -75,7 +77,7 @@ def GetNextTokenIndex(tokens, pos): def GetPrevTokenIndex(tokens, pos): - """Get the index of the previous token before 'pos.'""" + """Get the index of the previous token before pos.""" for index, token in enumerate(tokens): if index > 0 and (token.lineno, token.column) >= pos: return index - 1 @@ -91,7 +93,11 @@ def TokenEnd(node): return (node.end_lineno, node.end_col_offset) +############################################################################# +### Code for debugging ### +############################################################################# + + def AstDump(node): - """Debugging code.""" import ast print(ast.dump(node, include_attributes=True, indent=4)) diff --git a/yapf/pyparser/split_penalty_visitor.py b/yapf/pyparser/split_penalty_visitor.py index 220190be7..5955bba2b 100644 --- a/yapf/pyparser/split_penalty_visitor.py +++ b/yapf/pyparser/split_penalty_visitor.py @@ -35,7 +35,7 @@ def __init__(self, logical_lines): token.split_penalty = split_penalty.UNBREAKABLE def _GetTokens(self, node): - return pyutils.FindTokensInRange(self.logical_lines, node) + return pyutils.GetTokens(self.logical_lines, node) ############################################################################ # Statements # @@ -53,14 +53,13 @@ def visit_FunctionDef(self, node): # body=[...], # decorator_list=[Call_1, Call_2, ..., Call_n], # keywords=[]) + tokens = self._GetTokens(node) for decorator in node.decorator_list: # The decorator token list begins after the '@'. The body of the decorator # is formatted like a normal "call." - tokens = self._GetTokens(decorator) + subrange = pyutils.GetTokensInSubRange(tokens, decorator) # Don't split after the '@'. - tokens[0].split_penalty = split_penalty.UNBREAKABLE - - tokens = self._GetTokens(node) + subrange[0].split_penalty = split_penalty.UNBREAKABLE if node.returns: start_index = pyutils.GetTokenIndex(tokens, @@ -342,13 +341,11 @@ def visit_Dict(self, node): # The keys should be on a single line if at all possible. for key in node.keys: - subrange = pyutils.GetTokensInSubRange(tokens, pyutils.TokenStart(key), - pyutils.TokenEnd(key)) + subrange = pyutils.GetTokensInSubRange(tokens, key) _IncreasePenalty(subrange[1:], split_penalty.DICT_KEY_EXPR) for value in node.values: - subrange = pyutils.GetTokensInSubRange(tokens, pyutils.TokenStart(value), - pyutils.TokenEnd(value)) + subrange = pyutils.GetTokensInSubRange(tokens, value) _IncreasePenalty(subrange[1:], split_penalty.DICT_VALUE_EXPR) return self.generic_visit(node) @@ -357,9 +354,7 @@ def visit_Set(self, node): # Set(elts=[Expr_1, Expr_2, ..., Expr_n]) tokens = self._GetTokens(node) for element in node.elts: - subrange = pyutils.GetTokensInSubRange(tokens, - pyutils.TokenStart(element), - pyutils.TokenEnd(element)) + subrange = pyutils.GetTokensInSubRange(tokens, element) _IncreasePenalty(subrange[1:], split_penalty.EXPR) return self.generic_visit(node) @@ -375,20 +370,15 @@ def visit_ListComp(self, node): # ... # ]) tokens = self._GetTokens(node) - element = pyutils.GetTokensInSubRange(tokens, pyutils.TokenStart(node.elt), - pyutils.TokenEnd(node.elt)) + element = pyutils.GetTokensInSubRange(tokens, node.elt) _IncreasePenalty(element[1:], split_penalty.EXPR) for comp in node.generators: - subrange = pyutils.GetTokensInSubRange(tokens, - pyutils.TokenStart(comp.iter), - pyutils.TokenEnd(comp.iter)) + subrange = pyutils.GetTokensInSubRange(tokens, comp.iter) _IncreasePenalty(subrange[1:], split_penalty.EXPR) for if_expr in comp.ifs: - subrange = pyutils.GetTokensInSubRange(tokens, - pyutils.TokenStart(if_expr), - pyutils.TokenEnd(if_expr)) + subrange = pyutils.GetTokensInSubRange(tokens, if_expr) _IncreasePenalty(subrange[1:], split_penalty.EXPR) return self.generic_visit(node) @@ -404,20 +394,15 @@ def visit_SetComp(self, node): # ... # ]) tokens = self._GetTokens(node) - element = pyutils.GetTokensInSubRange(tokens, pyutils.TokenStart(node.elt), - pyutils.TokenEnd(node.elt)) + element = pyutils.GetTokensInSubRange(tokens, node.elt) _IncreasePenalty(element[1:], split_penalty.EXPR) for comp in node.generators: - subrange = pyutils.GetTokensInSubRange(tokens, - pyutils.TokenStart(comp.iter), - pyutils.TokenEnd(comp.iter)) + subrange = pyutils.GetTokensInSubRange(tokens, comp.iter) _IncreasePenalty(subrange[1:], split_penalty.EXPR) for if_expr in comp.ifs: - subrange = pyutils.GetTokensInSubRange(tokens, - pyutils.TokenStart(if_expr), - pyutils.TokenEnd(if_expr)) + subrange = pyutils.GetTokensInSubRange(tokens, if_expr) _IncreasePenalty(subrange[1:], split_penalty.EXPR) return self.generic_visit(node) @@ -434,24 +419,18 @@ def visit_DictComp(self, node): # ... # ]) tokens = self._GetTokens(node) - key = pyutils.GetTokensInSubRange(tokens, pyutils.TokenStart(node.key), - pyutils.TokenEnd(node.key)) + key = pyutils.GetTokensInSubRange(tokens, node.key) _IncreasePenalty(key[1:], split_penalty.EXPR) - value = pyutils.GetTokensInSubRange(tokens, pyutils.TokenStart(node.value), - pyutils.TokenEnd(node.value)) + value = pyutils.GetTokensInSubRange(tokens, node.value) _IncreasePenalty(value[1:], split_penalty.EXPR) for comp in node.generators: - subrange = pyutils.GetTokensInSubRange(tokens, - pyutils.TokenStart(comp.iter), - pyutils.TokenEnd(comp.iter)) + subrange = pyutils.GetTokensInSubRange(tokens, comp.iter) _IncreasePenalty(subrange[1:], split_penalty.EXPR) for if_expr in comp.ifs: - subrange = pyutils.GetTokensInSubRange(tokens, - pyutils.TokenStart(if_expr), - pyutils.TokenEnd(if_expr)) + subrange = pyutils.GetTokensInSubRange(tokens, if_expr) _IncreasePenalty(subrange[1:], split_penalty.EXPR) return self.generic_visit(node) @@ -467,20 +446,15 @@ def visit_GeneratorExp(self, node): # ... # ]) tokens = self._GetTokens(node) - element = pyutils.GetTokensInSubRange(tokens, pyutils.TokenStart(node.elt), - pyutils.TokenEnd(node.elt)) + element = pyutils.GetTokensInSubRange(tokens, node.elt) _IncreasePenalty(element[1:], split_penalty.EXPR) for comp in node.generators: - subrange = pyutils.GetTokensInSubRange(tokens, - pyutils.TokenStart(comp.iter), - pyutils.TokenEnd(comp.iter)) + subrange = pyutils.GetTokensInSubRange(tokens, comp.iter) _IncreasePenalty(subrange[1:], split_penalty.EXPR) for if_expr in comp.ifs: - subrange = pyutils.GetTokensInSubRange(tokens, - pyutils.TokenStart(if_expr), - pyutils.TokenEnd(if_expr)) + subrange = pyutils.GetTokensInSubRange(tokens, if_expr) _IncreasePenalty(subrange[1:], split_penalty.EXPR) return self.generic_visit(node) @@ -545,8 +519,7 @@ def visit_Call(self, node): _IncreasePenalty(tokens[paren_index], split_penalty.UNBREAKABLE) for arg in node.args: - subrange = pyutils.GetTokensInSubRange(tokens, pyutils.TokenStart(arg), - pyutils.TokenEnd(arg)) + subrange = pyutils.GetTokensInSubRange(tokens, arg) _IncreasePenalty(subrange[1:], split_penalty.EXPR) return self.generic_visit(node) @@ -606,9 +579,7 @@ def visit_List(self, node): tokens = self._GetTokens(node) for element in node.elts: - subrange = pyutils.GetTokensInSubRange(tokens, - pyutils.TokenStart(element), - pyutils.TokenEnd(element)) + subrange = pyutils.GetTokensInSubRange(tokens, element) _IncreasePenalty(subrange[1:], split_penalty.EXPR) _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) @@ -619,9 +590,7 @@ def visit_Tuple(self, node): tokens = self._GetTokens(node) for element in node.elts: - subrange = pyutils.GetTokensInSubRange(tokens, - pyutils.TokenStart(element), - pyutils.TokenEnd(element)) + subrange = pyutils.GetTokensInSubRange(tokens, element) _IncreasePenalty(subrange[1:], split_penalty.EXPR) _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) @@ -634,9 +603,7 @@ def visit_Slice(self, node): tokens = self._GetTokens(node) if hasattr(node, 'lower') and node.lower: - subrange = pyutils.GetTokensInSubRange(tokens, - pyutils.TokenStart(node.lower), - pyutils.TokenEnd(node.lower)) + subrange = pyutils.GetTokensInSubRange(tokens, node.lower) _IncreasePenalty(subrange, split_penalty.EXPR) _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) @@ -644,9 +611,7 @@ def visit_Slice(self, node): colon_index = pyutils.GetPrevTokenIndex(tokens, pyutils.TokenStart(node.upper)) _IncreasePenalty(tokens[colon_index], split_penalty.UNBREAKABLE) - subrange = pyutils.GetTokensInSubRange(tokens, - pyutils.TokenStart(node.upper), - pyutils.TokenEnd(node.upper)) + subrange = pyutils.GetTokensInSubRange(tokens, node.upper) _IncreasePenalty(subrange, split_penalty.EXPR) _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) @@ -654,9 +619,7 @@ def visit_Slice(self, node): colon_index = pyutils.GetPrevTokenIndex(tokens, pyutils.TokenStart(node.step)) _IncreasePenalty(tokens[colon_index], split_penalty.UNBREAKABLE) - subrange = pyutils.GetTokensInSubRange(tokens, - pyutils.TokenStart(node.step), - pyutils.TokenEnd(node.step)) + subrange = pyutils.GetTokensInSubRange(tokens, node.step) _IncreasePenalty(subrange, split_penalty.EXPR) _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) @@ -934,3 +897,10 @@ def _DecreasePenalty(tokens, amt): tokens = [tokens] for token in tokens: token.split_penalty -= amt + + +def _SetPenalty(tokens, amt): + if not isinstance(tokens, list): + tokens = [tokens] + for token in tokens: + token.split_penalty = amt From 8cae3db180a0ee349842f6f522807a725f36dff1 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 26 Feb 2022 15:27:21 -0800 Subject: [PATCH 552/719] Clean up how multiline lambdas are handled --- yapf/pyparser/split_penalty_visitor.py | 3 +-- yapf/yapflib/split_penalty.py | 29 ++++++++++++++++++-------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/yapf/pyparser/split_penalty_visitor.py b/yapf/pyparser/split_penalty_visitor.py index 5955bba2b..aae55b22c 100644 --- a/yapf/pyparser/split_penalty_visitor.py +++ b/yapf/pyparser/split_penalty_visitor.py @@ -320,8 +320,7 @@ def visit_Lambda(self, node): _IncreasePenalty(tokens[1:], split_penalty.LAMBDA) if style.Get('ALLOW_MULTILINE_LAMBDAS'): - tokens = self._GetTokens(node.body) - _DecreasePenalty(tokens[1], split_penalty.LAMBDA) + _SetPenalty(self._GetTokens(node.body), split_penalty.MULTIPLINE_LAMBDA) return self.generic_visit(node) diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 3d2b9f79a..f3f136385 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -12,17 +12,28 @@ # See the License for the specific language governing permissions and # limitations under the License. -UNBREAKABLE = 1000**3 +from yapf.yapflib import style -DOTTED_NAME = 4000 -VERY_STRONGLY_CONNECTED = 3500 -STRONGLY_CONNECTED = 3000 +# Generic split penalties +UNBREAKABLE = 1000**5 +VERY_STRONGLY_CONNECTED = 5000 +STRONGLY_CONNECTED = 2500 -EXPR = 1000 +############################################################################# +### Grammar-specific penalties - should be <= 1000 ### +############################################################################# -ARGUMENT = 2500 +# Lambdas shouldn't be split unless absolutely necessary or if +# ALLOW_MULTILINE_LAMBDAS is True. +LAMBDA = 1000 +MULTILINE_LAMBDA = 500 -DICT_KEY_EXPR = 2000 -DICT_VALUE_EXPR = 1100 +ANNOTATION = 100 +ARGUMENT = 25 -LAMBDA = 10000 +# TODO: Assign real values. +RETURN_TYPE = 1 +DOTTED_NAME = 40 +EXPR = 10 +DICT_KEY_EXPR = 20 +DICT_VALUE_EXPR = 11 From fbe63050c1c4b48d1b8968083eed9605ffe92653 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 26 Feb 2022 15:29:16 -0800 Subject: [PATCH 553/719] Handle argument annotations. --- yapf/pyparser/split_penalty_visitor.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/yapf/pyparser/split_penalty_visitor.py b/yapf/pyparser/split_penalty_visitor.py index aae55b22c..679fa159d 100644 --- a/yapf/pyparser/split_penalty_visitor.py +++ b/yapf/pyparser/split_penalty_visitor.py @@ -858,7 +858,12 @@ def visit_arg(self, node): # annotation=Expr, # type_comment='') tokens = self._GetTokens(node) - _IncreasePenalty(tokens[1:], split_penalty.ARGUMENT) + + # Process any annotations. + if hasattr(node, 'annotation') and node.annotation: + annotation = node.annotation + subrange = pyutils.GetTokensInSubRange(tokens, annotation) + _IncreasePenalty(subrange, split_penalty.ANNOTATION) return self.generic_visit(node) From d55e289992d7baf1b03d3f656ec25922d116548a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 26 Feb 2022 16:30:26 -0800 Subject: [PATCH 554/719] Decorators aren't in the same range as the function def node --- yapf/pyparser/split_penalty_visitor.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yapf/pyparser/split_penalty_visitor.py b/yapf/pyparser/split_penalty_visitor.py index 679fa159d..2d9c992b5 100644 --- a/yapf/pyparser/split_penalty_visitor.py +++ b/yapf/pyparser/split_penalty_visitor.py @@ -57,9 +57,9 @@ def visit_FunctionDef(self, node): for decorator in node.decorator_list: # The decorator token list begins after the '@'. The body of the decorator # is formatted like a normal "call." - subrange = pyutils.GetTokensInSubRange(tokens, decorator) + decorator_range = self._GetTokens(decorator) # Don't split after the '@'. - subrange[0].split_penalty = split_penalty.UNBREAKABLE + decorator_range[0].split_penalty = split_penalty.UNBREAKABLE if node.returns: start_index = pyutils.GetTokenIndex(tokens, @@ -101,8 +101,8 @@ def visit_ClassDef(self, node): for decorator in node.decorator_list: # Don't split after the '@'. - tokens = self._GetTokens(decorator) - tokens[0].split_penalty = split_penalty.UNBREAKABLE + decorator_range = self._GetTokens(decorator) + decorator_range[0].split_penalty = split_penalty.UNBREAKABLE return self.generic_visit(node) From 1adc1ceff4aa9c6bdce53ea561dd9ce0ddf64853 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 26 Feb 2022 16:31:20 -0800 Subject: [PATCH 555/719] Pass in the node's name This helps encapsulation. --- yapf/pytree/pytree_unwrapper.py | 3 ++- yapf/yapflib/format_token.py | 24 ++++++++++++------------ yapf/yapflib/reformatter.py | 3 ++- yapftests/format_token_test.py | 12 ++++++++---- yapftests/logical_line_test.py | 25 ++++++++++++++----------- 5 files changed, 38 insertions(+), 29 deletions(-) diff --git a/yapf/pytree/pytree_unwrapper.py b/yapf/pytree/pytree_unwrapper.py index 39dceac5f..3fe4ade08 100644 --- a/yapf/pytree/pytree_unwrapper.py +++ b/yapf/pytree/pytree_unwrapper.py @@ -297,7 +297,8 @@ def DefaultLeafVisit(self, leaf): self._StartNewLine() elif leaf.type != grammar_token.COMMENT or leaf.value.strip(): # Add non-whitespace tokens and comments that aren't empty. - self._cur_logical_line.AppendToken(format_token.FormatToken(leaf)) + self._cur_logical_line.AppendToken( + format_token.FormatToken(leaf, pytree_utils.NodeName(leaf))) _BRACKET_MATCH = {')': '(', '}': '{', ']': '['} diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 58c30f1ad..89e61d98e 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -83,14 +83,23 @@ class FormatToken(object): newlines: The number of newlines needed before this token. """ - def __init__(self, node, node_name=None): + def __init__(self, node, name): """Constructor. Arguments: node: (pytree.Leaf) The node that's being wrapped. - none_name: (string) The name of the node. + name: (string) The name of the node. """ self.node = node + self.name = name + self.type = node.type + self.column = node.column + self.lineno = node.lineno + self.value = node.value + + if self.is_continuation: + self.value = node.value.rstrip() + self.next_token = None self.previous_token = None self.matching_bracket = None @@ -105,20 +114,11 @@ def __init__(self, node, node_name=None): node, pytree_utils.Annotation.MUST_SPLIT, default=False) self.newlines = pytree_utils.GetNodeAnnotation( node, pytree_utils.Annotation.NEWLINES) - - self.type = node.type - self.column = node.column - self.lineno = node.lineno - self.name = pytree_utils.NodeName(node) if not node_name else node_name - self.spaces_required_before = 0 + if self.is_comment: self.spaces_required_before = style.Get('SPACES_BEFORE_COMMENT') - self.value = node.value - if self.is_continuation: - self.value = node.value.rstrip() - stypes = pytree_utils.GetNodeAnnotation(node, pytree_utils.Annotation.SUBTYPE) self.subtypes = {subtypes.NONE} if not stypes else stypes diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 8730b9623..b2dfbd484 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -738,7 +738,8 @@ def _SingleOrMergedLines(lines): if line.last.value != ':': leaf = pytree.Leaf( type=token.SEMI, value=';', context=('', (line.lineno, column))) - line.AppendToken(format_token.FormatToken(leaf)) + line.AppendToken( + format_token.FormatToken(leaf, pytree_utils.NodeName(leaf))) for tok in lines[index].tokens: line.AppendToken(tok) index += 1 diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index e324983d5..6ea24af63 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -66,23 +66,27 @@ def testVAlignRight(self): class FormatTokenTest(unittest.TestCase): def testSimple(self): - tok = format_token.FormatToken(pytree.Leaf(token.STRING, "'hello world'")) + tok = format_token.FormatToken( + pytree.Leaf(token.STRING, "'hello world'"), 'STRING') self.assertEqual( "FormatToken(name=DOCSTRING, value='hello world', column=0, " "lineno=0, splitpenalty=0)", str(tok)) self.assertTrue(tok.is_string) - tok = format_token.FormatToken(pytree.Leaf(token.COMMENT, '# A comment')) + tok = format_token.FormatToken( + pytree.Leaf(token.COMMENT, '# A comment'), 'COMMENT') self.assertEqual( 'FormatToken(name=COMMENT, value=# A comment, column=0, ' 'lineno=0, splitpenalty=0)', str(tok)) self.assertTrue(tok.is_comment) def testIsMultilineString(self): - tok = format_token.FormatToken(pytree.Leaf(token.STRING, '"""hello"""')) + tok = format_token.FormatToken( + pytree.Leaf(token.STRING, '"""hello"""'), 'STRING') self.assertTrue(tok.is_multiline_string) - tok = format_token.FormatToken(pytree.Leaf(token.STRING, 'r"""hello"""')) + tok = format_token.FormatToken( + pytree.Leaf(token.STRING, 'r"""hello"""'), 'STRING') self.assertTrue(tok.is_multiline_string) diff --git a/yapftests/logical_line_test.py b/yapftests/logical_line_test.py index ca921d225..d18262a7c 100644 --- a/yapftests/logical_line_test.py +++ b/yapftests/logical_line_test.py @@ -29,29 +29,32 @@ class LogicalLineBasicTest(unittest.TestCase): def testConstruction(self): - toks = _MakeFormatTokenList([(token.DOT, '.'), (token.VBAR, '|')]) + toks = _MakeFormatTokenList([(token.DOT, '.', 'DOT'), + (token.VBAR, '|', 'VBAR')]) lline = logical_line.LogicalLine(20, toks) self.assertEqual(20, lline.depth) self.assertEqual(['DOT', 'VBAR'], [tok.name for tok in lline.tokens]) def testFirstLast(self): - toks = _MakeFormatTokenList([(token.DOT, '.'), (token.LPAR, '('), - (token.VBAR, '|')]) + toks = _MakeFormatTokenList([(token.DOT, '.', 'DOT'), + (token.LPAR, '(', 'LPAR'), + (token.VBAR, '|', 'VBAR')]) lline = logical_line.LogicalLine(20, toks) self.assertEqual(20, lline.depth) self.assertEqual('DOT', lline.first.name) self.assertEqual('VBAR', lline.last.name) def testAsCode(self): - toks = _MakeFormatTokenList([(token.DOT, '.'), (token.LPAR, '('), - (token.VBAR, '|')]) + toks = _MakeFormatTokenList([(token.DOT, '.', 'DOT'), + (token.LPAR, '(', 'LPAR'), + (token.VBAR, '|', 'VBAR')]) lline = logical_line.LogicalLine(2, toks) self.assertEqual(' . ( |', lline.AsCode()) def testAppendToken(self): lline = logical_line.LogicalLine(0) - lline.AppendToken(_MakeFormatTokenLeaf(token.LPAR, '(')) - lline.AppendToken(_MakeFormatTokenLeaf(token.RPAR, ')')) + lline.AppendToken(_MakeFormatTokenLeaf(token.LPAR, '(', 'LPAR')) + lline.AppendToken(_MakeFormatTokenLeaf(token.RPAR, ')', 'RPAR')) self.assertEqual(['LPAR', 'RPAR'], [tok.name for tok in lline.tokens]) @@ -75,14 +78,14 @@ def f(a, b): self.assertEqual(lparen.split_penalty, split_penalty.UNBREAKABLE) -def _MakeFormatTokenLeaf(token_type, token_value): - return format_token.FormatToken(pytree.Leaf(token_type, token_value)) +def _MakeFormatTokenLeaf(token_type, token_value, name): + return format_token.FormatToken(pytree.Leaf(token_type, token_value), name) def _MakeFormatTokenList(token_type_values): return [ - _MakeFormatTokenLeaf(token_type, token_value) - for token_type, token_value in token_type_values + _MakeFormatTokenLeaf(token_type, token_value, token_name) + for token_type, token_value, token_name in token_type_values ] From 33e7699c655bb6dc8b09a31640773810fbe7f08b Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 26 Feb 2022 16:45:56 -0800 Subject: [PATCH 556/719] Don't use pytree 'node' to access values --- yapf/yapflib/format_token.py | 2 +- yapf/yapflib/reformatter.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 89e61d98e..6eea05473 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -196,7 +196,7 @@ def RetainHorizontalSpacing(self, first_column, depth): return cur_column = self.column - prev_column = previous.node.column + prev_column = previous.column prev_len = len(previous.value) if previous.is_pseudo and previous.value == ')': diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index b2dfbd484..3bea3c7b6 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -61,9 +61,9 @@ def Reformat(llines, verify=False, lines=None): if not lline.disable: if lline.first.is_comment: - lline.first.node.value = lline.first.node.value.rstrip() + lline.first.value = lline.first.value.rstrip() elif lline.last.is_comment: - lline.last.node.value = lline.last.node.value.rstrip() + lline.last.value = lline.last.value.rstrip() if prev_line and prev_line.disable: # Keep the vertical spacing between a disabled and enabled formatting # region. From 957b61c4a01af85f9519f5cf5dac922fb17c4aa2 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 26 Feb 2022 17:13:47 -0800 Subject: [PATCH 557/719] Remove bad comment markers --- yapf/pyparser/pyparser_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/pyparser/pyparser_utils.py b/yapf/pyparser/pyparser_utils.py index 72d8f0805..3f17b15a4 100644 --- a/yapf/pyparser/pyparser_utils.py +++ b/yapf/pyparser/pyparser_utils.py @@ -94,7 +94,7 @@ def TokenEnd(node): ############################################################################# -### Code for debugging ### +# Code for debugging # ############################################################################# From c733e76bcbeb7fa853bdda2a1171b292baccf669 Mon Sep 17 00:00:00 2001 From: Andrii Oriekhov Date: Tue, 1 Mar 2022 23:23:30 +0200 Subject: [PATCH 558/719] add GitHub URL for PyPi (#997) --- setup.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.py b/setup.py index 86e938471..73e69f33a 100644 --- a/setup.py +++ b/setup.py @@ -50,6 +50,9 @@ def run(self): maintainer='Bill Wendling', maintainer_email='morbo@google.com', packages=find_packages('.'), + project_urls={ + 'Source': 'https://github.com/google/yapf', + }, classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Console', From 0953195425e86be46e308e1989076304fce4c894 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 1 Mar 2022 14:25:43 -0800 Subject: [PATCH 559/719] Fix multiple # in comment warning. --- yapf/pyparser/pyparser.py | 3 ++- yapf/pyparser/split_penalty_visitor.py | 8 +++++--- yapf/yapflib/split_penalty.py | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/yapf/pyparser/pyparser.py b/yapf/pyparser/pyparser.py index 61cf45ed7..a8a28ebc8 100644 --- a/yapf/pyparser/pyparser.py +++ b/yapf/pyparser/pyparser.py @@ -66,6 +66,7 @@ def ParseCode(unformatted_source, filename=''): try: ast_tree = ast.parse(unformatted_source, filename) + ast.fix_missing_locations(ast_tree) readline = py3compat.StringIO(unformatted_source).readline tokens = tokenize.generate_tokens(readline) except Exception: @@ -74,8 +75,8 @@ def ParseCode(unformatted_source, filename=''): logical_lines = _CreateLogicalLines(tokens) # Process the logical lines. - ast.fix_missing_locations(ast_tree) split_penalty_visitor.SplitPenalty(logical_lines).visit(ast_tree) + return logical_lines diff --git a/yapf/pyparser/split_penalty_visitor.py b/yapf/pyparser/split_penalty_visitor.py index 2d9c992b5..047b48a3d 100644 --- a/yapf/pyparser/split_penalty_visitor.py +++ b/yapf/pyparser/split_penalty_visitor.py @@ -61,6 +61,11 @@ def visit_FunctionDef(self, node): # Don't split after the '@'. decorator_range[0].split_penalty = split_penalty.UNBREAKABLE + for token in tokens[1:]: + if token.value == '(': + break + _SetPenalty(token, split_penalty.UNBREAKABLE) + if node.returns: start_index = pyutils.GetTokenIndex(tokens, pyutils.TokenStart(node.returns)) @@ -84,9 +89,6 @@ def visit_AsyncFunctionDef(self, node): # body=[...], # decorator_list=[Expr_1, Expr_2, ..., Expr_n], # keywords=[]) - tokens = self._GetTokens(node) - _IncreasePenalty(tokens[1], split_penalty.UNBREAKABLE) - return self.visit_FunctionDef(node) def visit_ClassDef(self, node): diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index f3f136385..79b68edcd 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -20,7 +20,7 @@ STRONGLY_CONNECTED = 2500 ############################################################################# -### Grammar-specific penalties - should be <= 1000 ### +# Grammar-specific penalties - should be <= 1000 # ############################################################################# # Lambdas shouldn't be split unless absolutely necessary or if From 84df63cfffd7c0654b2b7a184a6c9f4e8ed691f9 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 1 Mar 2022 15:11:32 -0800 Subject: [PATCH 560/719] Add missing commit --- yapf/yapflib/reformatter.py | 1 + 1 file changed, 1 insertion(+) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 3bea3c7b6..14e0bde70 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -28,6 +28,7 @@ from lib2to3 import pytree from lib2to3.pgen2 import token +from yapf.pytree import pytree_utils from yapf.yapflib import format_decision_state from yapf.yapflib import format_token from yapf.yapflib import line_joiner From b8ef9207b269224aafb390bab305fb945f280948 Mon Sep 17 00:00:00 2001 From: Tim Gates Date: Fri, 15 Jul 2022 08:17:59 +1000 Subject: [PATCH 561/719] docs: Fix a few typos There are small typos in: - yapf/yapflib/format_decision_state.py - yapf/yapflib/logical_line.py - yapftests/file_resources_test.py Fixes: - Should read `overzealous` rather than `overzelous`. - Should read `indent` rather than `indend`. - Should read `formatting` rather than `formattings`. --- yapf/yapflib/format_decision_state.py | 2 +- yapf/yapflib/logical_line.py | 2 +- yapftests/file_resources_test.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index c299d1c85..a64cbbf83 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -14,7 +14,7 @@ """Implements a format decision state object that manages whitespace decisions. Each token is processed one at a time, at which point its whitespace formatting -decisions are made. A graph of potential whitespace formattings is created, +decisions are made. A graph of potential whitespace formatting is created, where each node in the graph is a format decision state object. The heuristic tries formatting the token with and without a newline before it to determine which one has the least penalty. Therefore, the format decision state object for diff --git a/yapf/yapflib/logical_line.py b/yapf/yapflib/logical_line.py index 8c84b7ba8..7f03509fb 100644 --- a/yapf/yapflib/logical_line.py +++ b/yapf/yapflib/logical_line.py @@ -159,7 +159,7 @@ def AsCode(self, indent_per_depth=2): have spaces around them, for example). Arguments: - indent_per_depth: how much spaces to indend per depth level. + indent_per_depth: how much spaces to indent per depth level. Returns: A string representing the line as code. diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 31184c4a3..62e8deed7 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -350,7 +350,7 @@ def test_find_with_excluded_hidden_dirs_relative(self): child of the current directory which has been specified in a relative manner. - At its core, the bug has to do with overzelous stripping of "./foo" so that + At its core, the bug has to do with overzealous stripping of "./foo" so that it removes too much from "./.foo" . """ tdir1 = self._make_test_dir('.test1') From c3975df200e141a6ab65c840f06b1a0ff27f5b81 Mon Sep 17 00:00:00 2001 From: Xiao Wang Date: Thu, 18 Aug 2022 10:40:01 +0200 Subject: [PATCH 562/719] features to align assignment operators and dictionary colons --- yapf/pytree/comment_splicer.py | 1 - yapf/pytree/subtype_assigner.py | 16 +- yapf/yapflib/format_decision_state.py | 1 + yapf/yapflib/format_token.py | 89 +++++ yapf/yapflib/reformatter.py | 508 ++++++++++++++++++++++++++ yapf/yapflib/style.py | 24 ++ yapf/yapflib/subtypes.py | 1 + yapftests/format_token_test.py | 34 +- yapftests/reformatter_basic_test.py | 368 ++++++++++++++++++- yapftests/subtype_assigner_test.py | 109 +++++- yapftests/yapf_test.py | 2 +- 11 files changed, 1138 insertions(+), 15 deletions(-) diff --git a/yapf/pytree/comment_splicer.py b/yapf/pytree/comment_splicer.py index ae5ffe66f..9e8f02c48 100644 --- a/yapf/pytree/comment_splicer.py +++ b/yapf/pytree/comment_splicer.py @@ -42,7 +42,6 @@ def SpliceComments(tree): # This is a list because Python 2.x doesn't have 'nonlocal' :) prev_leaf = [None] _AnnotateIndents(tree) - def _VisitNodeRec(node): """Recursively visit each node to splice comments into the AST.""" # This loop may insert into node.children, so we'll iterate over a copy. diff --git a/yapf/pytree/subtype_assigner.py b/yapf/pytree/subtype_assigner.py index dd3ea3d1e..03d7efe1a 100644 --- a/yapf/pytree/subtype_assigner.py +++ b/yapf/pytree/subtype_assigner.py @@ -240,6 +240,7 @@ def Visit_argument(self, node): # pylint: disable=invalid-name # argument ::= # test [comp_for] | test '=' test self._ProcessArgLists(node) + #TODO add a subtype to each argument? def Visit_arglist(self, node): # pylint: disable=invalid-name # arglist ::= @@ -300,6 +301,7 @@ def Visit_typedargslist(self, node): # pylint: disable=invalid-name for i in range(1, len(node.children)): prev_child = node.children[i - 1] child = node.children[i] + if prev_child.type == grammar_token.COMMA: _AppendFirstLeafTokenSubtype(child, subtypes.PARAMETER_START) elif child.type == grammar_token.COMMA: @@ -309,6 +311,10 @@ def Visit_typedargslist(self, node): # pylint: disable=invalid-name tname = True _SetArgListSubtype(child, subtypes.TYPED_NAME, subtypes.TYPED_NAME_ARG_LIST) + # NOTE Every element of the tynamme argument list + # should have this list type + _AppendSubtypeRec(child, subtypes.TYPED_NAME_ARG_LIST) + elif child.type == grammar_token.COMMA: tname = False elif child.type == grammar_token.EQUAL and tname: @@ -383,21 +389,25 @@ def HasSubtype(node): for child in node.children: node_name = pytree_utils.NodeName(child) + #TODO exclude it if the first leaf is a comment in appendfirstleaftokensubtype if node_name not in {'atom', 'COMMA'}: _AppendFirstLeafTokenSubtype(child, list_subtype) + def _AppendTokenSubtype(node, subtype): """Append the token's subtype only if it's not already set.""" pytree_utils.AppendNodeAnnotation(node, pytree_utils.Annotation.SUBTYPE, subtype) - +#TODO should exclude comment child to all Appendsubtypes functions def _AppendFirstLeafTokenSubtype(node, subtype): """Append the first leaf token's subtypes.""" + #TODO exclude the comment leaf if isinstance(node, pytree.Leaf): - _AppendTokenSubtype(node, subtype) - return + _AppendTokenSubtype(node, subtype) + return + _AppendFirstLeafTokenSubtype(node.children[0], subtype) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index c299d1c85..efcef0ba4 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -978,6 +978,7 @@ def _GetNewlineColumn(self): not self.param_list_stack[-1].SplitBeforeClosingBracket( top_of_stack.indent) and top_of_stack.indent == ((self.line.depth + 1) * style.Get('INDENT_WIDTH'))): + # NOTE: comment inside argument list is not excluded in subtype assigner if (subtypes.PARAMETER_START in current.subtypes or (previous.is_comment and subtypes.PARAMETER_START in previous.subtypes)): diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 6eea05473..f8658f772 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -14,6 +14,7 @@ """Enhanced token information for formatting.""" import keyword +from operator import sub import re from lib2to3.pgen2 import token @@ -124,6 +125,7 @@ def __init__(self, node, name): self.subtypes = {subtypes.NONE} if not stypes else stypes self.is_pseudo = hasattr(node, 'is_pseudo') and node.is_pseudo + @property def formatted_whitespace_prefix(self): if style.Get('INDENT_BLANK_LINES'): @@ -322,3 +324,90 @@ def is_pytype_comment(self): def is_copybara_comment(self): return self.is_comment and re.match( r'#.*\bcopybara:\s*(strip|insert|replace)', self.value) + + + @property + def is_assign(self): + return subtypes.ASSIGN_OPERATOR in self.subtypes + + @property + def is_dict_colon(self): + # if the token is dictionary colon and + # the dictionary has no comp_for + return self.value == ':' and self.previous_token.is_dict_key + + @property + def is_dict_key(self): + # if the token is dictionary key which is not preceded by doubel stars and + # the dictionary has no comp_for + return subtypes.DICTIONARY_KEY_PART in self.subtypes + + @property + def is_dict_key_start(self): + # if the token is dictionary key start + return subtypes.DICTIONARY_KEY in self.subtypes + + @property + def is_dict_value(self): + return subtypes.DICTIONARY_VALUE in self.subtypes + + @property + def is_augassign(self): + augassigns = {'+=', '-=' , '*=' , '@=' , '/=' , '%=' , '&=' , '|=' , '^=' , + '<<=' , '>>=' , '**=' , '//='} + return self.value in augassigns + + @property + def is_argassign(self): + return (subtypes.DEFAULT_OR_NAMED_ASSIGN in self.subtypes + or subtypes.VARARGS_LIST in self.subtypes) + + @property + def is_argname(self): + # it's the argument part before argument assignment operator, + # including tnames and data type + # not the assign operator, + # not the value after the assign operator + + # argument without assignment is also included + # the token is arg part before '=' but not after '=' + if self.is_argname_start: + return True + + # exclude comment inside argument list + if not self.is_comment: + # the token is any element in typed arglist + if subtypes.TYPED_NAME_ARG_LIST in self.subtypes: + return True + + return False + + + @property + def is_argname_start(self): + # return true if it's the start of every argument entry + if self.previous_token: + previous_subtypes = self.previous_token.subtypes + + return ( + (not self.is_comment + and subtypes.DEFAULT_OR_NAMED_ASSIGN not in self.subtypes + and subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in self.subtypes + and subtypes.DEFAULT_OR_NAMED_ASSIGN not in previous_subtypes + and (not subtypes.PARAMETER_STOP in self.subtypes + or subtypes.PARAMETER_START in self.subtypes) + ) + or # if there is comment, the arg after it is the argname start + (not self.is_comment and self.previous_token and self.previous_token.is_comment + and + (subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in previous_subtypes + or subtypes.TYPED_NAME_ARG_LIST in self.subtypes + or subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in self.subtypes)) + ) + + + + + + + diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 14e0bde70..92aaa950e 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -22,6 +22,7 @@ from __future__ import unicode_literals import collections +from distutils.errors import LinkError import heapq import re @@ -102,6 +103,15 @@ def Reformat(llines, verify=False, lines=None): final_lines.append(lline) prev_line = lline + + if style.Get('ALIGN_ASSIGNMENT'): + _AlignAssignment(final_lines) + if (style.Get('EACH_DICT_ENTRY_ON_SEPARATE_LINE') + and style.Get('ALIGN_DICT_COLON')): + _AlignDictColon(final_lines) + if style.Get('ALIGN_ARGUMENT_ASSIGNMENT'): + _AlignArgAssign(final_lines) + _AlignTrailingComments(final_lines) return _FormatFinalLines(final_lines, verify) @@ -394,6 +404,504 @@ def _AlignTrailingComments(final_lines): final_lines_index += 1 +def _AlignAssignment(final_lines): + """Align assignment operators and augmented assignment operators to the same column""" + + final_lines_index = 0 + while final_lines_index < len(final_lines): + line = final_lines[final_lines_index] + + assert line.tokens + process_content = False + + for tok in line.tokens: + if tok.is_assign or tok.is_augassign: + # all pre assignment variable lengths in one block of lines + all_pa_variables_lengths = [] + max_variables_length = 0 + + while True: + # EOF + if final_lines_index + len(all_pa_variables_lengths) == len(final_lines): + break + + this_line_index = final_lines_index + len(all_pa_variables_lengths) + this_line = final_lines[this_line_index] + + next_line = None + if this_line_index < len(final_lines) - 1: + next_line = final_lines[final_lines_index + len(all_pa_variables_lengths) + 1 ] + + assert this_line.tokens, next_line.tokens + + # align them differently when there is a blank line in between + if (all_pa_variables_lengths and + this_line.tokens[0].formatted_whitespace_prefix.startswith('\n\n') + ): + break + + # if there is a standalone comment or keyword statement line + # or other lines without assignment in between, break + elif (all_pa_variables_lengths and + True not in [tok.is_assign or tok.is_augassign for tok in this_line.tokens]): + if this_line.tokens[0].is_comment: + if style.Get('NEW_ALIGNMENT_AFTER_COMMENTLINE'): + break + else: break + + if this_line.disable: + all_pa_variables_lengths.append([]) + continue + + variables_content = '' + pa_variables_lengths = [] + contain_object = False + line_tokens = this_line.tokens + # only one assignment expression is on each line + for index in range(len(line_tokens)): + line_tok = line_tokens[index] + + prefix = line_tok.formatted_whitespace_prefix + newline_index = prefix.rfind('\n') + if newline_index != -1: + variables_content = '' + prefix = prefix[newline_index + 1:] + + if line_tok.is_assign or line_tok.is_augassign: + next_toks = [line_tokens[i] for i in range(index+1, len(line_tokens))] + # if there is object(list/tuple/dict) with newline entries, break, + # update the alignment so far and start to calulate new alignment + for tok in next_toks: + if tok.value in ['(', '[', '{'] and tok.next_token: + if (tok.next_token.formatted_whitespace_prefix.startswith('\n') + or (tok.next_token.is_comment and tok.next_token.next_token.formatted_whitespace_prefix.startswith('\n'))): + pa_variables_lengths.append(len(variables_content)) + contain_object = True + break + if not contain_object: + if line_tok.is_assign: + pa_variables_lengths.append(len(variables_content)) + # if augassign, add the extra augmented part to the max length caculation + elif line_tok.is_augassign: + pa_variables_lengths.append(len(variables_content) + len(line_tok.value) - 1 ) + # don't add the tokens + # after the assignment operator + break + else: + variables_content += '{}{}'.format(prefix, line_tok.value) + + if pa_variables_lengths: + max_variables_length = max(max_variables_length, max(pa_variables_lengths)) + + all_pa_variables_lengths.append(pa_variables_lengths) + + # after saving this line's max variable length, + # we check if next line has the same depth as this line, + # if not, we don't want to calculate their max variable length together + # so we break the while loop, update alignment so far, and + # then go to next line that has '=' + if next_line: + if this_line.depth != next_line.depth: + break + # if this line contains objects with newline entries, + # start new block alignment + if contain_object: + break + + # if no update of max_length, just go to the next block + if max_variables_length == 0: continue + + max_variables_length += 2 + + # Update the assignment token values based on the max variable length + for all_pa_variables_lengths_index, pa_variables_lengths in enumerate( + all_pa_variables_lengths): + if not pa_variables_lengths: + continue + this_line = final_lines[final_lines_index + all_pa_variables_lengths_index] + + # only the first assignment operator on each line + pa_variables_lengths_index = 0 + for line_tok in this_line.tokens: + if line_tok.is_assign or line_tok.is_augassign: + assert pa_variables_lengths[0] < max_variables_length + + if pa_variables_lengths_index < len(pa_variables_lengths): + whitespace = ' ' * ( + max_variables_length - pa_variables_lengths[0] - 1) + + assign_content = '{}{}'.format(whitespace, line_tok.value.strip()) + + existing_whitespace_prefix = \ + line_tok.formatted_whitespace_prefix.lstrip('\n') + + # in case the existing spaces are larger than padded spaces + if (len(whitespace) == 1 or len(whitespace) > 1 and + len(existing_whitespace_prefix)>len(whitespace)): + line_tok.whitespace_prefix = '' + elif assign_content.startswith(existing_whitespace_prefix): + assign_content = assign_content[len(existing_whitespace_prefix):] + + # update the assignment operator value + line_tok.value = assign_content + + pa_variables_lengths_index += 1 + + final_lines_index += len(all_pa_variables_lengths) + + process_content = True + break + + if not process_content: + final_lines_index += 1 + + +def _AlignArgAssign(final_lines): + """Align the assign operators in a argument list to the same column""" + """NOTE One argument list of one function is on one logical line! + But funtion calls/argument lists can be in argument list. + """ + final_lines_index = 0 + while final_lines_index < len(final_lines): + line = final_lines[final_lines_index] + if line.disable: + final_lines_index += 1 + continue + + assert line.tokens + process_content = False + + for tok in line.tokens: + if tok.is_argassign: + + this_line = line + line_tokens = this_line.tokens + + for open_index in range(len(line_tokens)): + line_tok = line_tokens[open_index] + + if (line_tok.value == '(' and not line_tok.is_pseudo + and line_tok.next_token.formatted_whitespace_prefix.startswith('\n')): + index = open_index + # skip the comments in the beginning + index += 1 + line_tok = line_tokens[index] + while not line_tok.is_argname_start and index < len(line_tokens)-1: + index += 1 + line_tok = line_tokens[index] + + # check if the argstart is on newline + if line_tok.is_argname_start and line_tok.formatted_whitespace_prefix.startswith('\n'): + first_arg_index = index + first_arg_column = len(line_tok.formatted_whitespace_prefix.lstrip('\n')) + + closing = False + all_arg_name_lengths = [] + arg_name_lengths = [] + name_content = '' + arg_column = first_arg_column + + # start with the first argument + # that has nextline prefix + while not closing: + # if there is a comment in between, save, reset and continue to calulate new alignment + if (style.Get('NEW_ALIGNMENT_AFTER_COMMENTLINE') + and arg_name_lengths and line_tok.is_comment + and line_tok.formatted_whitespace_prefix.startswith('\n')): + all_arg_name_lengths.append(arg_name_lengths) + arg_name_lengths = [] + index += 1 + line_tok = line_tokens[index] + continue + + prefix = line_tok.formatted_whitespace_prefix + newline_index = prefix.rfind('\n') + + if newline_index != -1: + if line_tok.is_argname_start: + name_content = '' + prefix = prefix[newline_index + 1:] + arg_column = len(prefix) + # if a typed arg name is so long + # that there are newlines inside + # only calulate the last line arg_name that has the assignment + elif line_tok.is_argname: + name_content = '' + prefix = prefix[newline_index + 1:] + # if any argument not on newline + elif line_tok.is_argname_start: + name_content = '' + arg_column = line_tok.column + # in case they are formatted into one line in final_line + # but are put in separated lines in original codes + if arg_column == first_arg_column: + arg_column = line_tok.formatted_whitespace_prefix + # on the same argument level + if (line_tok.is_argname_start and arg_name_lengths + and arg_column==first_arg_column): + argname_end = line_tok + while argname_end.is_argname: + argname_end = argname_end.next_token + # argument without assignment in between + if not argname_end.is_argassign: + all_arg_name_lengths.append(arg_name_lengths) + arg_name_lengths = [] + index += 1 + line_tok = line_tokens[index] + continue + + if line_tok.is_argassign and arg_column == first_arg_column: + arg_name_lengths.append(len(name_content)) + elif line_tok.is_argname and arg_column == first_arg_column: + name_content += '{}{}'.format(prefix, line_tok.value) + # add up all token values before the arg assign operator + + index += 1 + if index < len(line_tokens): + line_tok = line_tokens[index] + # when the matching closing bracket never found + # due to edge cases where the closing bracket + # is not indented or dedented + else: + all_arg_name_lengths.append(arg_name_lengths) + break + + # if there is a new object(list/tuple/dict) with its entries on newlines, + # save, reset and continue to calulate new alignment + if (line_tok.value in ['(', '[','{'] and line_tok.next_token + and line_tok.next_token.formatted_whitespace_prefix.startswith('\n')): + if arg_name_lengths: + all_arg_name_lengths.append(arg_name_lengths) + arg_name_lengths = [] + index += 1 + line_tok = line_tokens[index] + continue + + if line_tok.value == ')'and not line_tok.is_pseudo: + if line_tok.formatted_whitespace_prefix.startswith('\n'): + close_column = len(line_tok.formatted_whitespace_prefix.lstrip('\n')) + else: close_column = line_tok.column + if close_column < first_arg_column: + if arg_name_lengths: + all_arg_name_lengths.append(arg_name_lengths) + closing = True + + # update the alignment once one full arg list is processed + if all_arg_name_lengths: + # if argument list with only the first argument on newline + if len(all_arg_name_lengths) == 1 and len(all_arg_name_lengths[0]) == 1: + continue + max_name_length = 0 + all_arg_name_lengths_index = 0 + arg_name_lengths = all_arg_name_lengths[all_arg_name_lengths_index] + max_name_length = max(arg_name_lengths or [0]) + 2 + arg_lengths_index = 0 + for token in line_tokens[first_arg_index:index]: + if token.is_argassign: + name_token = token.previous_token + while name_token.is_argname and not name_token.is_argname_start: + name_token = name_token.previous_token + name_column = len(name_token.formatted_whitespace_prefix.lstrip('\n')) + if name_column == first_arg_column: + if all_arg_name_lengths_index < len(all_arg_name_lengths): + if arg_lengths_index == len(arg_name_lengths): + all_arg_name_lengths_index += 1 + arg_name_lengths = all_arg_name_lengths[all_arg_name_lengths_index] + max_name_length = max(arg_name_lengths or [0]) + 2 + arg_lengths_index = 0 + + if arg_lengths_index < len(arg_name_lengths): + + assert arg_name_lengths[arg_lengths_index] < max_name_length + + padded_spaces = ' ' * ( + max_name_length - arg_name_lengths[arg_lengths_index] - 1) + arg_lengths_index += 1 + + assign_content = '{}{}'.format(padded_spaces, token.value.strip()) + existing_whitespace_prefix = \ + token.formatted_whitespace_prefix.lstrip('\n') + + # in case the existing spaces are larger than padded spaces + if (len(padded_spaces)==1 or len(padded_spaces)>1 and + len(existing_whitespace_prefix)>len(padded_spaces)): + token.whitespace_prefix = '' + elif assign_content.startswith(existing_whitespace_prefix): + assign_content = assign_content[len(existing_whitespace_prefix):] + + token.value = assign_content + + final_lines_index += 1 + process_content = True + break + + if not process_content: + final_lines_index += 1 + + +def _AlignDictColon(final_lines): + """Align colons in a dict to the same column""" + """NOTE One (nested) dict/list is one logical line!""" + final_lines_index = 0 + while final_lines_index < len(final_lines): + line = final_lines[final_lines_index] + if line.disable: + final_lines_index += 1 + continue + + assert line.tokens + process_content = False + + for tok in line.tokens: + # make sure each dict entry on separate lines and + # the dict has more than one entry + if (tok.is_dict_key and tok.formatted_whitespace_prefix.startswith('\n') and + not tok.is_comment): + + this_line = line + + line_tokens = this_line.tokens + for open_index in range(len(line_tokens)): + line_tok = line_tokens[open_index] + + # check each time if the detected dict is the dict we aim for + if line_tok.value == '{' and line_tok.next_token.formatted_whitespace_prefix.startswith('\n'): + index = open_index + # skip the comments in the beginning + index += 1 + line_tok = line_tokens[index] + while not line_tok.is_dict_key and index < len(line_tokens)-1: + index += 1 + line_tok = line_tokens[index] + # in case empty dict, check if dict key again + if line_tok.is_dict_key and line_tok.formatted_whitespace_prefix.startswith('\n'): + closing = False # the closing bracket in dict '}'. + keys_content = '' + all_dict_keys_lengths = [] + dict_keys_lengths = [] + + # record the column number of the first key + first_key_column = len(line_tok.formatted_whitespace_prefix.lstrip('\n')) + key_column = first_key_column + + # while not closing: + while not closing: + prefix = line_tok.formatted_whitespace_prefix + newline = prefix.startswith('\n') + if newline: + # if comments inbetween, save, reset and continue to caluclate new alignment + if (style.Get('NEW_ALIGNMENT_AFTER_COMMENTLINE') + and dict_keys_lengths and line_tok.is_comment): + all_dict_keys_lengths.append(dict_keys_lengths) + dict_keys_lengths =[] + index += 1 + line_tok = line_tokens[index] + continue + if line_tok.is_dict_key_start: + keys_content = '' + prefix = prefix.lstrip('\n') + key_column = len(prefix) + # if the dict key is so long that it has multi-lines + # only caculate the last line that has the colon + elif line_tok.is_dict_key: + keys_content = '' + prefix = prefix.lstrip('\n') + elif line_tok.is_dict_key_start: + key_column = line_tok.column + + if line_tok.is_dict_colon and key_column == first_key_column: + dict_keys_lengths.append(len(keys_content)) + elif line_tok.is_dict_key and key_column == first_key_column: + keys_content += '{}{}'.format(prefix, line_tok.value) + + index += 1 + if index < len(line_tokens): + line_tok = line_tokens[index] + # when the matching closing bracket never found + # due to edge cases where the closing bracket + # is not indented or dedented, e.g. ']}', with another bracket before + else: + all_dict_keys_lengths.append(dict_keys_lengths) + break + + # if there is new objects(list/tuple/dict) with its entries on newlines, + # or a function call with any of its arguments on newlines, + # save, reset and continue to calulate new alignment + if (line_tok.value in ['(', '[', '{'] and not line_tok.is_pseudo and line_tok.next_token + and line_tok.next_token.formatted_whitespace_prefix.startswith('\n')): + if dict_keys_lengths: + all_dict_keys_lengths.append(dict_keys_lengths) + dict_keys_lengths = [] + index += 1 + line_tok = line_tokens[index] + continue + # the matching closing bracket is either same indented or dedented + # accordingly to previous level's indentation + # the first found, immediately break the while loop + if line_tok.value == '}': + if line_tok.formatted_whitespace_prefix.startswith('\n'): + close_column = len(line_tok.formatted_whitespace_prefix.lstrip('\n')) + else: close_column = line_tok.column + if close_column < first_key_column: + if dict_keys_lengths: + all_dict_keys_lengths.append(dict_keys_lengths) + closing = True + + # update the alignment once one dict is processed + if all_dict_keys_lengths: + max_keys_length = 0 + all_dict_keys_lengths_index = 0 + dict_keys_lengths = all_dict_keys_lengths[all_dict_keys_lengths_index] + max_keys_length = max(dict_keys_lengths or [0]) + 2 + keys_lengths_index = 0 + for token in line_tokens[open_index+1:index]: + if token.is_dict_colon: + # check if the key has multiple tokens and + # get the first key token in this key + key_token = token.previous_token + while key_token.previous_token.is_dict_key: + key_token = key_token.previous_token + key_column = len(key_token.formatted_whitespace_prefix.lstrip('\n')) + + if key_column == first_key_column: + + if keys_lengths_index == len(dict_keys_lengths): + all_dict_keys_lengths_index += 1 + dict_keys_lengths = all_dict_keys_lengths[all_dict_keys_lengths_index] + max_keys_length = max(dict_keys_lengths or [0]) + 2 + keys_lengths_index = 0 + + if keys_lengths_index < len(dict_keys_lengths): + assert dict_keys_lengths[keys_lengths_index] < max_keys_length + + padded_spaces = ' ' * ( + max_keys_length - dict_keys_lengths[keys_lengths_index] - 1) + keys_lengths_index += 1 + #NOTE if the existing whitespaces are larger than padded spaces + existing_whitespace_prefix = \ + token.formatted_whitespace_prefix.lstrip('\n') + colon_content = '{}{}'.format(padded_spaces, token.value.strip()) + + # in case the existing spaces are larger than the paddes spaces + if (len(padded_spaces) == 1 or len(padded_spaces) > 1 + and len(existing_whitespace_prefix) >= len(padded_spaces)): + # remove the existing spaces + token.whitespace_prefix = '' + elif colon_content.startswith(existing_whitespace_prefix): + colon_content = colon_content[len(existing_whitespace_prefix):] + + token.value = colon_content + + final_lines_index += 1 + + process_content = True + break + + if not process_content: + final_lines_index += 1 + + + def _FormatFinalLines(final_lines, verify): """Compose the final output from the finalized lines.""" formatted_code = [] diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 233a64e6b..a4c54b5f8 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -54,6 +54,22 @@ def SetGlobalStyle(style): _STYLE_HELP = dict( ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=textwrap.dedent("""\ Align closing bracket with visual indentation."""), + ALIGN_ASSIGNMENT=textwrap.dedent("""\ + Align assignment or augmented assignment operators. + If there is a blank line or newline comment or objects with newline entries in between, + it will start new block alignment."""), + ALIGN_ARGUMENT_ASSIGNMENT=textwrap.dedent("""\ + Align assignment operators in the argument list if they are all split on newlines. + Arguments without assignment are ignored. + Arguments without assignment in between will initiate new block alignment calulation. + Newline comments or objects with newline entries will also start new block alignment."""), + ALIGN_DICT_COLON=textwrap.dedent("""\ + Align the colons in the dictionary + if all entries in dictionay are split on newlines. + and 'EACH_DICT_ENTRY_ON_SEPERATE_LINE' set True. + """), + NEW_ALIGNMENT_AFTER_COMMENTLINE=textwrap.dedent("""\ + Start new assignment or colon alignment when there is a newline comment in between."""), ALLOW_MULTILINE_LAMBDAS=textwrap.dedent("""\ Allow lambdas to be formatted on more than one line."""), ALLOW_MULTILINE_DICTIONARY_KEYS=textwrap.dedent("""\ @@ -419,6 +435,10 @@ def CreatePEP8Style(): """Create the PEP8 formatting style.""" return dict( ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=True, + ALIGN_ASSIGNMENT=False, + ALIGN_ARGUMENT_ASSIGNMENT=False, + ALIGN_DICT_COLON=False, + NEW_ALIGNMENT_AFTER_COMMENTLINE=False, ALLOW_MULTILINE_LAMBDAS=False, ALLOW_MULTILINE_DICTIONARY_KEYS=False, ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=True, @@ -607,6 +627,10 @@ def _IntOrIntListConverter(s): # Note: this dict has to map all the supported style options. _STYLE_OPTION_VALUE_CONVERTER = dict( ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=_BoolConverter, + ALIGN_ASSIGNMENT=_BoolConverter, + ALIGN_DICT_COLON=_BoolConverter, + NEW_ALIGNMENT_AFTER_COMMENTLINE=_BoolConverter, + ALIGN_ARGUMENT_ASSIGNMENT=_BoolConverter, ALLOW_MULTILINE_LAMBDAS=_BoolConverter, ALLOW_MULTILINE_DICTIONARY_KEYS=_BoolConverter, ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=_BoolConverter, diff --git a/yapf/yapflib/subtypes.py b/yapf/yapflib/subtypes.py index b4b7efe75..21ca213ad 100644 --- a/yapf/yapflib/subtypes.py +++ b/yapf/yapflib/subtypes.py @@ -38,3 +38,4 @@ SIMPLE_EXPRESSION = 22 PARAMETER_START = 23 PARAMETER_STOP = 24 + diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index 6ea24af63..3bb1ce9f5 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -15,10 +15,11 @@ import unittest -from lib2to3 import pytree +from lib2to3 import pytree, pygram from lib2to3.pgen2 import token from yapf.yapflib import format_token +from yapf.pytree import subtype_assigner class TabbedContinuationAlignPaddingTest(unittest.TestCase): @@ -89,6 +90,37 @@ def testIsMultilineString(self): pytree.Leaf(token.STRING, 'r"""hello"""'), 'STRING') self.assertTrue(tok.is_multiline_string) + #------------test argument names------------ + # fun( + # a='hello world', + # # comment, + # b='') + child1 = pytree.Leaf(token.NAME, 'a') + child2 = pytree.Leaf(token.EQUAL, '=') + child3 = pytree.Leaf(token.STRING, "'hello world'") + child4 = pytree.Leaf(token.COMMA, ',') + child5 = pytree.Leaf(token.COMMENT,'# comment') + child6 = pytree.Leaf(token.COMMA, ',') + child7 = pytree.Leaf(token.NAME, 'b') + child8 = pytree.Leaf(token.EQUAL, '=') + child9 = pytree.Leaf(token.STRING, "''") + node_type = pygram.python_grammar.symbol2number['arglist'] + node = pytree.Node(node_type, [child1, child2, child3, child4, child5, + child6, child7, child8,child9]) + subtype_assigner.AssignSubtypes(node) + + def testIsArgName(self, node=node): + tok = format_token.FormatToken(node.children[0],'NAME') + self.assertTrue(tok.is_argname) + + def testIsArgAssign(self, node=node): + tok = format_token.FormatToken(node.children[1], 'EQUAL') + self.assertTrue(tok.is_argassign) + + # test if comment inside is not argname + def testCommentNotIsArgName(self, node=node): + tok = format_token.FormatToken(node.children[4], 'COMMENT') + self.assertFalse(tok.is_argname) if __name__ == '__main__': unittest.main() diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 657d1e246..0c68c8525 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1583,18 +1583,20 @@ def testNoSplittingWithinSubscriptList(self): llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) + def testExcessCharacters(self): code = textwrap.dedent("""\ - class foo: + class foo: - def bar(self): - self.write(s=[ - '%s%s %s' % ('many of really', 'long strings', '+ just makes up 81') - ]) - """) # noqa + def bar(self): + self.write(s=[ + '%s%s %s' % ('many of really', 'long strings', '+ just makes up 81') + ]) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) + unformatted_code = textwrap.dedent("""\ def _(): if True: @@ -2863,6 +2865,8 @@ def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: pass """) # noqa + # if dedent closing brackets and Align argAssign are true, there will be + # spaces before the argassign expected_formatted_code = textwrap.dedent("""\ def function( first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None @@ -2879,7 +2883,8 @@ def function( try: style.SetGlobalStyle( style.CreateStyleFromConfig('{based_on_style: yapf,' - ' dedent_closing_brackets: True}')) + ' dedent_closing_brackets: True,' + ' align_argument_assignment: False}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, @@ -3165,6 +3170,355 @@ def testWalrus(self): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected, reformatter.Reformat(llines)) + #------tests for alignment functions-------- + def testAlignAssignBlankLineInbetween(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{align_assignment: true}')) + unformatted_code = textwrap.dedent("""\ + val_first = 1 + val_second += 2 + + val_third = 3 + """) + expected_formatted_code = textwrap.dedent("""\ + val_first = 1 + val_second += 2 + + val_third = 3 + """) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) + + def testAlignAssignCommentLineInbetween(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{align_assignment: true,' + 'new_alignment_after_commentline = true}')) + unformatted_code = textwrap.dedent("""\ + val_first = 1 + val_second += 2 + # comment + val_third = 3 + """) + expected_formatted_code = textwrap.dedent("""\ + val_first = 1 + val_second += 2 + # comment + val_third = 3 + """) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) + + def testAlignAssignDefLineInbetween(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{align_assignment: true}')) + unformatted_code = textwrap.dedent("""\ + val_first = 1 + val_second += 2 + def fun(): + a = 'example' + abc = '' + val_third = 3 + """) + expected_formatted_code = textwrap.dedent("""\ + val_first = 1 + val_second += 2 + + + def fun(): + a = 'example' + abc = '' + + + val_third = 3 + """) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) + + def testAlignAssignObjectWithNewLineInbetween(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{align_assignment: true}')) + unformatted_code = textwrap.dedent("""\ + val_first = 1 + val_second += 2 + object = { + entry1:1, + entry2:2, + entry3:3, + } + val_third = 3 + """) + expected_formatted_code = textwrap.dedent("""\ + val_first = 1 + val_second += 2 + object = { + entry1: 1, + entry2: 2, + entry3: 3, + } + val_third = 3 + """) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) + + def testAlignAssignWithOnlyOneAssignmentLine(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{align_assignment: true}')) + unformatted_code = textwrap.dedent("""\ + val_first = 1 + """) + expected_formatted_code = unformatted_code + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) + + ########## for Align_ArgAssign()########### + def testAlignArgAssignTypedName(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{align_argument_assignment: true,' + 'dedent_closing_brackets: true}')) + unformatted_code = textwrap.dedent("""\ +def f1( + self, + *, + app_name:str="", + server=None, + main_app=None, + db: Optional[NemDB]=None, + root: Optional[str]="", + conf: Optional[dict]={1, 2}, + ini_section: str="" +): pass +""") + expected_formatted_code = textwrap.dedent("""\ +def f1( + self, + *, + app_name: str = "", + server =None, + main_app =None, + db: Optional[NemDB] = None, + root: Optional[str] = "", + conf: Optional[dict] = {1, 2}, + ini_section: str = "" +): + pass +""") + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) + + # test both object/nested argument list with newlines and + # argument without assignment in between + def testAlignArgAssignNestedArglistInBetween(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{align_argument_assignment: true,' + 'dedent_closing_brackets: true}')) + unformatted_code = textwrap.dedent("""\ +arglist = test( + first_argument='', + second_argument=fun( + self, role=3, username_id, client_id=1, very_long_long_long_long_long='' + ), + third_argument=3, + fourth_argument=4 +) +""") + expected_formatted_code = textwrap.dedent("""\ +arglist = test( + first_argument ='', + second_argument =fun( + self, + role =3, + username_id, + client_id =1, + very_long_long_long_long_long ='' + ), + third_argument =3, + fourth_argument =4 +) +""") + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) + + # start new alignment after comment line in between + def testAlignArgAssignCommentLineInBetween(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{align_argument_assignment: true,' + 'dedent_closing_brackets: true,' + 'new_alignment_after_commentline:true}')) + unformatted_code = textwrap.dedent("""\ +arglist = test( + client_id=0, + username_id=1, + # comment + user_name='xxxxxxxxxxxxxxxxxxxxx' +) +""") + expected_formatted_code = textwrap.dedent("""\ +arglist = test( + client_id =0, + username_id =1, + # comment + user_name ='xxxxxxxxxxxxxxxxxxxxx' +) +""") + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) + + def testAlignArgAssignWithOnlyFirstArgOnNewline(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{align_argument_assignment: true,' + 'dedent_closing_brackets: true}')) + unformatted_code = textwrap.dedent("""\ +arglist = self.get_data_from_excelsheet( + client_id=0, username_id=1, user_name='xxxxxxxxxxxxxxxxxxxx' +) +""") + expected_formatted_code = unformatted_code + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) + + def testAlignArgAssignArgumentsCanFitInOneLine(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{align_argument_assignment: true,' + 'dedent_closing_brackets: true}')) + unformatted_code = textwrap.dedent("""\ +def function( + first_argument_xxxxxx =(0,), + second_argument =None +) -> None: + pass +""") + expected_formatted_code = textwrap.dedent("""\ +def function(first_argument_xxxxxx=(0,), second_argument=None) -> None: + pass +""") + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) + + ########for align dictionary colons######### + def testAlignDictColonNestedDictInBetween(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{align_dict_colon: true,' + 'dedent_closing_brackets: true}')) + unformatted_code = textwrap.dedent("""\ +fields = [{"type": "text","required": True,"html": {"attr": 'style="width: 250px;" maxlength="30"',"page": 0,}, + "list" : [1, 2, 3, 4]}] +""") + expected_formatted_code = textwrap.dedent("""\ +fields = [ + { + "type" : "text", + "required" : True, + "html" : { + "attr" : 'style="width: 250px;" maxlength="30"', + "page" : 0, + }, + "list" : [1, 2, 3, 4] + } +] +""") + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) + + def testAlignDictColonCommentLineInBetween(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{align_dict_colon: true,' + 'dedent_closing_brackets: true,' + 'new_alignment_after_commentline: true}')) + unformatted_code = textwrap.dedent("""\ +fields = [{ + "type": "text", + "required": True, + # comment + "list": [1, 2, 3, 4]}] +""") + expected_formatted_code = textwrap.dedent("""\ +fields = [{ + "type" : "text", + "required" : True, + # comment + "list" : [1, 2, 3, 4] +}] +""") + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) + + def testAlignDictColonLargerExistingSpacesBefore(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{align_dict_colon: true,' + 'dedent_closing_brackets: true}')) + unformatted_code = textwrap.dedent("""\ +fields = [{ + "type" : "text", + "required" : True, + "list" : [1, 2, 3, 4], +}] +""") + expected_formatted_code = textwrap.dedent("""\ +fields = [{ + "type" : "text", + "required" : True, + "list" : [1, 2, 3, 4], +}] +""") + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) + + + + + if __name__ == '__main__': unittest.main() diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index 8616169c9..c69d13e4e 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -123,12 +123,117 @@ def testFuncCallWithDefaultAssign(self): subtypes.NONE, subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, }), - ('=', {subtypes.DEFAULT_OR_NAMED_ASSIGN}), - ("'hello world'", {subtypes.NONE}), + ('=', { + subtypes.DEFAULT_OR_NAMED_ASSIGN + }), + ("'hello world'", { + subtypes.NONE + }), + (')', {subtypes.NONE}), + ], + ]) + + #----test comment subtype inside the argument list---- + def testCommentSubtypesInsideArglist(self): + code = textwrap.dedent("""\ + foo( + # comment + x, + a='hello world') + """) + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckFormatTokenSubtypes(llines, [ + [ + ('foo', {subtypes.NONE}), + ('(', {subtypes.NONE}), + ('# comment', {subtypes.NONE, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST}), + ('x', { + subtypes.NONE, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + (',', {subtypes.NONE}), + ('a', { + subtypes.NONE, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + ('=', { + subtypes.DEFAULT_OR_NAMED_ASSIGN + }), + ("'hello world'", { + subtypes.NONE + }), + (')', {subtypes.NONE}), + ], + ]) + + # ----test typed arguments subtypes------ + def testTypedArgumentsInsideArglist(self): + code = textwrap.dedent("""\ +def foo( + self, + preprocess: Callable[[str], str] = identity + ): pass +""") + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckFormatTokenSubtypes(llines, [ + [ + ('def', {subtypes.NONE}), + ('foo', {subtypes.FUNC_DEF}), + ('(', {subtypes.NONE}), + ('self', {subtypes.NONE, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + subtypes.PARAMETER_START, + subtypes.PARAMETER_STOP + }), + (',', {subtypes.NONE}), + ('preprocess', { + subtypes.NONE, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + subtypes.PARAMETER_START, + subtypes.TYPED_NAME_ARG_LIST + }), + (':', { + subtypes.TYPED_NAME, + subtypes.TYPED_NAME_ARG_LIST, + }), + ('Callable', {subtypes.TYPED_NAME_ARG_LIST + }), + ('[', { + subtypes.SUBSCRIPT_BRACKET, + subtypes.TYPED_NAME_ARG_LIST + }), + ('[', {subtypes.TYPED_NAME_ARG_LIST + }), + ('str', {subtypes.TYPED_NAME_ARG_LIST + }), + (']', {subtypes.TYPED_NAME_ARG_LIST + }), + (',', {subtypes.TYPED_NAME_ARG_LIST + }), + ('str', {subtypes.TYPED_NAME_ARG_LIST + }), + (']', { + subtypes.SUBSCRIPT_BRACKET, + subtypes.TYPED_NAME_ARG_LIST + }), + ('=', { + subtypes.DEFAULT_OR_NAMED_ASSIGN, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + subtypes.TYPED_NAME + }), + ('identity', { + subtypes.NONE, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + subtypes.PARAMETER_STOP + }), (')', {subtypes.NONE}), + (':', {subtypes.NONE})], + [('pass', {subtypes.NONE}), ], ]) + def testSetComprehension(self): code = textwrap.dedent("""\ def foo(strs): diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 2330f4e18..4ddaf5c8a 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -26,7 +26,7 @@ from lib2to3.pgen2 import tokenize -from yapf.yapflib import errors +from yapf.yapflib import errors, reformatter from yapf.yapflib import py3compat from yapf.yapflib import style from yapf.yapflib import yapf_api From ddc0257b4397f10bf431bc3dde6182888e6f4288 Mon Sep 17 00:00:00 2001 From: Xiao Wang Date: Tue, 30 Aug 2022 11:59:59 +0200 Subject: [PATCH 563/719] update the changelog and readme --- CHANGELOG | 4 ++ CONTRIBUTORS | 1 + README.rst | 51 ++++++++++++++++++++++++ yapf/pytree/comment_splicer.py | 1 + yapf/pytree/subtype_assigner.py | 9 +---- yapf/yapflib/format_token.py | 11 ----- yapf/yapflib/reformatter.py | 1 - yapf/yapflib/style.py | 2 +- yapf/yapflib/subtypes.py | 3 +- yapftests/reformatter_basic_test.py | 19 ++++----- yapftests/subtype_assigner_test.py | 62 +++++++++-------------------- yapftests/yapf_test.py | 2 +- 12 files changed, 88 insertions(+), 78 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5ac3e6329..9004d6da0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.41.1] 2022-08-30 +### Added +- Add 4 new knobs to align assignment operators and dictionary colons. They are align_assignment, align_argument_assignment, align_dict_colon and new_alignment_after_commentline. + ## [0.40.0] UNRELEASED ### Added - Add a new Python parser to generate logical lines. diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 054ef2652..1852a9133 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -15,3 +15,4 @@ Sam Clegg Ɓukasz Langa Oleg Butuzov Mauricio Herrera Cuadra +Xiao Wang \ No newline at end of file diff --git a/README.rst b/README.rst index 5734a5d76..39b368c7d 100644 --- a/README.rst +++ b/README.rst @@ -390,6 +390,57 @@ Options:: Knobs ===== +``ALIGN_ASSIGNMENT`` + Align assignment or augmented assignment operators. + If there is a blank line or a newline comment or a multiline object + (e.g. a dictionary, a list, a function call) in between, + it will start new block alignment. Lines in the same block have the same + indentation level. + + .. code-block:: python + a = 1 + abc = 2 + if condition == None: + var += '' + var_long -= 4 + b = 3 + bc = 4 + +``ALIGN_ARGUMENT_ASSIGNMENT`` + Align assignment operators in the argument list if they are all split on newlines. + Arguments without assignment in between will initiate new block alignment calulation; + for example, a comment line. + Multiline objects in between will also initiate a new alignment block. + + .. code-block:: python + rglist = test( + var_first = 0, + var_second = '', + var_dict = { + "key_1" : '', + "key_2" : 2, + "key_3" : True, + }, + var_third = 1, + var_very_long = None ) + +``ALIGN_DICT_COLON`` + Align the colons in the dictionary if all entries in dictionay are split on newlines + or 'EACH_DICT_ENTRY_ON_SEPERATE_LINE' is set True. + A commentline or multi-line object in between will start new alignment block. + .. code-block:: python + fields = + { + "field" : "ediid", + "type" : "text", + # key: value + "required" : True, + } + +``NEW_ALIGNMENT_AFTER_COMMENTLINE`` + Make it optional to whether start a new alignmetn block for assignment + alignment and colon alignment after a comment line. + ``ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT`` Align closing bracket with visual indentation. diff --git a/yapf/pytree/comment_splicer.py b/yapf/pytree/comment_splicer.py index 9e8f02c48..ae5ffe66f 100644 --- a/yapf/pytree/comment_splicer.py +++ b/yapf/pytree/comment_splicer.py @@ -42,6 +42,7 @@ def SpliceComments(tree): # This is a list because Python 2.x doesn't have 'nonlocal' :) prev_leaf = [None] _AnnotateIndents(tree) + def _VisitNodeRec(node): """Recursively visit each node to splice comments into the AST.""" # This loop may insert into node.children, so we'll iterate over a copy. diff --git a/yapf/pytree/subtype_assigner.py b/yapf/pytree/subtype_assigner.py index 03d7efe1a..5ebefc704 100644 --- a/yapf/pytree/subtype_assigner.py +++ b/yapf/pytree/subtype_assigner.py @@ -301,7 +301,6 @@ def Visit_typedargslist(self, node): # pylint: disable=invalid-name for i in range(1, len(node.children)): prev_child = node.children[i - 1] child = node.children[i] - if prev_child.type == grammar_token.COMMA: _AppendFirstLeafTokenSubtype(child, subtypes.PARAMETER_START) elif child.type == grammar_token.COMMA: @@ -311,7 +310,7 @@ def Visit_typedargslist(self, node): # pylint: disable=invalid-name tname = True _SetArgListSubtype(child, subtypes.TYPED_NAME, subtypes.TYPED_NAME_ARG_LIST) - # NOTE Every element of the tynamme argument list + # NOTE Every element of the tynamme argument # should have this list type _AppendSubtypeRec(child, subtypes.TYPED_NAME_ARG_LIST) @@ -389,25 +388,21 @@ def HasSubtype(node): for child in node.children: node_name = pytree_utils.NodeName(child) - #TODO exclude it if the first leaf is a comment in appendfirstleaftokensubtype if node_name not in {'atom', 'COMMA'}: _AppendFirstLeafTokenSubtype(child, list_subtype) - def _AppendTokenSubtype(node, subtype): """Append the token's subtype only if it's not already set.""" pytree_utils.AppendNodeAnnotation(node, pytree_utils.Annotation.SUBTYPE, subtype) -#TODO should exclude comment child to all Appendsubtypes functions + def _AppendFirstLeafTokenSubtype(node, subtype): """Append the first leaf token's subtypes.""" - #TODO exclude the comment leaf if isinstance(node, pytree.Leaf): _AppendTokenSubtype(node, subtype) return - _AppendFirstLeafTokenSubtype(node.children[0], subtype) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index f8658f772..1618b35af 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -14,7 +14,6 @@ """Enhanced token information for formatting.""" import keyword -from operator import sub import re from lib2to3.pgen2 import token @@ -125,7 +124,6 @@ def __init__(self, node, name): self.subtypes = {subtypes.NONE} if not stypes else stypes self.is_pseudo = hasattr(node, 'is_pseudo') and node.is_pseudo - @property def formatted_whitespace_prefix(self): if style.Get('INDENT_BLANK_LINES'): @@ -325,7 +323,6 @@ def is_copybara_comment(self): return self.is_comment and re.match( r'#.*\bcopybara:\s*(strip|insert|replace)', self.value) - @property def is_assign(self): return subtypes.ASSIGN_OPERATOR in self.subtypes @@ -382,7 +379,6 @@ def is_argname(self): return False - @property def is_argname_start(self): # return true if it's the start of every argument entry @@ -404,10 +400,3 @@ def is_argname_start(self): or subtypes.TYPED_NAME_ARG_LIST in self.subtypes or subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in self.subtypes)) ) - - - - - - - diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 92aaa950e..4cdaf165c 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -103,7 +103,6 @@ def Reformat(llines, verify=False, lines=None): final_lines.append(lline) prev_line = lline - if style.Get('ALIGN_ASSIGNMENT'): _AlignAssignment(final_lines) if (style.Get('EACH_DICT_ENTRY_ON_SEPARATE_LINE') diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index a4c54b5f8..d9e9e5e9e 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -66,7 +66,7 @@ def SetGlobalStyle(style): ALIGN_DICT_COLON=textwrap.dedent("""\ Align the colons in the dictionary if all entries in dictionay are split on newlines. - and 'EACH_DICT_ENTRY_ON_SEPERATE_LINE' set True. + or 'EACH_DICT_ENTRY_ON_SEPERATE_LINE' is set True. """), NEW_ALIGNMENT_AFTER_COMMENTLINE=textwrap.dedent("""\ Start new assignment or colon alignment when there is a newline comment in between."""), diff --git a/yapf/yapflib/subtypes.py b/yapf/yapflib/subtypes.py index 21ca213ad..2c0431853 100644 --- a/yapf/yapflib/subtypes.py +++ b/yapf/yapflib/subtypes.py @@ -37,5 +37,4 @@ TYPED_NAME_ARG_LIST = 21 SIMPLE_EXPRESSION = 22 PARAMETER_START = 23 -PARAMETER_STOP = 24 - +PARAMETER_STOP = 24 \ No newline at end of file diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 0c68c8525..3371ac339 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1583,20 +1583,18 @@ def testNoSplittingWithinSubscriptList(self): llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) - def testExcessCharacters(self): code = textwrap.dedent("""\ - class foo: + class foo: - def bar(self): - self.write(s=[ - '%s%s %s' % ('many of really', 'long strings', '+ just makes up 81') - ]) - """) # noqa + def bar(self): + self.write(s=[ + '%s%s %s' % ('many of really', 'long strings', '+ just makes up 81') + ]) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ def _(): if True: @@ -2865,8 +2863,6 @@ def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: pass """) # noqa - # if dedent closing brackets and Align argAssign are true, there will be - # spaces before the argassign expected_formatted_code = textwrap.dedent("""\ def function( first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None @@ -2883,8 +2879,7 @@ def function( try: style.SetGlobalStyle( style.CreateStyleFromConfig('{based_on_style: yapf,' - ' dedent_closing_brackets: True,' - ' align_argument_assignment: False}')) + ' dedent_closing_brackets: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index c69d13e4e..97f9cd3ac 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -123,12 +123,8 @@ def testFuncCallWithDefaultAssign(self): subtypes.NONE, subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, }), - ('=', { - subtypes.DEFAULT_OR_NAMED_ASSIGN - }), - ("'hello world'", { - subtypes.NONE - }), + ('=', {subtypes.DEFAULT_OR_NAMED_ASSIGN}), + ("'hello world'", {subtypes.NONE}), (')', {subtypes.NONE}), ], ]) @@ -150,19 +146,13 @@ def testCommentSubtypesInsideArglist(self): subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST}), ('x', { subtypes.NONE, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - }), + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST}), (',', {subtypes.NONE}), ('a', { subtypes.NONE, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - }), - ('=', { - subtypes.DEFAULT_OR_NAMED_ASSIGN - }), - ("'hello world'", { - subtypes.NONE - }), + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST}), + ('=', {subtypes.DEFAULT_OR_NAMED_ASSIGN}), + ("'hello world'", {subtypes.NONE}), (')', {subtypes.NONE}), ], ]) @@ -184,56 +174,42 @@ def foo( ('self', {subtypes.NONE, subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, subtypes.PARAMETER_START, - subtypes.PARAMETER_STOP - }), + subtypes.PARAMETER_STOP}), (',', {subtypes.NONE}), ('preprocess', { subtypes.NONE, subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, subtypes.PARAMETER_START, - subtypes.TYPED_NAME_ARG_LIST - }), + subtypes.TYPED_NAME_ARG_LIST}), (':', { subtypes.TYPED_NAME, - subtypes.TYPED_NAME_ARG_LIST, - }), - ('Callable', {subtypes.TYPED_NAME_ARG_LIST - }), + subtypes.TYPED_NAME_ARG_LIST}), + ('Callable', {subtypes.TYPED_NAME_ARG_LIST}), ('[', { subtypes.SUBSCRIPT_BRACKET, - subtypes.TYPED_NAME_ARG_LIST - }), - ('[', {subtypes.TYPED_NAME_ARG_LIST - }), - ('str', {subtypes.TYPED_NAME_ARG_LIST - }), - (']', {subtypes.TYPED_NAME_ARG_LIST - }), - (',', {subtypes.TYPED_NAME_ARG_LIST - }), - ('str', {subtypes.TYPED_NAME_ARG_LIST - }), + subtypes.TYPED_NAME_ARG_LIST}), + ('[', {subtypes.TYPED_NAME_ARG_LIST}), + ('str', {subtypes.TYPED_NAME_ARG_LIST}), + (']', {subtypes.TYPED_NAME_ARG_LIST}), + (',', {subtypes.TYPED_NAME_ARG_LIST}), + ('str', {subtypes.TYPED_NAME_ARG_LIST}), (']', { subtypes.SUBSCRIPT_BRACKET, - subtypes.TYPED_NAME_ARG_LIST - }), + subtypes.TYPED_NAME_ARG_LIST}), ('=', { subtypes.DEFAULT_OR_NAMED_ASSIGN, subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - subtypes.TYPED_NAME - }), + subtypes.TYPED_NAME}), ('identity', { subtypes.NONE, subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - subtypes.PARAMETER_STOP - }), + subtypes.PARAMETER_STOP}), (')', {subtypes.NONE}), (':', {subtypes.NONE})], [('pass', {subtypes.NONE}), ], ]) - def testSetComprehension(self): code = textwrap.dedent("""\ def foo(strs): diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 4ddaf5c8a..2330f4e18 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -26,7 +26,7 @@ from lib2to3.pgen2 import tokenize -from yapf.yapflib import errors, reformatter +from yapf.yapflib import errors from yapf.yapflib import py3compat from yapf.yapflib import style from yapf.yapflib import yapf_api From 9ea41f85ecd564eee88b13704099b26627c25e68 Mon Sep 17 00:00:00 2001 From: Xiao Wang Date: Tue, 30 Aug 2022 12:08:43 +0200 Subject: [PATCH 564/719] small fixes --- README.rst | 2 +- yapf/pytree/subtype_assigner.py | 4 ++-- yapf/yapflib/subtypes.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 39b368c7d..845ea441d 100644 --- a/README.rst +++ b/README.rst @@ -438,7 +438,7 @@ Knobs } ``NEW_ALIGNMENT_AFTER_COMMENTLINE`` - Make it optional to whether start a new alignmetn block for assignment + Make it optional to start a new alignmetn block for assignment alignment and colon alignment after a comment line. ``ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT`` diff --git a/yapf/pytree/subtype_assigner.py b/yapf/pytree/subtype_assigner.py index 5ebefc704..0ee247a82 100644 --- a/yapf/pytree/subtype_assigner.py +++ b/yapf/pytree/subtype_assigner.py @@ -401,8 +401,8 @@ def _AppendTokenSubtype(node, subtype): def _AppendFirstLeafTokenSubtype(node, subtype): """Append the first leaf token's subtypes.""" if isinstance(node, pytree.Leaf): - _AppendTokenSubtype(node, subtype) - return + _AppendTokenSubtype(node, subtype) + return _AppendFirstLeafTokenSubtype(node.children[0], subtype) diff --git a/yapf/yapflib/subtypes.py b/yapf/yapflib/subtypes.py index 2c0431853..b4b7efe75 100644 --- a/yapf/yapflib/subtypes.py +++ b/yapf/yapflib/subtypes.py @@ -37,4 +37,4 @@ TYPED_NAME_ARG_LIST = 21 SIMPLE_EXPRESSION = 22 PARAMETER_START = 23 -PARAMETER_STOP = 24 \ No newline at end of file +PARAMETER_STOP = 24 From 8926920de03582b33dcee0a5eef53b7845361d76 Mon Sep 17 00:00:00 2001 From: lizawang <56673986+lizawang@users.noreply.github.com> Date: Tue, 30 Aug 2022 13:32:06 +0200 Subject: [PATCH 565/719] Update README.rst --- README.rst | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index 845ea441d..71e4497be 100644 --- a/README.rst +++ b/README.rst @@ -398,6 +398,7 @@ Knobs indentation level. .. code-block:: python + a = 1 abc = 2 if condition == None: @@ -413,22 +414,25 @@ Knobs Multiline objects in between will also initiate a new alignment block. .. code-block:: python - rglist = test( - var_first = 0, - var_second = '', - var_dict = { - "key_1" : '', - "key_2" : 2, - "key_3" : True, - }, - var_third = 1, - var_very_long = None ) + + rglist = test( + var_first = 0, + var_second = '', + var_dict = { + "key_1" : '', + "key_2" : 2, + "key_3" : True, + }, + var_third = 1, + var_very_long = None ) ``ALIGN_DICT_COLON`` Align the colons in the dictionary if all entries in dictionay are split on newlines or 'EACH_DICT_ENTRY_ON_SEPERATE_LINE' is set True. A commentline or multi-line object in between will start new alignment block. + .. code-block:: python + fields = { "field" : "ediid", From 1528de981adc70e2869714a1b527f1450e367e67 Mon Sep 17 00:00:00 2001 From: Xiao Wang Date: Tue, 30 Aug 2022 13:57:19 +0200 Subject: [PATCH 566/719] fix readme --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index 845ea441d..c54801650 100644 --- a/README.rst +++ b/README.rst @@ -398,6 +398,7 @@ Knobs indentation level. .. code-block:: python + a = 1 abc = 2 if condition == None: @@ -413,6 +414,7 @@ Knobs Multiline objects in between will also initiate a new alignment block. .. code-block:: python + rglist = test( var_first = 0, var_second = '', @@ -428,7 +430,9 @@ Knobs Align the colons in the dictionary if all entries in dictionay are split on newlines or 'EACH_DICT_ENTRY_ON_SEPERATE_LINE' is set True. A commentline or multi-line object in between will start new alignment block. + .. code-block:: python + fields = { "field" : "ediid", From 7eb1c3407950e30e92486d399684f91c2c548c99 Mon Sep 17 00:00:00 2001 From: Xiao Wang Date: Tue, 13 Sep 2022 18:12:28 +0200 Subject: [PATCH 567/719] fix align_dict_colon --- yapf/yapflib/format_token.py | 1 + yapf/yapflib/reformatter.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 1618b35af..070987851 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -382,6 +382,7 @@ def is_argname(self): @property def is_argname_start(self): # return true if it's the start of every argument entry + previous_subtypes = {0} if self.previous_token: previous_subtypes = self.previous_token.subtypes diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 4cdaf165c..e63917134 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -858,7 +858,7 @@ def _AlignDictColon(final_lines): # check if the key has multiple tokens and # get the first key token in this key key_token = token.previous_token - while key_token.previous_token.is_dict_key: + while key_token.is_dict_key and not key_token.is_dict_key_start: key_token = key_token.previous_token key_column = len(key_token.formatted_whitespace_prefix.lstrip('\n')) From a75196d02c242eea23acc4ca779ab02b18edf94b Mon Sep 17 00:00:00 2001 From: Xiao Wang Date: Thu, 15 Sep 2022 10:46:49 +0200 Subject: [PATCH 568/719] add test for the case when the dict starts with a comment --- yapf/yapflib/reformatter.py | 4 +- yapftests/reformatter_basic_test.py | 87 ++++++++++++++++------------- 2 files changed, 50 insertions(+), 41 deletions(-) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index e63917134..8f8a103f8 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -658,7 +658,7 @@ def _AlignArgAssign(final_lines): index += 1 if index < len(line_tokens): line_tok = line_tokens[index] - # when the matching closing bracket never found + # when the matching closing bracket is never found # due to edge cases where the closing bracket # is not indented or dedented else: @@ -816,7 +816,7 @@ def _AlignDictColon(final_lines): index += 1 if index < len(line_tokens): line_tok = line_tokens[index] - # when the matching closing bracket never found + # when the matching closing bracket is never found # due to edge cases where the closing bracket # is not indented or dedented, e.g. ']}', with another bracket before else: diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 3371ac339..0eeeefdce 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -3285,12 +3285,12 @@ def testAlignAssignWithOnlyOneAssignmentLine(self): finally: style.SetGlobalStyle(style.CreateYapfStyle()) - ########## for Align_ArgAssign()########### + ########## for Align_ArgAssign()########### def testAlignArgAssignTypedName(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig('{align_argument_assignment: true,' - 'dedent_closing_brackets: true}')) + 'split_before_first_argument: true}')) unformatted_code = textwrap.dedent("""\ def f1( self, @@ -3314,8 +3314,7 @@ def f1( db: Optional[NemDB] = None, root: Optional[str] = "", conf: Optional[dict] = {1, 2}, - ini_section: str = "" -): + ini_section: str = ""): pass """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) @@ -3329,13 +3328,12 @@ def f1( def testAlignArgAssignNestedArglistInBetween(self): try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{align_argument_assignment: true,' - 'dedent_closing_brackets: true}')) + style.CreateStyleFromConfig('{align_argument_assignment: true}')) unformatted_code = textwrap.dedent("""\ arglist = test( first_argument='', second_argument=fun( - self, role=3, username_id, client_id=1, very_long_long_long_long_long='' + self, role=None, client_name='', client_id=1, very_long_long_long_long_long='' ), third_argument=3, fourth_argument=4 @@ -3346,14 +3344,12 @@ def testAlignArgAssignNestedArglistInBetween(self): first_argument ='', second_argument =fun( self, - role =3, - username_id, + role =None, + client_name ='', client_id =1, - very_long_long_long_long_long ='' - ), + very_long_long_long_long_long =''), third_argument =3, - fourth_argument =4 -) + fourth_argument =4) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, @@ -3366,7 +3362,6 @@ def testAlignArgAssignCommentLineInBetween(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig('{align_argument_assignment: true,' - 'dedent_closing_brackets: true,' 'new_alignment_after_commentline:true}')) unformatted_code = textwrap.dedent("""\ arglist = test( @@ -3381,8 +3376,7 @@ def testAlignArgAssignCommentLineInBetween(self): client_id =0, username_id =1, # comment - user_name ='xxxxxxxxxxxxxxxxxxxxx' -) + user_name ='xxxxxxxxxxxxxxxxxxxxx') """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, @@ -3393,12 +3387,10 @@ def testAlignArgAssignCommentLineInBetween(self): def testAlignArgAssignWithOnlyFirstArgOnNewline(self): try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{align_argument_assignment: true,' - 'dedent_closing_brackets: true}')) + style.CreateStyleFromConfig('{align_argument_assignment: true}')) unformatted_code = textwrap.dedent("""\ arglist = self.get_data_from_excelsheet( - client_id=0, username_id=1, user_name='xxxxxxxxxxxxxxxxxxxx' -) + client_id=0, username_id=1, user_name='xxxxxxxxxxxxxxxxxxxx') """) expected_formatted_code = unformatted_code llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) @@ -3410,8 +3402,7 @@ def testAlignArgAssignWithOnlyFirstArgOnNewline(self): def testAlignArgAssignArgumentsCanFitInOneLine(self): try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{align_argument_assignment: true,' - 'dedent_closing_brackets: true}')) + style.CreateStyleFromConfig('{align_argument_assignment: true}')) unformatted_code = textwrap.dedent("""\ def function( first_argument_xxxxxx =(0,), @@ -3433,24 +3424,21 @@ def function(first_argument_xxxxxx=(0,), second_argument=None) -> None: def testAlignDictColonNestedDictInBetween(self): try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{align_dict_colon: true,' - 'dedent_closing_brackets: true}')) + style.CreateStyleFromConfig('{align_dict_colon: true}')) unformatted_code = textwrap.dedent("""\ fields = [{"type": "text","required": True,"html": {"attr": 'style="width: 250px;" maxlength="30"',"page": 0,}, "list" : [1, 2, 3, 4]}] """) expected_formatted_code = textwrap.dedent("""\ -fields = [ - { - "type" : "text", - "required" : True, - "html" : { - "attr" : 'style="width: 250px;" maxlength="30"', - "page" : 0, - }, - "list" : [1, 2, 3, 4] - } -] +fields = [{ + "type" : "text", + "required" : True, + "html" : { + "attr" : 'style="width: 250px;" maxlength="30"', + "page" : 0, + }, + "list" : [1, 2, 3, 4] +}] """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, @@ -3462,7 +3450,6 @@ def testAlignDictColonCommentLineInBetween(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig('{align_dict_colon: true,' - 'dedent_closing_brackets: true,' 'new_alignment_after_commentline: true}')) unformatted_code = textwrap.dedent("""\ fields = [{ @@ -3488,8 +3475,7 @@ def testAlignDictColonCommentLineInBetween(self): def testAlignDictColonLargerExistingSpacesBefore(self): try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{align_dict_colon: true,' - 'dedent_closing_brackets: true}')) + style.CreateStyleFromConfig('{align_dict_colon: true}')) unformatted_code = textwrap.dedent("""\ fields = [{ "type" : "text", @@ -3510,7 +3496,30 @@ def testAlignDictColonLargerExistingSpacesBefore(self): finally: style.SetGlobalStyle(style.CreateYapfStyle()) - + def testAlignDictColonCommentAfterOpenBracket(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{align_dict_colon: true}')) + unformatted_code = textwrap.dedent("""\ +fields = [{ + # comment + "type": "text", + "required": True, + "list": [1, 2, 3, 4]}] +""") + expected_formatted_code = textwrap.dedent("""\ +fields = [{ + # comment + "type" : "text", + "required" : True, + "list" : [1, 2, 3, 4] +}] +""") + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) From 69fb7e124ffc50672e391f858b969a440c66bc8f Mon Sep 17 00:00:00 2001 From: "Yilei \"Dolee\" Yang" Date: Fri, 23 Sep 2022 10:44:06 -0700 Subject: [PATCH 569/719] Also support Black's `# fmt: off/on` pragma. (#1026) * Also support Black's `# fmt: off/on` pragma. * Update changelog for the new pragma. --- CHANGELOG | 1 + yapf/yapflib/yapf_api.py | 4 ++-- yapftests/yapf_test.py | 23 +++++++++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5ac3e6329..8b29032f4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,7 @@ ## [0.40.0] UNRELEASED ### Added - Add a new Python parser to generate logical lines. +- Added support for `# fmt: on` and `# fmt: off` pragmas. ### Changes - Moved 'pytree' parsing tools into its own subdirectory. - Add support for Python 3.10. diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index c17451434..475d0186d 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -256,8 +256,8 @@ def _SplitSemicolons(lines): return res -DISABLE_PATTERN = r'^#.*\byapf:\s*disable\b' -ENABLE_PATTERN = r'^#.*\byapf:\s*enable\b' +DISABLE_PATTERN = r'^#.*\b(?:yapf:\s*disable|fmt: ?off)\b' +ENABLE_PATTERN = r'^#.*\b(?:yapf:\s*enable|fmt: ?on)\b' def _LineRangesToSet(line_ranges): diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 2330f4e18..6749bf0c1 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -152,6 +152,29 @@ def testDisableAndReenableLinesPattern(self): formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(expected_formatted_code, formatted_code) + def testFmtOnOff(self): + unformatted_code = textwrap.dedent(u"""\ + if a: b + + # fmt: off + if f: g + # fmt: on + + if h: i + """) + expected_formatted_code = textwrap.dedent(u"""\ + if a: b + + # fmt: off + if f: g + # fmt: on + + if h: i + """) + with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: + formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') + self.assertCodeEqual(expected_formatted_code, formatted_code) + def testDisablePartOfMultilineComment(self): unformatted_code = textwrap.dedent(u"""\ if a: b From 030c268b2a881546beb5c103e0c3da9209ab09b6 Mon Sep 17 00:00:00 2001 From: Bill Wendling <5993918+gwelymernans@users.noreply.github.com> Date: Fri, 23 Sep 2022 18:03:58 +0000 Subject: [PATCH 570/719] Change indentation --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 73e69f33a..5ba8b7a16 100644 --- a/setup.py +++ b/setup.py @@ -51,7 +51,7 @@ def run(self): maintainer_email='morbo@google.com', packages=find_packages('.'), project_urls={ - 'Source': 'https://github.com/google/yapf', + 'Source': 'https://github.com/google/yapf', }, classifiers=[ 'Development Status :: 4 - Beta', From 7c0c8d492898209e0627c0de569e606c0d7c8c38 Mon Sep 17 00:00:00 2001 From: Xiao Wang Date: Mon, 3 Oct 2022 14:46:26 +0200 Subject: [PATCH 571/719] branch for assignment alignment --- yapf/__init__.py | 536 +++--- yapf/pyparser/pyparser.py | 143 +- yapf/pyparser/pyparser_utils.py | 92 +- yapf/pyparser/split_penalty_visitor.py | 1776 ++++++++++---------- yapf/pytree/blank_line_calculator.py | 243 +-- yapf/pytree/comment_splicer.py | 526 +++--- yapf/pytree/continuation_splicer.py | 40 +- yapf/pytree/pytree_unwrapper.py | 537 +++--- yapf/pytree/pytree_utils.py | 285 ++-- yapf/pytree/pytree_visitor.py | 90 +- yapf/pytree/split_penalty.py | 1145 ++++++------- yapf/pytree/subtype_assigner.py | 867 +++++----- yapf/third_party/yapf_diff/yapf_diff.py | 197 +-- yapf/yapflib/errors.py | 23 +- yapf/yapflib/file_resources.py | 412 +++-- yapf/yapflib/format_decision_state.py | 2056 ++++++++++++----------- yapf/yapflib/format_token.py | 554 +++--- yapf/yapflib/identify_container.py | 60 +- yapf/yapflib/line_joiner.py | 84 +- yapf/yapflib/logical_line.py | 1146 ++++++------- yapf/yapflib/object_state.py | 303 ++-- yapf/yapflib/py3compat.py | 158 +- yapf/yapflib/reformatter.py | 1718 ++++++++----------- yapf/yapflib/split_penalty.py | 16 +- yapf/yapflib/style.py | 1043 ++++++------ yapf/yapflib/subtypes.py | 48 +- yapf/yapflib/verifier.py | 102 +- yapf/yapflib/yapf_api.py | 369 ++-- yapftests/format_token_test.py | 31 - yapftests/reformatter_basic_test.py | 243 +-- yapftests/subtype_assigner_test.py | 81 - 31 files changed, 7155 insertions(+), 7769 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 94e445b59..e8825c1cb 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -41,8 +41,8 @@ __version__ = '0.32.0' -def main(argv): - """Main program. +def main( argv ): + """Main program. Arguments: argv: command-line arguments, such as sys.argv (including the program name @@ -55,114 +55,116 @@ def main(argv): Raises: YapfError: if none of the supplied files were Python files. """ - parser = _BuildParser() - args = parser.parse_args(argv[1:]) - style_config = args.style - - if args.style_help: - _PrintHelp(args) - return 0 - - if args.lines and len(args.files) > 1: - parser.error('cannot use -l/--lines with more than one file') - - lines = _GetLines(args.lines) if args.lines is not None else None - if not args.files: - # No arguments specified. Read code from stdin. - if args.in_place or args.diff: - parser.error('cannot use --in-place or --diff flags when reading ' - 'from stdin') - - original_source = [] - while True: - # Test that sys.stdin has the "closed" attribute. When using pytest, it - # co-opts sys.stdin, which makes the "main_tests.py" fail. This is gross. - if hasattr(sys.stdin, "closed") and sys.stdin.closed: - break - try: - # Use 'raw_input' instead of 'sys.stdin.read', because otherwise the - # user will need to hit 'Ctrl-D' more than once if they're inputting - # the program by hand. 'raw_input' throws an EOFError exception if - # 'Ctrl-D' is pressed, which makes it easy to bail out of this loop. - original_source.append(py3compat.raw_input()) - except EOFError: - break - except KeyboardInterrupt: - return 1 - - if style_config is None and not args.no_local_style: - style_config = file_resources.GetDefaultStyleForDir(os.getcwd()) - - source = [line.rstrip() for line in original_source] - source[0] = py3compat.removeBOM(source[0]) - - try: - reformatted_source, _ = yapf_api.FormatCode( - py3compat.unicode('\n'.join(source) + '\n'), - filename='', - style_config=style_config, - lines=lines, - verify=args.verify) - except errors.YapfError: - raise - except Exception as e: - raise errors.YapfError(errors.FormatErrorMsg(e)) - - file_resources.WriteReformattedCode('', reformatted_source) - return 0 - - # Get additional exclude patterns from ignorefile - exclude_patterns_from_ignore_file = file_resources.GetExcludePatternsForDir( - os.getcwd()) - - files = file_resources.GetCommandLineFiles(args.files, args.recursive, - (args.exclude or []) + - exclude_patterns_from_ignore_file) - if not files: - raise errors.YapfError('input filenames did not match any python files') - - changed = FormatFiles( - files, - lines, - style_config=args.style, - no_local_style=args.no_local_style, - in_place=args.in_place, - print_diff=args.diff, - verify=args.verify, - parallel=args.parallel, - quiet=args.quiet, - verbose=args.verbose) - return 1 if changed and (args.diff or args.quiet) else 0 - - -def _PrintHelp(args): - """Prints the help menu.""" - - if args.style is None and not args.no_local_style: - args.style = file_resources.GetDefaultStyleForDir(os.getcwd()) - style.SetGlobalStyle(style.CreateStyleFromConfig(args.style)) - print('[style]') - for option, docstring in sorted(style.Help().items()): - for line in docstring.splitlines(): - print('#', line and ' ' or '', line, sep='') - option_value = style.Get(option) - if isinstance(option_value, (set, list)): - option_value = ', '.join(map(str, option_value)) - print(option.lower(), '=', option_value, sep='') - print() - - -def FormatFiles(filenames, - lines, - style_config=None, - no_local_style=False, - in_place=False, - print_diff=False, - verify=False, - parallel=False, - quiet=False, - verbose=False): - """Format a list of files. + parser = _BuildParser() + args = parser.parse_args( argv[ 1 : ] ) + style_config = args.style + + if args.style_help: + _PrintHelp( args ) + return 0 + + if args.lines and len( args.files ) > 1: + parser.error( 'cannot use -l/--lines with more than one file' ) + + lines = _GetLines( args.lines ) if args.lines is not None else None + if not args.files: + # No arguments specified. Read code from stdin. + if args.in_place or args.diff: + parser.error( + 'cannot use --in-place or --diff flags when reading ' + 'from stdin' ) + + original_source = [] + while True: + # Test that sys.stdin has the "closed" attribute. When using pytest, it + # co-opts sys.stdin, which makes the "main_tests.py" fail. This is gross. + if hasattr( sys.stdin, "closed" ) and sys.stdin.closed: + break + try: + # Use 'raw_input' instead of 'sys.stdin.read', because otherwise the + # user will need to hit 'Ctrl-D' more than once if they're inputting + # the program by hand. 'raw_input' throws an EOFError exception if + # 'Ctrl-D' is pressed, which makes it easy to bail out of this loop. + original_source.append( py3compat.raw_input() ) + except EOFError: + break + except KeyboardInterrupt: + return 1 + + if style_config is None and not args.no_local_style: + style_config = file_resources.GetDefaultStyleForDir( os.getcwd() ) + + source = [ line.rstrip() for line in original_source ] + source[ 0 ] = py3compat.removeBOM( source[ 0 ] ) + + try: + reformatted_source, _ = yapf_api.FormatCode( + py3compat.unicode( '\n'.join( source ) + '\n' ), + filename = '', + style_config = style_config, + lines = lines, + verify = args.verify ) + except errors.YapfError: + raise + except Exception as e: + raise errors.YapfError( errors.FormatErrorMsg( e ) ) + + file_resources.WriteReformattedCode( '', reformatted_source ) + return 0 + + # Get additional exclude patterns from ignorefile + exclude_patterns_from_ignore_file = file_resources.GetExcludePatternsForDir( + os.getcwd() ) + + files = file_resources.GetCommandLineFiles( + args.files, args.recursive, + ( args.exclude or [] ) + exclude_patterns_from_ignore_file ) + if not files: + raise errors.YapfError( 'input filenames did not match any python files' ) + + changed = FormatFiles( + files, + lines, + style_config = args.style, + no_local_style = args.no_local_style, + in_place = args.in_place, + print_diff = args.diff, + verify = args.verify, + parallel = args.parallel, + quiet = args.quiet, + verbose = args.verbose ) + return 1 if changed and ( args.diff or args.quiet ) else 0 + + +def _PrintHelp( args ): + """Prints the help menu.""" + + if args.style is None and not args.no_local_style: + args.style = file_resources.GetDefaultStyleForDir( os.getcwd() ) + style.SetGlobalStyle( style.CreateStyleFromConfig( args.style ) ) + print( '[style]' ) + for option, docstring in sorted( style.Help().items() ): + for line in docstring.splitlines(): + print( '#', line and ' ' or '', line, sep = '' ) + option_value = style.Get( option ) + if isinstance( option_value, ( set, list ) ): + option_value = ', '.join( map( str, option_value ) ) + print( option.lower(), '=', option_value, sep = '' ) + print() + + +def FormatFiles( + filenames, + lines, + style_config = None, + no_local_style = False, + in_place = False, + print_diff = False, + verify = False, + parallel = False, + quiet = False, + verbose = False ): + """Format a list of files. Arguments: filenames: (list of unicode) A list of files to reformat. @@ -184,65 +186,68 @@ def FormatFiles(filenames, Returns: True if the source code changed in any of the files being formatted. """ - changed = False - if parallel: - import multiprocessing # pylint: disable=g-import-not-at-top - import concurrent.futures # pylint: disable=g-import-not-at-top - workers = min(multiprocessing.cpu_count(), len(filenames)) - with concurrent.futures.ProcessPoolExecutor(workers) as executor: - future_formats = [ - executor.submit(_FormatFile, filename, lines, style_config, - no_local_style, in_place, print_diff, verify, quiet, - verbose) for filename in filenames - ] - for future in concurrent.futures.as_completed(future_formats): - changed |= future.result() - else: - for filename in filenames: - changed |= _FormatFile(filename, lines, style_config, no_local_style, - in_place, print_diff, verify, quiet, verbose) - return changed - - -def _FormatFile(filename, - lines, - style_config=None, - no_local_style=False, - in_place=False, - print_diff=False, - verify=False, - quiet=False, - verbose=False): - """Format an individual file.""" - if verbose and not quiet: - print('Reformatting %s' % filename) - - if style_config is None and not no_local_style: - style_config = file_resources.GetDefaultStyleForDir( - os.path.dirname(filename)) - - try: - reformatted_code, encoding, has_change = yapf_api.FormatFile( + changed = False + if parallel: + import multiprocessing # pylint: disable=g-import-not-at-top + import concurrent.futures # pylint: disable=g-import-not-at-top + workers = min( multiprocessing.cpu_count(), len( filenames ) ) + with concurrent.futures.ProcessPoolExecutor( workers ) as executor: + future_formats = [ + executor.submit( + _FormatFile, filename, lines, style_config, no_local_style, + in_place, print_diff, verify, quiet, verbose ) + for filename in filenames + ] + for future in concurrent.futures.as_completed( future_formats ): + changed |= future.result() + else: + for filename in filenames: + changed |= _FormatFile( + filename, lines, style_config, no_local_style, in_place, print_diff, + verify, quiet, verbose ) + return changed + + +def _FormatFile( filename, - in_place=in_place, - style_config=style_config, - lines=lines, - print_diff=print_diff, - verify=verify, - logger=logging.warning) - except errors.YapfError: - raise - except Exception as e: - raise errors.YapfError(errors.FormatErrorMsg(e)) - - if not in_place and not quiet and reformatted_code: - file_resources.WriteReformattedCode(filename, reformatted_code, encoding, - in_place) - return has_change - - -def _GetLines(line_strings): - """Parses the start and end lines from a line string like 'start-end'. + lines, + style_config = None, + no_local_style = False, + in_place = False, + print_diff = False, + verify = False, + quiet = False, + verbose = False ): + """Format an individual file.""" + if verbose and not quiet: + print( 'Reformatting %s' % filename ) + + if style_config is None and not no_local_style: + style_config = file_resources.GetDefaultStyleForDir( + os.path.dirname( filename ) ) + + try: + reformatted_code, encoding, has_change = yapf_api.FormatFile( + filename, + in_place = in_place, + style_config = style_config, + lines = lines, + print_diff = print_diff, + verify = verify, + logger = logging.warning ) + except errors.YapfError: + raise + except Exception as e: + raise errors.YapfError( errors.FormatErrorMsg( e ) ) + + if not in_place and not quiet and reformatted_code: + file_resources.WriteReformattedCode( + filename, reformatted_code, encoding, in_place ) + return has_change + + +def _GetLines( line_strings ): + """Parses the start and end lines from a line string like 'start-end'. Arguments: line_strings: (array of string) A list of strings representing a line @@ -254,114 +259,117 @@ def _GetLines(line_strings): Raises: ValueError: If the line string failed to parse or was an invalid line range. """ - lines = [] - for line_string in line_strings: - # The 'list' here is needed by Python 3. - line = list(map(int, line_string.split('-', 1))) - if line[0] < 1: - raise errors.YapfError('invalid start of line range: %r' % line) - if line[0] > line[1]: - raise errors.YapfError('end comes before start in line range: %r' % line) - lines.append(tuple(line)) - return lines + lines = [] + for line_string in line_strings: + # The 'list' here is needed by Python 3. + line = list( map( int, line_string.split( '-', 1 ) ) ) + if line[ 0 ] < 1: + raise errors.YapfError( 'invalid start of line range: %r' % line ) + if line[ 0 ] > line[ 1 ]: + raise errors.YapfError( 'end comes before start in line range: %r' % line ) + lines.append( tuple( line ) ) + return lines def _BuildParser(): - """Constructs the parser for the command line arguments. + """Constructs the parser for the command line arguments. Returns: An ArgumentParser instance for the CLI. """ - parser = argparse.ArgumentParser( - prog='yapf', description='Formatter for Python code.') - parser.add_argument( - '-v', - '--version', - action='version', - version='%(prog)s {}'.format(__version__)) - - diff_inplace_quiet_group = parser.add_mutually_exclusive_group() - diff_inplace_quiet_group.add_argument( - '-d', - '--diff', - action='store_true', - help='print the diff for the fixed source') - diff_inplace_quiet_group.add_argument( - '-i', - '--in-place', - action='store_true', - help='make changes to files in place') - diff_inplace_quiet_group.add_argument( - '-q', - '--quiet', - action='store_true', - help='output nothing and set return value') - - lines_recursive_group = parser.add_mutually_exclusive_group() - lines_recursive_group.add_argument( - '-r', - '--recursive', - action='store_true', - help='run recursively over directories') - lines_recursive_group.add_argument( - '-l', - '--lines', - metavar='START-END', - action='append', - default=None, - help='range of lines to reformat, one-based') - - parser.add_argument( - '-e', - '--exclude', - metavar='PATTERN', - action='append', - default=None, - help='patterns for files to exclude from formatting') - parser.add_argument( - '--style', - action='store', - help=('specify formatting style: either a style name (for example "pep8" ' + parser = argparse.ArgumentParser( + prog = 'yapf', description = 'Formatter for Python code.' ) + parser.add_argument( + '-v', + '--version', + action = 'version', + version = '%(prog)s {}'.format( __version__ ) ) + + diff_inplace_quiet_group = parser.add_mutually_exclusive_group() + diff_inplace_quiet_group.add_argument( + '-d', + '--diff', + action = 'store_true', + help = 'print the diff for the fixed source' ) + diff_inplace_quiet_group.add_argument( + '-i', + '--in-place', + action = 'store_true', + help = 'make changes to files in place' ) + diff_inplace_quiet_group.add_argument( + '-q', + '--quiet', + action = 'store_true', + help = 'output nothing and set return value' ) + + lines_recursive_group = parser.add_mutually_exclusive_group() + lines_recursive_group.add_argument( + '-r', + '--recursive', + action = 'store_true', + help = 'run recursively over directories' ) + lines_recursive_group.add_argument( + '-l', + '--lines', + metavar = 'START-END', + action = 'append', + default = None, + help = 'range of lines to reformat, one-based' ) + + parser.add_argument( + '-e', + '--exclude', + metavar = 'PATTERN', + action = 'append', + default = None, + help = 'patterns for files to exclude from formatting' ) + parser.add_argument( + '--style', + action = 'store', + help = ( + 'specify formatting style: either a style name (for example "pep8" ' 'or "google"), or the name of a file with style settings. The ' 'default is pep8 unless a %s or %s or %s file located in the same ' 'directory as the source or one of its parent directories ' '(for stdin, the current directory is used).' % - (style.LOCAL_STYLE, style.SETUP_CONFIG, style.PYPROJECT_TOML))) - parser.add_argument( - '--style-help', - action='store_true', - help=('show style settings and exit; this output can be ' + ( style.LOCAL_STYLE, style.SETUP_CONFIG, style.PYPROJECT_TOML ) ) ) + parser.add_argument( + '--style-help', + action = 'store_true', + help = ( + 'show style settings and exit; this output can be ' 'saved to .style.yapf to make your settings ' - 'permanent')) - parser.add_argument( - '--no-local-style', - action='store_true', - help="don't search for local style definition") - parser.add_argument('--verify', action='store_true', help=argparse.SUPPRESS) - parser.add_argument( - '-p', - '--parallel', - action='store_true', - help=('run YAPF in parallel when formatting multiple files. Requires ' - 'concurrent.futures in Python 2.X')) - parser.add_argument( - '-vv', - '--verbose', - action='store_true', - help='print out file names while processing') - - parser.add_argument( - 'files', nargs='*', help='reads from stdin when no files are specified.') - return parser - - -def run_main(): # pylint: disable=invalid-name - try: - sys.exit(main(sys.argv)) - except errors.YapfError as e: - sys.stderr.write('yapf: ' + str(e) + '\n') - sys.exit(1) + 'permanent' ) ) + parser.add_argument( + '--no-local-style', + action = 'store_true', + help = "don't search for local style definition" ) + parser.add_argument( '--verify', action = 'store_true', help = argparse.SUPPRESS ) + parser.add_argument( + '-p', + '--parallel', + action = 'store_true', + help = ( + 'run YAPF in parallel when formatting multiple files. Requires ' + 'concurrent.futures in Python 2.X' ) ) + parser.add_argument( + '-vv', + '--verbose', + action = 'store_true', + help = 'print out file names while processing' ) + + parser.add_argument( + 'files', nargs = '*', help = 'reads from stdin when no files are specified.' ) + return parser + + +def run_main(): # pylint: disable=invalid-name + try: + sys.exit( main( sys.argv ) ) + except errors.YapfError as e: + sys.stderr.write( 'yapf: ' + str( e ) + '\n' ) + sys.exit( 1 ) if __name__ == '__main__': - run_main() + run_main() diff --git a/yapf/pyparser/pyparser.py b/yapf/pyparser/pyparser.py index a8a28ebc8..b6b7c50d7 100644 --- a/yapf/pyparser/pyparser.py +++ b/yapf/pyparser/pyparser.py @@ -46,8 +46,8 @@ CONTINUATION = token.N_TOKENS -def ParseCode(unformatted_source, filename=''): - """Parse a string of Python code into logical lines. +def ParseCode( unformatted_source, filename = '' ): + """Parse a string of Python code into logical lines. This provides an alternative entry point to YAPF. @@ -61,27 +61,27 @@ def ParseCode(unformatted_source, filename=''): Raises: An exception is raised if there's an error during AST parsing. """ - if not unformatted_source.endswith(os.linesep): - unformatted_source += os.linesep + if not unformatted_source.endswith( os.linesep ): + unformatted_source += os.linesep - try: - ast_tree = ast.parse(unformatted_source, filename) - ast.fix_missing_locations(ast_tree) - readline = py3compat.StringIO(unformatted_source).readline - tokens = tokenize.generate_tokens(readline) - except Exception: - raise + try: + ast_tree = ast.parse( unformatted_source, filename ) + ast.fix_missing_locations( ast_tree ) + readline = py3compat.StringIO( unformatted_source ).readline + tokens = tokenize.generate_tokens( readline ) + except Exception: + raise - logical_lines = _CreateLogicalLines(tokens) + logical_lines = _CreateLogicalLines( tokens ) - # Process the logical lines. - split_penalty_visitor.SplitPenalty(logical_lines).visit(ast_tree) + # Process the logical lines. + split_penalty_visitor.SplitPenalty( logical_lines ).visit( ast_tree ) - return logical_lines + return logical_lines -def _CreateLogicalLines(tokens): - """Separate tokens into logical lines. +def _CreateLogicalLines( tokens ): + """Separate tokens into logical lines. Arguments: tokens: (list of tokenizer.TokenInfo) Tokens generated by tokenizer. @@ -89,57 +89,58 @@ def _CreateLogicalLines(tokens): Returns: A list of LogicalLines. """ - logical_lines = [] - cur_logical_line = [] - prev_tok = None - depth = 0 - - for tok in tokens: - tok = py3compat.TokenInfo(*tok) - if tok.type == tokenize.NEWLINE: - # End of a logical line. - logical_lines.append(logical_line.LogicalLine(depth, cur_logical_line)) - cur_logical_line = [] - prev_tok = None - elif tok.type == tokenize.INDENT: - depth += 1 - elif tok.type == tokenize.DEDENT: - depth -= 1 - elif tok.type not in {tokenize.NL, tokenize.ENDMARKER}: - if (prev_tok and prev_tok.line.rstrip().endswith('\\') and - prev_tok.start[0] < tok.start[0]): - # Insert a token for a line continuation. - ctok = py3compat.TokenInfo( - type=CONTINUATION, - string='\\', - start=(prev_tok.start[0], prev_tok.start[1] + 1), - end=(prev_tok.end[0], prev_tok.end[0] + 2), - line=prev_tok.line) - ctok.lineno = ctok.start[0] - ctok.column = ctok.start[1] - ctok.value = '\\' - cur_logical_line.append(format_token.FormatToken(ctok, 'CONTINUATION')) - tok.lineno = tok.start[0] - tok.column = tok.start[1] - tok.value = tok.string - cur_logical_line.append( - format_token.FormatToken(tok, token.tok_name[tok.type])) - prev_tok = tok - - # Link the FormatTokens in each line together to for a doubly linked list. - for line in logical_lines: - previous = line.first - bracket_stack = [previous] if previous.OpensScope() else [] - for tok in line.tokens[1:]: - tok.previous_token = previous - previous.next_token = tok - previous = tok - - # Set up the "matching_bracket" attribute. - if tok.OpensScope(): - bracket_stack.append(tok) - elif tok.ClosesScope(): - bracket_stack[-1].matching_bracket = tok - tok.matching_bracket = bracket_stack.pop() - - return logical_lines + logical_lines = [] + cur_logical_line = [] + prev_tok = None + depth = 0 + + for tok in tokens: + tok = py3compat.TokenInfo( *tok ) + if tok.type == tokenize.NEWLINE: + # End of a logical line. + logical_lines.append( logical_line.LogicalLine( depth, cur_logical_line ) ) + cur_logical_line = [] + prev_tok = None + elif tok.type == tokenize.INDENT: + depth += 1 + elif tok.type == tokenize.DEDENT: + depth -= 1 + elif tok.type not in { tokenize.NL, tokenize.ENDMARKER }: + if ( prev_tok and prev_tok.line.rstrip().endswith( '\\' ) and + prev_tok.start[ 0 ] < tok.start[ 0 ] ): + # Insert a token for a line continuation. + ctok = py3compat.TokenInfo( + type = CONTINUATION, + string = '\\', + start = ( prev_tok.start[ 0 ], prev_tok.start[ 1 ] + 1 ), + end = ( prev_tok.end[ 0 ], prev_tok.end[ 0 ] + 2 ), + line = prev_tok.line ) + ctok.lineno = ctok.start[ 0 ] + ctok.column = ctok.start[ 1 ] + ctok.value = '\\' + cur_logical_line.append( + format_token.FormatToken( ctok, 'CONTINUATION' ) ) + tok.lineno = tok.start[ 0 ] + tok.column = tok.start[ 1 ] + tok.value = tok.string + cur_logical_line.append( + format_token.FormatToken( tok, token.tok_name[ tok.type ] ) ) + prev_tok = tok + + # Link the FormatTokens in each line together to for a doubly linked list. + for line in logical_lines: + previous = line.first + bracket_stack = [ previous ] if previous.OpensScope() else [] + for tok in line.tokens[ 1 : ]: + tok.previous_token = previous + previous.next_token = tok + previous = tok + + # Set up the "matching_bracket" attribute. + if tok.OpensScope(): + bracket_stack.append( tok ) + elif tok.ClosesScope(): + bracket_stack[ -1 ].matching_bracket = tok + tok.matching_bracket = bracket_stack.pop() + + return logical_lines diff --git a/yapf/pyparser/pyparser_utils.py b/yapf/pyparser/pyparser_utils.py index 3f17b15a4..4a37b89a9 100644 --- a/yapf/pyparser/pyparser_utils.py +++ b/yapf/pyparser/pyparser_utils.py @@ -29,68 +29,68 @@ """ -def GetTokens(logical_lines, node): - """Get a list of tokens within the node's range from the logical lines.""" - start = TokenStart(node) - end = TokenEnd(node) - tokens = [] +def GetTokens( logical_lines, node ): + """Get a list of tokens within the node's range from the logical lines.""" + start = TokenStart( node ) + end = TokenEnd( node ) + tokens = [] - for line in logical_lines: - if line.start > end: - break - if line.start <= start or line.end >= end: - tokens.extend(GetTokensInSubRange(line.tokens, node)) + for line in logical_lines: + if line.start > end: + break + if line.start <= start or line.end >= end: + tokens.extend( GetTokensInSubRange( line.tokens, node ) ) - return tokens + return tokens -def GetTokensInSubRange(tokens, node): - """Get a subset of tokens representing the node.""" - start = TokenStart(node) - end = TokenEnd(node) - tokens_in_range = [] +def GetTokensInSubRange( tokens, node ): + """Get a subset of tokens representing the node.""" + start = TokenStart( node ) + end = TokenEnd( node ) + tokens_in_range = [] - for tok in tokens: - tok_range = (tok.lineno, tok.column) - if tok_range >= start and tok_range < end: - tokens_in_range.append(tok) + for tok in tokens: + tok_range = ( tok.lineno, tok.column ) + if tok_range >= start and tok_range < end: + tokens_in_range.append( tok ) - return tokens_in_range + return tokens_in_range -def GetTokenIndex(tokens, pos): - """Get the index of the token at pos.""" - for index, token in enumerate(tokens): - if (token.lineno, token.column) == pos: - return index +def GetTokenIndex( tokens, pos ): + """Get the index of the token at pos.""" + for index, token in enumerate( tokens ): + if ( token.lineno, token.column ) == pos: + return index - return None + return None -def GetNextTokenIndex(tokens, pos): - """Get the index of the next token after pos.""" - for index, token in enumerate(tokens): - if (token.lineno, token.column) >= pos: - return index +def GetNextTokenIndex( tokens, pos ): + """Get the index of the next token after pos.""" + for index, token in enumerate( tokens ): + if ( token.lineno, token.column ) >= pos: + return index - return None + return None -def GetPrevTokenIndex(tokens, pos): - """Get the index of the previous token before pos.""" - for index, token in enumerate(tokens): - if index > 0 and (token.lineno, token.column) >= pos: - return index - 1 +def GetPrevTokenIndex( tokens, pos ): + """Get the index of the previous token before pos.""" + for index, token in enumerate( tokens ): + if index > 0 and ( token.lineno, token.column ) >= pos: + return index - 1 - return None + return None -def TokenStart(node): - return (node.lineno, node.col_offset) +def TokenStart( node ): + return ( node.lineno, node.col_offset ) -def TokenEnd(node): - return (node.end_lineno, node.end_col_offset) +def TokenEnd( node ): + return ( node.end_lineno, node.end_col_offset ) ############################################################################# @@ -98,6 +98,6 @@ def TokenEnd(node): ############################################################################# -def AstDump(node): - import ast - print(ast.dump(node, include_attributes=True, indent=4)) +def AstDump( node ): + import ast + print( ast.dump( node, include_attributes = True, indent = 4 ) ) diff --git a/yapf/pyparser/split_penalty_visitor.py b/yapf/pyparser/split_penalty_visitor.py index 047b48a3d..4d05558ba 100644 --- a/yapf/pyparser/split_penalty_visitor.py +++ b/yapf/pyparser/split_penalty_visitor.py @@ -21,892 +21,896 @@ # This is a skeleton of an AST visitor. -class SplitPenalty(ast.NodeVisitor): - """Compute split penalties between tokens.""" - - def __init__(self, logical_lines): - super(SplitPenalty, self).__init__() - self.logical_lines = logical_lines - - # We never want to split before a colon or comma. - for logical_line in logical_lines: - for token in logical_line.tokens: - if token.value in frozenset({',', ':'}): - token.split_penalty = split_penalty.UNBREAKABLE - - def _GetTokens(self, node): - return pyutils.GetTokens(self.logical_lines, node) - - ############################################################################ - # Statements # - ############################################################################ - - def visit_FunctionDef(self, node): - # FunctionDef(name=Name, - # args=arguments( - # posonlyargs=[], - # args=[], - # vararg=[], - # kwonlyargs=[], - # kw_defaults=[], - # defaults=[]), - # body=[...], - # decorator_list=[Call_1, Call_2, ..., Call_n], - # keywords=[]) - tokens = self._GetTokens(node) - for decorator in node.decorator_list: - # The decorator token list begins after the '@'. The body of the decorator - # is formatted like a normal "call." - decorator_range = self._GetTokens(decorator) - # Don't split after the '@'. - decorator_range[0].split_penalty = split_penalty.UNBREAKABLE - - for token in tokens[1:]: - if token.value == '(': - break - _SetPenalty(token, split_penalty.UNBREAKABLE) - - if node.returns: - start_index = pyutils.GetTokenIndex(tokens, - pyutils.TokenStart(node.returns)) - _IncreasePenalty(tokens[start_index - 1:start_index + 1], - split_penalty.VERY_STRONGLY_CONNECTED) - end_index = pyutils.GetTokenIndex(tokens, pyutils.TokenEnd(node.returns)) - _IncreasePenalty(tokens[start_index + 1:end_index], - split_penalty.STRONGLY_CONNECTED) - - return self.generic_visit(node) - - def visit_AsyncFunctionDef(self, node): - # AsyncFunctionDef(name=Name, - # args=arguments( - # posonlyargs=[], - # args=[], - # vararg=[], - # kwonlyargs=[], - # kw_defaults=[], - # defaults=[]), - # body=[...], - # decorator_list=[Expr_1, Expr_2, ..., Expr_n], - # keywords=[]) - return self.visit_FunctionDef(node) - - def visit_ClassDef(self, node): - # ClassDef(name=Name, - # bases=[Expr_1, Expr_2, ..., Expr_n], - # keywords=[], - # body=[], - # decorator_list=[Expr_1, Expr_2, ..., Expr_m]) - for base in node.bases: - tokens = self._GetTokens(base) - _IncreasePenalty(tokens[1:], split_penalty.EXPR) - - for decorator in node.decorator_list: - # Don't split after the '@'. - decorator_range = self._GetTokens(decorator) - decorator_range[0].split_penalty = split_penalty.UNBREAKABLE - - return self.generic_visit(node) - - def visit_Return(self, node): - # Return(value=Expr) - tokens = self._GetTokens(node) - _IncreasePenalty(tokens[1:], split_penalty.EXPR) - - return self.generic_visit(node) - - def visit_Delete(self, node): - # Delete(targets=[Expr_1, Expr_2, ..., Expr_n]) - for target in node.targets: - tokens = self._GetTokens(target) - _IncreasePenalty(tokens[1:], split_penalty.EXPR) - - return self.generic_visit(node) - - def visit_Assign(self, node): - # Assign(targets=[Expr_1, Expr_2, ..., Expr_n], - # value=Expr) - tokens = self._GetTokens(node) - _IncreasePenalty(tokens[1:], split_penalty.EXPR) - - return self.generic_visit(node) - - def visit_AugAssign(self, node): - # AugAssign(target=Name, - # op=Add(), - # value=Expr) - return self.generic_visit(node) - - def visit_AnnAssign(self, node): - # AnnAssign(target=Expr, - # annotation=TypeName, - # value=Expr, - # simple=number) - return self.generic_visit(node) - - def visit_For(self, node): - # For(target=Expr, - # iter=Expr, - # body=[...], - # orelse=[...]) - return self.generic_visit(node) - - def visit_AsyncFor(self, node): - # AsyncFor(target=Expr, - # iter=Expr, - # body=[...], - # orelse=[...]) - return self.generic_visit(node) - - def visit_While(self, node): - # While(test=Expr, - # body=[...], - # orelse=[...]) - return self.generic_visit(node) - - def visit_If(self, node): - # If(test=Expr, - # body=[...], - # orelse=[...]) - return self.generic_visit(node) - - def visit_With(self, node): - # With(items=[withitem_1, withitem_2, ..., withitem_n], - # body=[...]) - return self.generic_visit(node) - - def visit_AsyncWith(self, node): - # AsyncWith(items=[withitem_1, withitem_2, ..., withitem_n], - # body=[...]) - return self.generic_visit(node) - - def visit_Match(self, node): - # Match(subject=Expr, - # cases=[ - # match_case( - # pattern=pattern, - # guard=Expr, - # body=[...]), - # ... - # ]) - return self.generic_visit(node) - - def visit_Raise(self, node): - # Raise(exc=Expr) - return self.generic_visit(node) - - def visit_Try(self, node): - # Try(body=[...], - # handlers=[ExceptHandler_1, ExceptHandler_2, ..., ExceptHandler_b], - # orelse=[...], - # finalbody=[...]) - return self.generic_visit(node) - - def visit_Assert(self, node): - # Assert(test=Expr) - return self.generic_visit(node) - - def visit_Import(self, node): - # Import(names=[ - # alias( - # name=Identifier, - # asname=Identifier), - # ... - # ]) - return self.generic_visit(node) - - def visit_ImportFrom(self, node): - # ImportFrom(module=Identifier, - # names=[ - # alias( - # name=Identifier, - # asname=Identifier), - # ... - # ], - # level=num - return self.generic_visit(node) - - def visit_Global(self, node): - # Global(names=[Identifier_1, Identifier_2, ..., Identifier_n]) - return self.generic_visit(node) - - def visit_Nonlocal(self, node): - # Nonlocal(names=[Identifier_1, Identifier_2, ..., Identifier_n]) - return self.generic_visit(node) - - def visit_Expr(self, node): - # Expr(value=Expr) - return self.generic_visit(node) - - def visit_Pass(self, node): - # Pass() - return self.generic_visit(node) - - def visit_Break(self, node): - # Break() - return self.generic_visit(node) - - def visit_Continue(self, node): - # Continue() - return self.generic_visit(node) - - ############################################################################ - # Expressions # - ############################################################################ - - def visit_BoolOp(self, node): - # BoolOp(op=And | Or, - # values=[Expr_1, Expr_2, ..., Expr_n]) - tokens = self._GetTokens(node) - _IncreasePenalty(tokens[1:], split_penalty.EXPR) - - # Lower the split penalty to allow splitting before or after the logical - # operator. - split_before_operator = style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR') - operator_indices = [ - pyutils.GetNextTokenIndex(tokens, pyutils.TokenEnd(value)) - for value in node.values[:-1] - ] - for operator_index in operator_indices: - if not split_before_operator: - operator_index += 1 - _DecreasePenalty(tokens[operator_index], split_penalty.EXPR * 2) - - return self.generic_visit(node) - - def visit_NamedExpr(self, node): - # NamedExpr(target=Name, - # value=Expr) - tokens = self._GetTokens(node) - _IncreasePenalty(tokens[1:], split_penalty.EXPR) - - return self.generic_visit(node) - - def visit_BinOp(self, node): - # BinOp(left=LExpr - # op=Add | Sub | Mult | MatMult | Div | Mod | Pow | LShift | - # RShift | BitOr | BitXor | BitAnd | FloorDiv - # right=RExpr) - tokens = self._GetTokens(node) - _IncreasePenalty(tokens[1:], split_penalty.EXPR) - - # Lower the split penalty to allow splitting before or after the arithmetic - # operator. - operator_index = pyutils.GetNextTokenIndex(tokens, - pyutils.TokenEnd(node.left)) - if not style.Get('SPLIT_BEFORE_ARITHMETIC_OPERATOR'): - operator_index += 1 - - _DecreasePenalty(tokens[operator_index], split_penalty.EXPR * 2) - - return self.generic_visit(node) - - def visit_UnaryOp(self, node): - # UnaryOp(op=Not | USub | UAdd | Invert, - # operand=Expr) - tokens = self._GetTokens(node) - _IncreasePenalty(tokens[1:], split_penalty.EXPR) - _IncreasePenalty(tokens[1], style.Get('SPLIT_PENALTY_AFTER_UNARY_OPERATOR')) - - return self.generic_visit(node) - - def visit_Lambda(self, node): - # Lambda(args=arguments( - # posonlyargs=[arg(...), arg(...), ..., arg(...)], - # args=[arg(...), arg(...), ..., arg(...)], - # kwonlyargs=[arg(...), arg(...), ..., arg(...)], - # kw_defaults=[arg(...), arg(...), ..., arg(...)], - # defaults=[arg(...), arg(...), ..., arg(...)]), - # body=Expr) - tokens = self._GetTokens(node) - _IncreasePenalty(tokens[1:], split_penalty.LAMBDA) - - if style.Get('ALLOW_MULTILINE_LAMBDAS'): - _SetPenalty(self._GetTokens(node.body), split_penalty.MULTIPLINE_LAMBDA) - - return self.generic_visit(node) - - def visit_IfExp(self, node): - # IfExp(test=TestExpr, - # body=BodyExpr, - # orelse=OrElseExpr) - tokens = self._GetTokens(node) - _IncreasePenalty(tokens[1:], split_penalty.EXPR) - - return self.generic_visit(node) - - def visit_Dict(self, node): - # Dict(keys=[Expr_1, Expr_2, ..., Expr_n], - # values=[Expr_1, Expr_2, ..., Expr_n]) - tokens = self._GetTokens(node) - - # The keys should be on a single line if at all possible. - for key in node.keys: - subrange = pyutils.GetTokensInSubRange(tokens, key) - _IncreasePenalty(subrange[1:], split_penalty.DICT_KEY_EXPR) - - for value in node.values: - subrange = pyutils.GetTokensInSubRange(tokens, value) - _IncreasePenalty(subrange[1:], split_penalty.DICT_VALUE_EXPR) - - return self.generic_visit(node) - - def visit_Set(self, node): - # Set(elts=[Expr_1, Expr_2, ..., Expr_n]) - tokens = self._GetTokens(node) - for element in node.elts: - subrange = pyutils.GetTokensInSubRange(tokens, element) - _IncreasePenalty(subrange[1:], split_penalty.EXPR) - - return self.generic_visit(node) - - def visit_ListComp(self, node): - # ListComp(elt=Expr, - # generators=[ - # comprehension( - # target=Expr, - # iter=Expr, - # ifs=[Expr_1, Expr_2, ..., Expr_n], - # is_async=0), - # ... - # ]) - tokens = self._GetTokens(node) - element = pyutils.GetTokensInSubRange(tokens, node.elt) - _IncreasePenalty(element[1:], split_penalty.EXPR) - - for comp in node.generators: - subrange = pyutils.GetTokensInSubRange(tokens, comp.iter) - _IncreasePenalty(subrange[1:], split_penalty.EXPR) - - for if_expr in comp.ifs: - subrange = pyutils.GetTokensInSubRange(tokens, if_expr) - _IncreasePenalty(subrange[1:], split_penalty.EXPR) - - return self.generic_visit(node) - - def visit_SetComp(self, node): - # SetComp(elt=Expr, - # generators=[ - # comprehension( - # target=Expr, - # iter=Expr, - # ifs=[Expr_1, Expr_2, ..., Expr_n], - # is_async=0), - # ... - # ]) - tokens = self._GetTokens(node) - element = pyutils.GetTokensInSubRange(tokens, node.elt) - _IncreasePenalty(element[1:], split_penalty.EXPR) - - for comp in node.generators: - subrange = pyutils.GetTokensInSubRange(tokens, comp.iter) - _IncreasePenalty(subrange[1:], split_penalty.EXPR) - - for if_expr in comp.ifs: - subrange = pyutils.GetTokensInSubRange(tokens, if_expr) - _IncreasePenalty(subrange[1:], split_penalty.EXPR) - - return self.generic_visit(node) - - def visit_DictComp(self, node): - # DictComp(key=KeyExpr, - # value=ValExpr, - # generators=[ - # comprehension( - # target=TargetExpr - # iter=IterExpr, - # ifs=[Expr_1, Expr_2, ..., Expr_n]), - # is_async=0)], - # ... - # ]) - tokens = self._GetTokens(node) - key = pyutils.GetTokensInSubRange(tokens, node.key) - _IncreasePenalty(key[1:], split_penalty.EXPR) - - value = pyutils.GetTokensInSubRange(tokens, node.value) - _IncreasePenalty(value[1:], split_penalty.EXPR) - - for comp in node.generators: - subrange = pyutils.GetTokensInSubRange(tokens, comp.iter) - _IncreasePenalty(subrange[1:], split_penalty.EXPR) - - for if_expr in comp.ifs: - subrange = pyutils.GetTokensInSubRange(tokens, if_expr) - _IncreasePenalty(subrange[1:], split_penalty.EXPR) - - return self.generic_visit(node) - - def visit_GeneratorExp(self, node): - # GeneratorExp(elt=Expr, - # generators=[ - # comprehension( - # target=Expr, - # iter=Expr, - # ifs=[Expr_1, Expr_2, ..., Expr_n], - # is_async=0), - # ... - # ]) - tokens = self._GetTokens(node) - element = pyutils.GetTokensInSubRange(tokens, node.elt) - _IncreasePenalty(element[1:], split_penalty.EXPR) - - for comp in node.generators: - subrange = pyutils.GetTokensInSubRange(tokens, comp.iter) - _IncreasePenalty(subrange[1:], split_penalty.EXPR) - - for if_expr in comp.ifs: - subrange = pyutils.GetTokensInSubRange(tokens, if_expr) - _IncreasePenalty(subrange[1:], split_penalty.EXPR) - - return self.generic_visit(node) - - def visit_Await(self, node): - # Await(value=Expr) - tokens = self._GetTokens(node) - _IncreasePenalty(tokens[1:], split_penalty.EXPR) - - return self.generic_visit(node) - - def visit_Yield(self, node): - # Yield(value=Expr) - tokens = self._GetTokens(node) - _IncreasePenalty(tokens[1:], split_penalty.EXPR) - - return self.generic_visit(node) - - def visit_YieldFrom(self, node): - # YieldFrom(value=Expr) - tokens = self._GetTokens(node) - _IncreasePenalty(tokens[1:], split_penalty.EXPR) - tokens[2].split_penalty = split_penalty.UNBREAKABLE - - return self.generic_visit(node) - - def visit_Compare(self, node): - # Compare(left=LExpr, - # ops=[Op_1, Op_2, ..., Op_n], - # comparators=[Expr_1, Expr_2, ..., Expr_n]) - tokens = self._GetTokens(node) - _IncreasePenalty(tokens[1:], split_penalty.EXPR) - - operator_indices = [ - pyutils.GetNextTokenIndex(tokens, pyutils.TokenEnd(node.left)) - ] + [ - pyutils.GetNextTokenIndex(tokens, pyutils.TokenEnd(comparator)) - for comparator in node.comparators[:-1] - ] - split_before = style.Get('SPLIT_BEFORE_ARITHMETIC_OPERATOR') - - for operator_index in operator_indices: - if not split_before: - operator_index += 1 - _DecreasePenalty(tokens[operator_index], split_penalty.EXPR * 2) - - return self.generic_visit(node) - - def visit_Call(self, node): - # Call(func=Expr, - # args=[Expr_1, Expr_2, ..., Expr_n], - # keywords=[ - # keyword( - # arg='d', - # value=Expr), - # ... - # ]) - tokens = self._GetTokens(node) - - # Don't never split before the opening parenthesis. - paren_index = pyutils.GetNextTokenIndex(tokens, pyutils.TokenEnd(node.func)) - _IncreasePenalty(tokens[paren_index], split_penalty.UNBREAKABLE) - - for arg in node.args: - subrange = pyutils.GetTokensInSubRange(tokens, arg) - _IncreasePenalty(subrange[1:], split_penalty.EXPR) - - return self.generic_visit(node) - - def visit_FormattedValue(self, node): - # FormattedValue(value=Expr, - # conversion=-1) - return node # Ignore formatted values. - - def visit_JoinedStr(self, node): - # JoinedStr(values=[Expr_1, Expr_2, ..., Expr_n]) - return self.generic_visit(node) - - def visit_Constant(self, node): - # Constant(value=Expr) - return self.generic_visit(node) - - def visit_Attribute(self, node): - # Attribute(value=Expr, - # attr=Identifier) - tokens = self._GetTokens(node) - split_before = style.Get('SPLIT_BEFORE_DOT') - dot_indices = pyutils.GetNextTokenIndex(tokens, - pyutils.TokenEnd(node.value)) - - if not split_before: - dot_indices += 1 - _IncreasePenalty(tokens[dot_indices], split_penalty.VERY_STRONGLY_CONNECTED) - - return self.generic_visit(node) - - def visit_Subscript(self, node): - # Subscript(value=ValueExpr, - # slice=SliceExpr) - tokens = self._GetTokens(node) - - # Don't split before the opening bracket of a subscript. - bracket_index = pyutils.GetNextTokenIndex(tokens, - pyutils.TokenEnd(node.value)) - _IncreasePenalty(tokens[bracket_index], split_penalty.UNBREAKABLE) - - return self.generic_visit(node) - - def visit_Starred(self, node): - # Starred(value=Expr) - return self.generic_visit(node) - - def visit_Name(self, node): - # Name(id=Identifier) - tokens = self._GetTokens(node) - _IncreasePenalty(tokens[1:], split_penalty.UNBREAKABLE) - - return self.generic_visit(node) - - def visit_List(self, node): - # List(elts=[Expr_1, Expr_2, ..., Expr_n]) - tokens = self._GetTokens(node) - - for element in node.elts: - subrange = pyutils.GetTokensInSubRange(tokens, element) - _IncreasePenalty(subrange[1:], split_penalty.EXPR) - _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) - - return self.generic_visit(node) - - def visit_Tuple(self, node): - # Tuple(elts=[Expr_1, Expr_2, ..., Expr_n]) - tokens = self._GetTokens(node) - - for element in node.elts: - subrange = pyutils.GetTokensInSubRange(tokens, element) - _IncreasePenalty(subrange[1:], split_penalty.EXPR) - _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) - - return self.generic_visit(node) - - def visit_Slice(self, node): - # Slice(lower=Expr, - # upper=Expr, - # step=Expr) - tokens = self._GetTokens(node) - - if hasattr(node, 'lower') and node.lower: - subrange = pyutils.GetTokensInSubRange(tokens, node.lower) - _IncreasePenalty(subrange, split_penalty.EXPR) - _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) - - if hasattr(node, 'upper') and node.upper: - colon_index = pyutils.GetPrevTokenIndex(tokens, - pyutils.TokenStart(node.upper)) - _IncreasePenalty(tokens[colon_index], split_penalty.UNBREAKABLE) - subrange = pyutils.GetTokensInSubRange(tokens, node.upper) - _IncreasePenalty(subrange, split_penalty.EXPR) - _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) - - if hasattr(node, 'step') and node.step: - colon_index = pyutils.GetPrevTokenIndex(tokens, - pyutils.TokenStart(node.step)) - _IncreasePenalty(tokens[colon_index], split_penalty.UNBREAKABLE) - subrange = pyutils.GetTokensInSubRange(tokens, node.step) - _IncreasePenalty(subrange, split_penalty.EXPR) - _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) - - return self.generic_visit(node) - - ############################################################################ - # Expression Context # - ############################################################################ - - def visit_Load(self, node): - # Load() - return self.generic_visit(node) - - def visit_Store(self, node): - # Store() - return self.generic_visit(node) - - def visit_Del(self, node): - # Del() - return self.generic_visit(node) - - ############################################################################ - # Boolean Operators # - ############################################################################ +class SplitPenalty( ast.NodeVisitor ): + """Compute split penalties between tokens.""" + + def __init__( self, logical_lines ): + super( SplitPenalty, self ).__init__() + self.logical_lines = logical_lines + + # We never want to split before a colon or comma. + for logical_line in logical_lines: + for token in logical_line.tokens: + if token.value in frozenset( { ',', ':' } ): + token.split_penalty = split_penalty.UNBREAKABLE + + def _GetTokens( self, node ): + return pyutils.GetTokens( self.logical_lines, node ) + + ############################################################################ + # Statements # + ############################################################################ + + def visit_FunctionDef( self, node ): + # FunctionDef(name=Name, + # args=arguments( + # posonlyargs=[], + # args=[], + # vararg=[], + # kwonlyargs=[], + # kw_defaults=[], + # defaults=[]), + # body=[...], + # decorator_list=[Call_1, Call_2, ..., Call_n], + # keywords=[]) + tokens = self._GetTokens( node ) + for decorator in node.decorator_list: + # The decorator token list begins after the '@'. The body of the decorator + # is formatted like a normal "call." + decorator_range = self._GetTokens( decorator ) + # Don't split after the '@'. + decorator_range[ 0 ].split_penalty = split_penalty.UNBREAKABLE + + for token in tokens[ 1 : ]: + if token.value == '(': + break + _SetPenalty( token, split_penalty.UNBREAKABLE ) + + if node.returns: + start_index = pyutils.GetTokenIndex( + tokens, pyutils.TokenStart( node.returns ) ) + _IncreasePenalty( + tokens[ start_index - 1 : start_index + 1 ], + split_penalty.VERY_STRONGLY_CONNECTED ) + end_index = pyutils.GetTokenIndex( + tokens, pyutils.TokenEnd( node.returns ) ) + _IncreasePenalty( + tokens[ start_index + 1 : end_index ], + split_penalty.STRONGLY_CONNECTED ) + + return self.generic_visit( node ) + + def visit_AsyncFunctionDef( self, node ): + # AsyncFunctionDef(name=Name, + # args=arguments( + # posonlyargs=[], + # args=[], + # vararg=[], + # kwonlyargs=[], + # kw_defaults=[], + # defaults=[]), + # body=[...], + # decorator_list=[Expr_1, Expr_2, ..., Expr_n], + # keywords=[]) + return self.visit_FunctionDef( node ) + + def visit_ClassDef( self, node ): + # ClassDef(name=Name, + # bases=[Expr_1, Expr_2, ..., Expr_n], + # keywords=[], + # body=[], + # decorator_list=[Expr_1, Expr_2, ..., Expr_m]) + for base in node.bases: + tokens = self._GetTokens( base ) + _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) + + for decorator in node.decorator_list: + # Don't split after the '@'. + decorator_range = self._GetTokens( decorator ) + decorator_range[ 0 ].split_penalty = split_penalty.UNBREAKABLE + + return self.generic_visit( node ) + + def visit_Return( self, node ): + # Return(value=Expr) + tokens = self._GetTokens( node ) + _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) + + return self.generic_visit( node ) + + def visit_Delete( self, node ): + # Delete(targets=[Expr_1, Expr_2, ..., Expr_n]) + for target in node.targets: + tokens = self._GetTokens( target ) + _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) + + return self.generic_visit( node ) + + def visit_Assign( self, node ): + # Assign(targets=[Expr_1, Expr_2, ..., Expr_n], + # value=Expr) + tokens = self._GetTokens( node ) + _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) + + return self.generic_visit( node ) + + def visit_AugAssign( self, node ): + # AugAssign(target=Name, + # op=Add(), + # value=Expr) + return self.generic_visit( node ) + + def visit_AnnAssign( self, node ): + # AnnAssign(target=Expr, + # annotation=TypeName, + # value=Expr, + # simple=number) + return self.generic_visit( node ) + + def visit_For( self, node ): + # For(target=Expr, + # iter=Expr, + # body=[...], + # orelse=[...]) + return self.generic_visit( node ) + + def visit_AsyncFor( self, node ): + # AsyncFor(target=Expr, + # iter=Expr, + # body=[...], + # orelse=[...]) + return self.generic_visit( node ) + + def visit_While( self, node ): + # While(test=Expr, + # body=[...], + # orelse=[...]) + return self.generic_visit( node ) + + def visit_If( self, node ): + # If(test=Expr, + # body=[...], + # orelse=[...]) + return self.generic_visit( node ) + + def visit_With( self, node ): + # With(items=[withitem_1, withitem_2, ..., withitem_n], + # body=[...]) + return self.generic_visit( node ) + + def visit_AsyncWith( self, node ): + # AsyncWith(items=[withitem_1, withitem_2, ..., withitem_n], + # body=[...]) + return self.generic_visit( node ) + + def visit_Match( self, node ): + # Match(subject=Expr, + # cases=[ + # match_case( + # pattern=pattern, + # guard=Expr, + # body=[...]), + # ... + # ]) + return self.generic_visit( node ) + + def visit_Raise( self, node ): + # Raise(exc=Expr) + return self.generic_visit( node ) + + def visit_Try( self, node ): + # Try(body=[...], + # handlers=[ExceptHandler_1, ExceptHandler_2, ..., ExceptHandler_b], + # orelse=[...], + # finalbody=[...]) + return self.generic_visit( node ) + + def visit_Assert( self, node ): + # Assert(test=Expr) + return self.generic_visit( node ) + + def visit_Import( self, node ): + # Import(names=[ + # alias( + # name=Identifier, + # asname=Identifier), + # ... + # ]) + return self.generic_visit( node ) + + def visit_ImportFrom( self, node ): + # ImportFrom(module=Identifier, + # names=[ + # alias( + # name=Identifier, + # asname=Identifier), + # ... + # ], + # level=num + return self.generic_visit( node ) + + def visit_Global( self, node ): + # Global(names=[Identifier_1, Identifier_2, ..., Identifier_n]) + return self.generic_visit( node ) + + def visit_Nonlocal( self, node ): + # Nonlocal(names=[Identifier_1, Identifier_2, ..., Identifier_n]) + return self.generic_visit( node ) + + def visit_Expr( self, node ): + # Expr(value=Expr) + return self.generic_visit( node ) + + def visit_Pass( self, node ): + # Pass() + return self.generic_visit( node ) + + def visit_Break( self, node ): + # Break() + return self.generic_visit( node ) + + def visit_Continue( self, node ): + # Continue() + return self.generic_visit( node ) + + ############################################################################ + # Expressions # + ############################################################################ + + def visit_BoolOp( self, node ): + # BoolOp(op=And | Or, + # values=[Expr_1, Expr_2, ..., Expr_n]) + tokens = self._GetTokens( node ) + _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) + + # Lower the split penalty to allow splitting before or after the logical + # operator. + split_before_operator = style.Get( 'SPLIT_BEFORE_LOGICAL_OPERATOR' ) + operator_indices = [ + pyutils.GetNextTokenIndex( tokens, pyutils.TokenEnd( value ) ) + for value in node.values[ :-1 ] + ] + for operator_index in operator_indices: + if not split_before_operator: + operator_index += 1 + _DecreasePenalty( tokens[ operator_index ], split_penalty.EXPR * 2 ) + + return self.generic_visit( node ) + + def visit_NamedExpr( self, node ): + # NamedExpr(target=Name, + # value=Expr) + tokens = self._GetTokens( node ) + _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) + + return self.generic_visit( node ) + + def visit_BinOp( self, node ): + # BinOp(left=LExpr + # op=Add | Sub | Mult | MatMult | Div | Mod | Pow | LShift | + # RShift | BitOr | BitXor | BitAnd | FloorDiv + # right=RExpr) + tokens = self._GetTokens( node ) + _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) + + # Lower the split penalty to allow splitting before or after the arithmetic + # operator. + operator_index = pyutils.GetNextTokenIndex( + tokens, pyutils.TokenEnd( node.left ) ) + if not style.Get( 'SPLIT_BEFORE_ARITHMETIC_OPERATOR' ): + operator_index += 1 + + _DecreasePenalty( tokens[ operator_index ], split_penalty.EXPR * 2 ) + + return self.generic_visit( node ) + + def visit_UnaryOp( self, node ): + # UnaryOp(op=Not | USub | UAdd | Invert, + # operand=Expr) + tokens = self._GetTokens( node ) + _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) + _IncreasePenalty( + tokens[ 1 ], style.Get( 'SPLIT_PENALTY_AFTER_UNARY_OPERATOR' ) ) + + return self.generic_visit( node ) + + def visit_Lambda( self, node ): + # Lambda(args=arguments( + # posonlyargs=[arg(...), arg(...), ..., arg(...)], + # args=[arg(...), arg(...), ..., arg(...)], + # kwonlyargs=[arg(...), arg(...), ..., arg(...)], + # kw_defaults=[arg(...), arg(...), ..., arg(...)], + # defaults=[arg(...), arg(...), ..., arg(...)]), + # body=Expr) + tokens = self._GetTokens( node ) + _IncreasePenalty( tokens[ 1 : ], split_penalty.LAMBDA ) + + if style.Get( 'ALLOW_MULTILINE_LAMBDAS' ): + _SetPenalty( self._GetTokens( node.body ), split_penalty.MULTIPLINE_LAMBDA ) + + return self.generic_visit( node ) + + def visit_IfExp( self, node ): + # IfExp(test=TestExpr, + # body=BodyExpr, + # orelse=OrElseExpr) + tokens = self._GetTokens( node ) + _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) + + return self.generic_visit( node ) + + def visit_Dict( self, node ): + # Dict(keys=[Expr_1, Expr_2, ..., Expr_n], + # values=[Expr_1, Expr_2, ..., Expr_n]) + tokens = self._GetTokens( node ) + + # The keys should be on a single line if at all possible. + for key in node.keys: + subrange = pyutils.GetTokensInSubRange( tokens, key ) + _IncreasePenalty( subrange[ 1 : ], split_penalty.DICT_KEY_EXPR ) + + for value in node.values: + subrange = pyutils.GetTokensInSubRange( tokens, value ) + _IncreasePenalty( subrange[ 1 : ], split_penalty.DICT_VALUE_EXPR ) + + return self.generic_visit( node ) + + def visit_Set( self, node ): + # Set(elts=[Expr_1, Expr_2, ..., Expr_n]) + tokens = self._GetTokens( node ) + for element in node.elts: + subrange = pyutils.GetTokensInSubRange( tokens, element ) + _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) + + return self.generic_visit( node ) + + def visit_ListComp( self, node ): + # ListComp(elt=Expr, + # generators=[ + # comprehension( + # target=Expr, + # iter=Expr, + # ifs=[Expr_1, Expr_2, ..., Expr_n], + # is_async=0), + # ... + # ]) + tokens = self._GetTokens( node ) + element = pyutils.GetTokensInSubRange( tokens, node.elt ) + _IncreasePenalty( element[ 1 : ], split_penalty.EXPR ) + + for comp in node.generators: + subrange = pyutils.GetTokensInSubRange( tokens, comp.iter ) + _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) + + for if_expr in comp.ifs: + subrange = pyutils.GetTokensInSubRange( tokens, if_expr ) + _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) + + return self.generic_visit( node ) + + def visit_SetComp( self, node ): + # SetComp(elt=Expr, + # generators=[ + # comprehension( + # target=Expr, + # iter=Expr, + # ifs=[Expr_1, Expr_2, ..., Expr_n], + # is_async=0), + # ... + # ]) + tokens = self._GetTokens( node ) + element = pyutils.GetTokensInSubRange( tokens, node.elt ) + _IncreasePenalty( element[ 1 : ], split_penalty.EXPR ) + + for comp in node.generators: + subrange = pyutils.GetTokensInSubRange( tokens, comp.iter ) + _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) + + for if_expr in comp.ifs: + subrange = pyutils.GetTokensInSubRange( tokens, if_expr ) + _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) + + return self.generic_visit( node ) + + def visit_DictComp( self, node ): + # DictComp(key=KeyExpr, + # value=ValExpr, + # generators=[ + # comprehension( + # target=TargetExpr + # iter=IterExpr, + # ifs=[Expr_1, Expr_2, ..., Expr_n]), + # is_async=0)], + # ... + # ]) + tokens = self._GetTokens( node ) + key = pyutils.GetTokensInSubRange( tokens, node.key ) + _IncreasePenalty( key[ 1 : ], split_penalty.EXPR ) + + value = pyutils.GetTokensInSubRange( tokens, node.value ) + _IncreasePenalty( value[ 1 : ], split_penalty.EXPR ) + + for comp in node.generators: + subrange = pyutils.GetTokensInSubRange( tokens, comp.iter ) + _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) + + for if_expr in comp.ifs: + subrange = pyutils.GetTokensInSubRange( tokens, if_expr ) + _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) + + return self.generic_visit( node ) + + def visit_GeneratorExp( self, node ): + # GeneratorExp(elt=Expr, + # generators=[ + # comprehension( + # target=Expr, + # iter=Expr, + # ifs=[Expr_1, Expr_2, ..., Expr_n], + # is_async=0), + # ... + # ]) + tokens = self._GetTokens( node ) + element = pyutils.GetTokensInSubRange( tokens, node.elt ) + _IncreasePenalty( element[ 1 : ], split_penalty.EXPR ) + + for comp in node.generators: + subrange = pyutils.GetTokensInSubRange( tokens, comp.iter ) + _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) + + for if_expr in comp.ifs: + subrange = pyutils.GetTokensInSubRange( tokens, if_expr ) + _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) + + return self.generic_visit( node ) + + def visit_Await( self, node ): + # Await(value=Expr) + tokens = self._GetTokens( node ) + _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) + + return self.generic_visit( node ) + + def visit_Yield( self, node ): + # Yield(value=Expr) + tokens = self._GetTokens( node ) + _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) + + return self.generic_visit( node ) + + def visit_YieldFrom( self, node ): + # YieldFrom(value=Expr) + tokens = self._GetTokens( node ) + _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) + tokens[ 2 ].split_penalty = split_penalty.UNBREAKABLE + + return self.generic_visit( node ) + + def visit_Compare( self, node ): + # Compare(left=LExpr, + # ops=[Op_1, Op_2, ..., Op_n], + # comparators=[Expr_1, Expr_2, ..., Expr_n]) + tokens = self._GetTokens( node ) + _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) + + operator_indices = [ + pyutils.GetNextTokenIndex( tokens, pyutils.TokenEnd( node.left ) ) + ] + [ + pyutils.GetNextTokenIndex( tokens, pyutils.TokenEnd( comparator ) ) + for comparator in node.comparators[ :-1 ] + ] + split_before = style.Get( 'SPLIT_BEFORE_ARITHMETIC_OPERATOR' ) + + for operator_index in operator_indices: + if not split_before: + operator_index += 1 + _DecreasePenalty( tokens[ operator_index ], split_penalty.EXPR * 2 ) + + return self.generic_visit( node ) + + def visit_Call( self, node ): + # Call(func=Expr, + # args=[Expr_1, Expr_2, ..., Expr_n], + # keywords=[ + # keyword( + # arg='d', + # value=Expr), + # ... + # ]) + tokens = self._GetTokens( node ) + + # Don't never split before the opening parenthesis. + paren_index = pyutils.GetNextTokenIndex( tokens, pyutils.TokenEnd( node.func ) ) + _IncreasePenalty( tokens[ paren_index ], split_penalty.UNBREAKABLE ) + + for arg in node.args: + subrange = pyutils.GetTokensInSubRange( tokens, arg ) + _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) + + return self.generic_visit( node ) + + def visit_FormattedValue( self, node ): + # FormattedValue(value=Expr, + # conversion=-1) + return node # Ignore formatted values. + + def visit_JoinedStr( self, node ): + # JoinedStr(values=[Expr_1, Expr_2, ..., Expr_n]) + return self.generic_visit( node ) + + def visit_Constant( self, node ): + # Constant(value=Expr) + return self.generic_visit( node ) + + def visit_Attribute( self, node ): + # Attribute(value=Expr, + # attr=Identifier) + tokens = self._GetTokens( node ) + split_before = style.Get( 'SPLIT_BEFORE_DOT' ) + dot_indices = pyutils.GetNextTokenIndex( + tokens, pyutils.TokenEnd( node.value ) ) + + if not split_before: + dot_indices += 1 + _IncreasePenalty( tokens[ dot_indices ], split_penalty.VERY_STRONGLY_CONNECTED ) + + return self.generic_visit( node ) + + def visit_Subscript( self, node ): + # Subscript(value=ValueExpr, + # slice=SliceExpr) + tokens = self._GetTokens( node ) + + # Don't split before the opening bracket of a subscript. + bracket_index = pyutils.GetNextTokenIndex( + tokens, pyutils.TokenEnd( node.value ) ) + _IncreasePenalty( tokens[ bracket_index ], split_penalty.UNBREAKABLE ) + + return self.generic_visit( node ) + + def visit_Starred( self, node ): + # Starred(value=Expr) + return self.generic_visit( node ) + + def visit_Name( self, node ): + # Name(id=Identifier) + tokens = self._GetTokens( node ) + _IncreasePenalty( tokens[ 1 : ], split_penalty.UNBREAKABLE ) + + return self.generic_visit( node ) + + def visit_List( self, node ): + # List(elts=[Expr_1, Expr_2, ..., Expr_n]) + tokens = self._GetTokens( node ) + + for element in node.elts: + subrange = pyutils.GetTokensInSubRange( tokens, element ) + _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) + _DecreasePenalty( subrange[ 0 ], split_penalty.EXPR // 2 ) + + return self.generic_visit( node ) + + def visit_Tuple( self, node ): + # Tuple(elts=[Expr_1, Expr_2, ..., Expr_n]) + tokens = self._GetTokens( node ) + + for element in node.elts: + subrange = pyutils.GetTokensInSubRange( tokens, element ) + _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) + _DecreasePenalty( subrange[ 0 ], split_penalty.EXPR // 2 ) + + return self.generic_visit( node ) + + def visit_Slice( self, node ): + # Slice(lower=Expr, + # upper=Expr, + # step=Expr) + tokens = self._GetTokens( node ) + + if hasattr( node, 'lower' ) and node.lower: + subrange = pyutils.GetTokensInSubRange( tokens, node.lower ) + _IncreasePenalty( subrange, split_penalty.EXPR ) + _DecreasePenalty( subrange[ 0 ], split_penalty.EXPR // 2 ) + + if hasattr( node, 'upper' ) and node.upper: + colon_index = pyutils.GetPrevTokenIndex( + tokens, pyutils.TokenStart( node.upper ) ) + _IncreasePenalty( tokens[ colon_index ], split_penalty.UNBREAKABLE ) + subrange = pyutils.GetTokensInSubRange( tokens, node.upper ) + _IncreasePenalty( subrange, split_penalty.EXPR ) + _DecreasePenalty( subrange[ 0 ], split_penalty.EXPR // 2 ) + + if hasattr( node, 'step' ) and node.step: + colon_index = pyutils.GetPrevTokenIndex( + tokens, pyutils.TokenStart( node.step ) ) + _IncreasePenalty( tokens[ colon_index ], split_penalty.UNBREAKABLE ) + subrange = pyutils.GetTokensInSubRange( tokens, node.step ) + _IncreasePenalty( subrange, split_penalty.EXPR ) + _DecreasePenalty( subrange[ 0 ], split_penalty.EXPR // 2 ) + + return self.generic_visit( node ) + + ############################################################################ + # Expression Context # + ############################################################################ + + def visit_Load( self, node ): + # Load() + return self.generic_visit( node ) + + def visit_Store( self, node ): + # Store() + return self.generic_visit( node ) + + def visit_Del( self, node ): + # Del() + return self.generic_visit( node ) + + ############################################################################ + # Boolean Operators # + ############################################################################ - def visit_And(self, node): - # And() - return self.generic_visit(node) + def visit_And( self, node ): + # And() + return self.generic_visit( node ) - def visit_Or(self, node): - # Or() - return self.generic_visit(node) - - ############################################################################ - # Binary Operators # - ############################################################################ - - def visit_Add(self, node): - # Add() - return self.generic_visit(node) + def visit_Or( self, node ): + # Or() + return self.generic_visit( node ) + + ############################################################################ + # Binary Operators # + ############################################################################ + + def visit_Add( self, node ): + # Add() + return self.generic_visit( node ) - def visit_Sub(self, node): - # Sub() - return self.generic_visit(node) - - def visit_Mult(self, node): - # Mult() - return self.generic_visit(node) - - def visit_MatMult(self, node): - # MatMult() - return self.generic_visit(node) - - def visit_Div(self, node): - # Div() - return self.generic_visit(node) - - def visit_Mod(self, node): - # Mod() - return self.generic_visit(node) - - def visit_Pow(self, node): - # Pow() - return self.generic_visit(node) - - def visit_LShift(self, node): - # LShift() - return self.generic_visit(node) - - def visit_RShift(self, node): - # RShift() - return self.generic_visit(node) - - def visit_BitOr(self, node): - # BitOr() - return self.generic_visit(node) - - def visit_BitXor(self, node): - # BitXor() - return self.generic_visit(node) - - def visit_BitAnd(self, node): - # BitAnd() - return self.generic_visit(node) - - def visit_FloorDiv(self, node): - # FloorDiv() - return self.generic_visit(node) - - ############################################################################ - # Unary Operators # - ############################################################################ - - def visit_Invert(self, node): - # Invert() - return self.generic_visit(node) - - def visit_Not(self, node): - # Not() - return self.generic_visit(node) - - def visit_UAdd(self, node): - # UAdd() - return self.generic_visit(node) - - def visit_USub(self, node): - # USub() - return self.generic_visit(node) - - ############################################################################ - # Comparison Operators # - ############################################################################ - - def visit_Eq(self, node): - # Eq() - return self.generic_visit(node) - - def visit_NotEq(self, node): - # NotEq() - return self.generic_visit(node) - - def visit_Lt(self, node): - # Lt() - return self.generic_visit(node) - - def visit_LtE(self, node): - # LtE() - return self.generic_visit(node) - - def visit_Gt(self, node): - # Gt() - return self.generic_visit(node) - - def visit_GtE(self, node): - # GtE() - return self.generic_visit(node) - - def visit_Is(self, node): - # Is() - return self.generic_visit(node) - - def visit_IsNot(self, node): - # IsNot() - return self.generic_visit(node) - - def visit_In(self, node): - # In() - return self.generic_visit(node) - - def visit_NotIn(self, node): - # NotIn() - return self.generic_visit(node) - - ############################################################################ - # Exception Handler # - ############################################################################ - - def visit_ExceptionHandler(self, node): - # ExceptHandler(type=Expr, - # name=Identifier, - # body=[...]) - return self.generic_visit(node) - - ############################################################################ - # Matching Patterns # - ############################################################################ - - def visit_MatchValue(self, node): - # MatchValue(value=Expr) - return self.generic_visit(node) - - def visit_MatchSingleton(self, node): - # MatchSingleton(value=Constant) - return self.generic_visit(node) - - def visit_MatchSequence(self, node): - # MatchSequence(patterns=[pattern_1, pattern_2, ..., pattern_n]) - return self.generic_visit(node) - - def visit_MatchMapping(self, node): - # MatchMapping(keys=[Expr_1, Expr_2, ..., Expr_n], - # patterns=[pattern_1, pattern_2, ..., pattern_m], - # rest=Identifier) - return self.generic_visit(node) - - def visit_MatchClass(self, node): - # MatchClass(cls=Expr, - # patterns=[pattern_1, pattern_2, ...], - # kwd_attrs=[Identifier_1, Identifier_2, ...], - # kwd_patterns=[pattern_1, pattern_2, ...]) - return self.generic_visit(node) - - def visit_MatchStar(self, node): - # MatchStar(name=Identifier) - return self.generic_visit(node) - - def visit_MatchAs(self, node): - # MatchAs(pattern=pattern, - # name=Identifier) - return self.generic_visit(node) - - def visit_MatchOr(self, node): - # MatchOr(patterns=[pattern_1, pattern_2, ...]) - return self.generic_visit(node) - - ############################################################################ - # Type Ignore # - ############################################################################ - - def visit_TypeIgnore(self, node): - # TypeIgnore(tag=string) - return self.generic_visit(node) - - ############################################################################ - # Miscellaneous # - ############################################################################ - - def visit_comprehension(self, node): - # comprehension(target=Expr, - # iter=Expr, - # ifs=[Expr_1, Expr_2, ..., Expr_n], - # is_async=0) - return self.generic_visit(node) - - def visit_arguments(self, node): - # arguments(posonlyargs=[arg_1, arg_2, ..., arg_a], - # args=[arg_1, arg_2, ..., arg_b], - # vararg=arg, - # kwonlyargs=[arg_1, arg_2, ..., arg_c], - # kw_defaults=[arg_1, arg_2, ..., arg_d], - # kwarg=arg, - # defaults=[Expr_1, Expr_2, ..., Expr_n]) - return self.generic_visit(node) - - def visit_arg(self, node): - # arg(arg=Identifier, - # annotation=Expr, - # type_comment='') - tokens = self._GetTokens(node) - - # Process any annotations. - if hasattr(node, 'annotation') and node.annotation: - annotation = node.annotation - subrange = pyutils.GetTokensInSubRange(tokens, annotation) - _IncreasePenalty(subrange, split_penalty.ANNOTATION) - - return self.generic_visit(node) - - def visit_keyword(self, node): - # keyword(arg=Identifier, - # value=Expr) - return self.generic_visit(node) - - def visit_alias(self, node): - # alias(name=Identifier, - # asname=Identifier) - return self.generic_visit(node) - - def visit_withitem(self, node): - # withitem(context_expr=Expr, - # optional_vars=Expr) - return self.generic_visit(node) - - def visit_match_case(self, node): - # match_case(pattern=pattern, - # guard=Expr, - # body=[...]) - return self.generic_visit(node) - - -def _IncreasePenalty(tokens, amt): - if not isinstance(tokens, list): - tokens = [tokens] - for token in tokens: - token.split_penalty += amt - - -def _DecreasePenalty(tokens, amt): - if not isinstance(tokens, list): - tokens = [tokens] - for token in tokens: - token.split_penalty -= amt - - -def _SetPenalty(tokens, amt): - if not isinstance(tokens, list): - tokens = [tokens] - for token in tokens: - token.split_penalty = amt + def visit_Sub( self, node ): + # Sub() + return self.generic_visit( node ) + + def visit_Mult( self, node ): + # Mult() + return self.generic_visit( node ) + + def visit_MatMult( self, node ): + # MatMult() + return self.generic_visit( node ) + + def visit_Div( self, node ): + # Div() + return self.generic_visit( node ) + + def visit_Mod( self, node ): + # Mod() + return self.generic_visit( node ) + + def visit_Pow( self, node ): + # Pow() + return self.generic_visit( node ) + + def visit_LShift( self, node ): + # LShift() + return self.generic_visit( node ) + + def visit_RShift( self, node ): + # RShift() + return self.generic_visit( node ) + + def visit_BitOr( self, node ): + # BitOr() + return self.generic_visit( node ) + + def visit_BitXor( self, node ): + # BitXor() + return self.generic_visit( node ) + + def visit_BitAnd( self, node ): + # BitAnd() + return self.generic_visit( node ) + + def visit_FloorDiv( self, node ): + # FloorDiv() + return self.generic_visit( node ) + + ############################################################################ + # Unary Operators # + ############################################################################ + + def visit_Invert( self, node ): + # Invert() + return self.generic_visit( node ) + + def visit_Not( self, node ): + # Not() + return self.generic_visit( node ) + + def visit_UAdd( self, node ): + # UAdd() + return self.generic_visit( node ) + + def visit_USub( self, node ): + # USub() + return self.generic_visit( node ) + + ############################################################################ + # Comparison Operators # + ############################################################################ + + def visit_Eq( self, node ): + # Eq() + return self.generic_visit( node ) + + def visit_NotEq( self, node ): + # NotEq() + return self.generic_visit( node ) + + def visit_Lt( self, node ): + # Lt() + return self.generic_visit( node ) + + def visit_LtE( self, node ): + # LtE() + return self.generic_visit( node ) + + def visit_Gt( self, node ): + # Gt() + return self.generic_visit( node ) + + def visit_GtE( self, node ): + # GtE() + return self.generic_visit( node ) + + def visit_Is( self, node ): + # Is() + return self.generic_visit( node ) + + def visit_IsNot( self, node ): + # IsNot() + return self.generic_visit( node ) + + def visit_In( self, node ): + # In() + return self.generic_visit( node ) + + def visit_NotIn( self, node ): + # NotIn() + return self.generic_visit( node ) + + ############################################################################ + # Exception Handler # + ############################################################################ + + def visit_ExceptionHandler( self, node ): + # ExceptHandler(type=Expr, + # name=Identifier, + # body=[...]) + return self.generic_visit( node ) + + ############################################################################ + # Matching Patterns # + ############################################################################ + + def visit_MatchValue( self, node ): + # MatchValue(value=Expr) + return self.generic_visit( node ) + + def visit_MatchSingleton( self, node ): + # MatchSingleton(value=Constant) + return self.generic_visit( node ) + + def visit_MatchSequence( self, node ): + # MatchSequence(patterns=[pattern_1, pattern_2, ..., pattern_n]) + return self.generic_visit( node ) + + def visit_MatchMapping( self, node ): + # MatchMapping(keys=[Expr_1, Expr_2, ..., Expr_n], + # patterns=[pattern_1, pattern_2, ..., pattern_m], + # rest=Identifier) + return self.generic_visit( node ) + + def visit_MatchClass( self, node ): + # MatchClass(cls=Expr, + # patterns=[pattern_1, pattern_2, ...], + # kwd_attrs=[Identifier_1, Identifier_2, ...], + # kwd_patterns=[pattern_1, pattern_2, ...]) + return self.generic_visit( node ) + + def visit_MatchStar( self, node ): + # MatchStar(name=Identifier) + return self.generic_visit( node ) + + def visit_MatchAs( self, node ): + # MatchAs(pattern=pattern, + # name=Identifier) + return self.generic_visit( node ) + + def visit_MatchOr( self, node ): + # MatchOr(patterns=[pattern_1, pattern_2, ...]) + return self.generic_visit( node ) + + ############################################################################ + # Type Ignore # + ############################################################################ + + def visit_TypeIgnore( self, node ): + # TypeIgnore(tag=string) + return self.generic_visit( node ) + + ############################################################################ + # Miscellaneous # + ############################################################################ + + def visit_comprehension( self, node ): + # comprehension(target=Expr, + # iter=Expr, + # ifs=[Expr_1, Expr_2, ..., Expr_n], + # is_async=0) + return self.generic_visit( node ) + + def visit_arguments( self, node ): + # arguments(posonlyargs=[arg_1, arg_2, ..., arg_a], + # args=[arg_1, arg_2, ..., arg_b], + # vararg=arg, + # kwonlyargs=[arg_1, arg_2, ..., arg_c], + # kw_defaults=[arg_1, arg_2, ..., arg_d], + # kwarg=arg, + # defaults=[Expr_1, Expr_2, ..., Expr_n]) + return self.generic_visit( node ) + + def visit_arg( self, node ): + # arg(arg=Identifier, + # annotation=Expr, + # type_comment='') + tokens = self._GetTokens( node ) + + # Process any annotations. + if hasattr( node, 'annotation' ) and node.annotation: + annotation = node.annotation + subrange = pyutils.GetTokensInSubRange( tokens, annotation ) + _IncreasePenalty( subrange, split_penalty.ANNOTATION ) + + return self.generic_visit( node ) + + def visit_keyword( self, node ): + # keyword(arg=Identifier, + # value=Expr) + return self.generic_visit( node ) + + def visit_alias( self, node ): + # alias(name=Identifier, + # asname=Identifier) + return self.generic_visit( node ) + + def visit_withitem( self, node ): + # withitem(context_expr=Expr, + # optional_vars=Expr) + return self.generic_visit( node ) + + def visit_match_case( self, node ): + # match_case(pattern=pattern, + # guard=Expr, + # body=[...]) + return self.generic_visit( node ) + + +def _IncreasePenalty( tokens, amt ): + if not isinstance( tokens, list ): + tokens = [ tokens ] + for token in tokens: + token.split_penalty += amt + + +def _DecreasePenalty( tokens, amt ): + if not isinstance( tokens, list ): + tokens = [ tokens ] + for token in tokens: + token.split_penalty -= amt + + +def _SetPenalty( tokens, amt ): + if not isinstance( tokens, list ): + tokens = [ tokens ] + for token in tokens: + token.split_penalty = amt diff --git a/yapf/pytree/blank_line_calculator.py b/yapf/pytree/blank_line_calculator.py index 9d218bf97..141306e07 100644 --- a/yapf/pytree/blank_line_calculator.py +++ b/yapf/pytree/blank_line_calculator.py @@ -29,84 +29,84 @@ from yapf.yapflib import py3compat from yapf.yapflib import style -_NO_BLANK_LINES = 1 -_ONE_BLANK_LINE = 2 +_NO_BLANK_LINES = 1 +_ONE_BLANK_LINE = 2 _TWO_BLANK_LINES = 3 -_PYTHON_STATEMENTS = frozenset({ - 'small_stmt', 'expr_stmt', 'print_stmt', 'del_stmt', 'pass_stmt', - 'break_stmt', 'continue_stmt', 'return_stmt', 'raise_stmt', 'yield_stmt', - 'import_stmt', 'global_stmt', 'exec_stmt', 'assert_stmt', 'if_stmt', - 'while_stmt', 'for_stmt', 'try_stmt', 'with_stmt', 'nonlocal_stmt', - 'async_stmt', 'simple_stmt' -}) +_PYTHON_STATEMENTS = frozenset( + { + 'small_stmt', 'expr_stmt', 'print_stmt', 'del_stmt', 'pass_stmt', 'break_stmt', + 'continue_stmt', 'return_stmt', 'raise_stmt', 'yield_stmt', 'import_stmt', + 'global_stmt', 'exec_stmt', 'assert_stmt', 'if_stmt', 'while_stmt', 'for_stmt', + 'try_stmt', 'with_stmt', 'nonlocal_stmt', 'async_stmt', 'simple_stmt' + } ) -def CalculateBlankLines(tree): - """Run the blank line calculator visitor over the tree. +def CalculateBlankLines( tree ): + """Run the blank line calculator visitor over the tree. This modifies the tree in place. Arguments: tree: the top-level pytree node to annotate with subtypes. """ - blank_line_calculator = _BlankLineCalculator() - blank_line_calculator.Visit(tree) - - -class _BlankLineCalculator(pytree_visitor.PyTreeVisitor): - """_BlankLineCalculator - see file-level docstring for a description.""" - - def __init__(self): - self.class_level = 0 - self.function_level = 0 - self.last_comment_lineno = 0 - self.last_was_decorator = False - self.last_was_class_or_function = False - - def Visit_simple_stmt(self, node): # pylint: disable=invalid-name - self.DefaultNodeVisit(node) - if node.children[0].type == grammar_token.COMMENT: - self.last_comment_lineno = node.children[0].lineno - - def Visit_decorator(self, node): # pylint: disable=invalid-name - if (self.last_comment_lineno and - self.last_comment_lineno == node.children[0].lineno - 1): - _SetNumNewlines(node.children[0], _NO_BLANK_LINES) - else: - _SetNumNewlines(node.children[0], self._GetNumNewlines(node)) - for child in node.children: - self.Visit(child) - self.last_was_decorator = True - - def Visit_classdef(self, node): # pylint: disable=invalid-name - self.last_was_class_or_function = False - index = self._SetBlankLinesBetweenCommentAndClassFunc(node) - self.last_was_decorator = False - self.class_level += 1 - for child in node.children[index:]: - self.Visit(child) - self.class_level -= 1 - self.last_was_class_or_function = True - - def Visit_funcdef(self, node): # pylint: disable=invalid-name - self.last_was_class_or_function = False - index = self._SetBlankLinesBetweenCommentAndClassFunc(node) - if _AsyncFunction(node): - index = self._SetBlankLinesBetweenCommentAndClassFunc( - node.prev_sibling.parent) - _SetNumNewlines(node.children[0], None) - else: - index = self._SetBlankLinesBetweenCommentAndClassFunc(node) - self.last_was_decorator = False - self.function_level += 1 - for child in node.children[index:]: - self.Visit(child) - self.function_level -= 1 - self.last_was_class_or_function = True - - def DefaultNodeVisit(self, node): - """Override the default visitor for Node. + blank_line_calculator = _BlankLineCalculator() + blank_line_calculator.Visit( tree ) + + +class _BlankLineCalculator( pytree_visitor.PyTreeVisitor ): + """_BlankLineCalculator - see file-level docstring for a description.""" + + def __init__( self ): + self.class_level = 0 + self.function_level = 0 + self.last_comment_lineno = 0 + self.last_was_decorator = False + self.last_was_class_or_function = False + + def Visit_simple_stmt( self, node ): # pylint: disable=invalid-name + self.DefaultNodeVisit( node ) + if node.children[ 0 ].type == grammar_token.COMMENT: + self.last_comment_lineno = node.children[ 0 ].lineno + + def Visit_decorator( self, node ): # pylint: disable=invalid-name + if ( self.last_comment_lineno and + self.last_comment_lineno == node.children[ 0 ].lineno - 1 ): + _SetNumNewlines( node.children[ 0 ], _NO_BLANK_LINES ) + else: + _SetNumNewlines( node.children[ 0 ], self._GetNumNewlines( node ) ) + for child in node.children: + self.Visit( child ) + self.last_was_decorator = True + + def Visit_classdef( self, node ): # pylint: disable=invalid-name + self.last_was_class_or_function = False + index = self._SetBlankLinesBetweenCommentAndClassFunc( node ) + self.last_was_decorator = False + self.class_level += 1 + for child in node.children[ index : ]: + self.Visit( child ) + self.class_level -= 1 + self.last_was_class_or_function = True + + def Visit_funcdef( self, node ): # pylint: disable=invalid-name + self.last_was_class_or_function = False + index = self._SetBlankLinesBetweenCommentAndClassFunc( node ) + if _AsyncFunction( node ): + index = self._SetBlankLinesBetweenCommentAndClassFunc( + node.prev_sibling.parent ) + _SetNumNewlines( node.children[ 0 ], None ) + else: + index = self._SetBlankLinesBetweenCommentAndClassFunc( node ) + self.last_was_decorator = False + self.function_level += 1 + for child in node.children[ index : ]: + self.Visit( child ) + self.function_level -= 1 + self.last_was_class_or_function = True + + def DefaultNodeVisit( self, node ): + """Override the default visitor for Node. This will set the blank lines required if the last entity was a class or function. @@ -114,15 +114,15 @@ def DefaultNodeVisit(self, node): Arguments: node: (pytree.Node) The node to visit. """ - if self.last_was_class_or_function: - if pytree_utils.NodeName(node) in _PYTHON_STATEMENTS: - leaf = pytree_utils.FirstLeafNode(node) - _SetNumNewlines(leaf, self._GetNumNewlines(leaf)) - self.last_was_class_or_function = False - super(_BlankLineCalculator, self).DefaultNodeVisit(node) + if self.last_was_class_or_function: + if pytree_utils.NodeName( node ) in _PYTHON_STATEMENTS: + leaf = pytree_utils.FirstLeafNode( node ) + _SetNumNewlines( leaf, self._GetNumNewlines( leaf ) ) + self.last_was_class_or_function = False + super( _BlankLineCalculator, self ).DefaultNodeVisit( node ) - def _SetBlankLinesBetweenCommentAndClassFunc(self, node): - """Set the number of blanks between a comment and class or func definition. + def _SetBlankLinesBetweenCommentAndClassFunc( self, node ): + """Set the number of blanks between a comment and class or func definition. Class and function definitions have leading comments as children of the classdef and functdef nodes. @@ -133,47 +133,50 @@ def _SetBlankLinesBetweenCommentAndClassFunc(self, node): Returns: The index of the first child past the comment nodes. """ - index = 0 - while pytree_utils.IsCommentStatement(node.children[index]): - # Standalone comments are wrapped in a simple_stmt node with the comment - # node as its only child. - self.Visit(node.children[index].children[0]) - if not self.last_was_decorator: - _SetNumNewlines(node.children[index].children[0], _ONE_BLANK_LINE) - index += 1 - if (index and node.children[index].lineno - 1 - == node.children[index - 1].children[0].lineno): - _SetNumNewlines(node.children[index], _NO_BLANK_LINES) - else: - if self.last_comment_lineno + 1 == node.children[index].lineno: - num_newlines = _NO_BLANK_LINES - else: - num_newlines = self._GetNumNewlines(node) - _SetNumNewlines(node.children[index], num_newlines) - return index - - def _GetNumNewlines(self, node): - if self.last_was_decorator: - return _NO_BLANK_LINES - elif self._IsTopLevel(node): - return 1 + style.Get('BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION') - return _ONE_BLANK_LINE - - def _IsTopLevel(self, node): - return (not (self.class_level or self.function_level) and - _StartsInZerothColumn(node)) - - -def _SetNumNewlines(node, num_newlines): - pytree_utils.SetNodeAnnotation(node, pytree_utils.Annotation.NEWLINES, - num_newlines) - - -def _StartsInZerothColumn(node): - return (pytree_utils.FirstLeafNode(node).column == 0 or - (_AsyncFunction(node) and node.prev_sibling.column == 0)) - - -def _AsyncFunction(node): - return (py3compat.PY3 and node.prev_sibling and - node.prev_sibling.type == grammar_token.ASYNC) + index = 0 + while pytree_utils.IsCommentStatement( node.children[ index ] ): + # Standalone comments are wrapped in a simple_stmt node with the comment + # node as its only child. + self.Visit( node.children[ index ].children[ 0 ] ) + if not self.last_was_decorator: + _SetNumNewlines( node.children[ index ].children[ 0 ], _ONE_BLANK_LINE ) + index += 1 + if ( index and node.children[ index ].lineno - 1 + == node.children[ index - 1 ].children[ 0 ].lineno ): + _SetNumNewlines( node.children[ index ], _NO_BLANK_LINES ) + else: + if self.last_comment_lineno + 1 == node.children[ index ].lineno: + num_newlines = _NO_BLANK_LINES + else: + num_newlines = self._GetNumNewlines( node ) + _SetNumNewlines( node.children[ index ], num_newlines ) + return index + + def _GetNumNewlines( self, node ): + if self.last_was_decorator: + return _NO_BLANK_LINES + elif self._IsTopLevel( node ): + return 1 + style.Get( 'BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION' ) + return _ONE_BLANK_LINE + + def _IsTopLevel( self, node ): + return ( + not ( self.class_level or self.function_level ) and + _StartsInZerothColumn( node ) ) + + +def _SetNumNewlines( node, num_newlines ): + pytree_utils.SetNodeAnnotation( + node, pytree_utils.Annotation.NEWLINES, num_newlines ) + + +def _StartsInZerothColumn( node ): + return ( + pytree_utils.FirstLeafNode( node ).column == 0 or + ( _AsyncFunction( node ) and node.prev_sibling.column == 0 ) ) + + +def _AsyncFunction( node ): + return ( + py3compat.PY3 and node.prev_sibling and + node.prev_sibling.type == grammar_token.ASYNC ) diff --git a/yapf/pytree/comment_splicer.py b/yapf/pytree/comment_splicer.py index ae5ffe66f..33706ae47 100644 --- a/yapf/pytree/comment_splicer.py +++ b/yapf/pytree/comment_splicer.py @@ -28,8 +28,8 @@ from yapf.pytree import pytree_utils -def SpliceComments(tree): - """Given a pytree, splice comments into nodes of their own right. +def SpliceComments( tree ): + """Given a pytree, splice comments into nodes of their own right. Extract comments from the prefixes where they are housed after parsing. The prefixes that previously housed the comments become empty. @@ -38,176 +38,189 @@ def SpliceComments(tree): tree: a pytree.Node - the tree to work on. The tree is modified by this function. """ - # The previous leaf node encountered in the traversal. - # This is a list because Python 2.x doesn't have 'nonlocal' :) - prev_leaf = [None] - _AnnotateIndents(tree) - - def _VisitNodeRec(node): - """Recursively visit each node to splice comments into the AST.""" - # This loop may insert into node.children, so we'll iterate over a copy. - for child in node.children[:]: - if isinstance(child, pytree.Node): - # Nodes don't have prefixes. - _VisitNodeRec(child) - else: - if child.prefix.lstrip().startswith('#'): - # We have a comment prefix in this child, so splicing is needed. - comment_prefix = child.prefix - comment_lineno = child.lineno - comment_prefix.count('\n') - comment_column = child.column - - # Remember the leading indentation of this prefix and clear it. - # Mopping up the prefix is important because we may go over this same - # child in the next iteration... - child_prefix = child.prefix.lstrip('\n') - prefix_indent = child_prefix[:child_prefix.find('#')] - if '\n' in prefix_indent: - prefix_indent = prefix_indent[prefix_indent.rfind('\n') + 1:] - child.prefix = '' - - if child.type == token.NEWLINE: - # If the prefix was on a NEWLINE leaf, it's part of the line so it - # will be inserted after the previously encountered leaf. - # We can't just insert it before the NEWLINE node, because as a - # result of the way pytrees are organized, this node can be under - # an inappropriate parent. - comment_column -= len(comment_prefix.lstrip()) - pytree_utils.InsertNodesAfter( - _CreateCommentsFromPrefix( - comment_prefix, - comment_lineno, - comment_column, - standalone=False), prev_leaf[0]) - elif child.type == token.DEDENT: - # Comment prefixes on DEDENT nodes also deserve special treatment, - # because their final placement depends on their prefix. - # We'll look for an ancestor of this child with a matching - # indentation, and insert the comment before it if the ancestor is - # on a DEDENT node and after it otherwise. - # - # lib2to3 places comments that should be separated into the same - # DEDENT node. For example, "comment 1" and "comment 2" will be - # combined. - # - # def _(): - # for x in y: - # pass - # # comment 1 - # - # # comment 2 - # pass - # - # In this case, we need to split them up ourselves. - - # Split into groups of comments at decreasing levels of indentation - comment_groups = [] - comment_column = None - for cmt in comment_prefix.split('\n'): - col = cmt.find('#') - if col < 0: - if comment_column is None: - # Skip empty lines at the top of the first comment group - comment_lineno += 1 - continue - elif comment_column is None or col < comment_column: - comment_column = col - comment_indent = cmt[:comment_column] - comment_groups.append((comment_column, comment_indent, [])) - comment_groups[-1][-1].append(cmt) - - # Insert a node for each group - for comment_column, comment_indent, comment_group in comment_groups: - ancestor_at_indent = _FindAncestorAtIndent(child, comment_indent) - if ancestor_at_indent.type == token.DEDENT: - InsertNodes = pytree_utils.InsertNodesBefore # pylint: disable=invalid-name # noqa - else: - InsertNodes = pytree_utils.InsertNodesAfter # pylint: disable=invalid-name # noqa - InsertNodes( - _CreateCommentsFromPrefix( - '\n'.join(comment_group) + '\n', - comment_lineno, - comment_column, - standalone=True), ancestor_at_indent) - comment_lineno += len(comment_group) - else: - # Otherwise there are two cases. - # - # 1. The comment is on its own line - # 2. The comment is part of an expression. - # - # Unfortunately, it's fairly difficult to distinguish between the - # two in lib2to3 trees. The algorithm here is to determine whether - # child is the first leaf in the statement it belongs to. If it is, - # then the comment (which is a prefix) belongs on a separate line. - # If it is not, it means the comment is buried deep in the statement - # and is part of some expression. - stmt_parent = _FindStmtParent(child) - - for leaf_in_parent in stmt_parent.leaves(): - if leaf_in_parent.type == token.NEWLINE: - continue - elif id(leaf_in_parent) == id(child): - # This comment stands on its own line, and it has to be inserted - # into the appropriate parent. We'll have to find a suitable - # parent to insert into. See comments above - # _STANDALONE_LINE_NODES for more details. - node_with_line_parent = _FindNodeWithStandaloneLineParent(child) - - if pytree_utils.NodeName( - node_with_line_parent.parent) in {'funcdef', 'classdef'}: - # Keep a comment that's not attached to a function or class - # next to the object it is attached to. - comment_end = ( - comment_lineno + comment_prefix.rstrip('\n').count('\n')) - if comment_end < node_with_line_parent.lineno - 1: - node_with_line_parent = node_with_line_parent.parent - - pytree_utils.InsertNodesBefore( - _CreateCommentsFromPrefix( - comment_prefix, comment_lineno, 0, standalone=True), - node_with_line_parent) - break - else: - if comment_lineno == prev_leaf[0].lineno: - comment_lines = comment_prefix.splitlines() - value = comment_lines[0].lstrip() - if value.rstrip('\n'): - comment_column = prev_leaf[0].column - comment_column += len(prev_leaf[0].value) - comment_column += ( - len(comment_lines[0]) - len(comment_lines[0].lstrip())) - comment_leaf = pytree.Leaf( - type=token.COMMENT, - value=value.rstrip('\n'), - context=('', (comment_lineno, comment_column))) - pytree_utils.InsertNodesAfter([comment_leaf], prev_leaf[0]) - comment_prefix = '\n'.join(comment_lines[1:]) - comment_lineno += 1 - - rindex = (0 if '\n' not in comment_prefix.rstrip() else - comment_prefix.rstrip().rindex('\n') + 1) - comment_column = ( - len(comment_prefix[rindex:]) - - len(comment_prefix[rindex:].lstrip())) - comments = _CreateCommentsFromPrefix( - comment_prefix, - comment_lineno, - comment_column, - standalone=False) - pytree_utils.InsertNodesBefore(comments, child) - break - - prev_leaf[0] = child - - _VisitNodeRec(tree) - - -def _CreateCommentsFromPrefix(comment_prefix, - comment_lineno, - comment_column, - standalone=False): - """Create pytree nodes to represent the given comment prefix. + # The previous leaf node encountered in the traversal. + # This is a list because Python 2.x doesn't have 'nonlocal' :) + prev_leaf = [ None ] + _AnnotateIndents( tree ) + + def _VisitNodeRec( node ): + """Recursively visit each node to splice comments into the AST.""" + # This loop may insert into node.children, so we'll iterate over a copy. + for child in node.children[ : ]: + if isinstance( child, pytree.Node ): + # Nodes don't have prefixes. + _VisitNodeRec( child ) + else: + if child.prefix.lstrip().startswith( '#' ): + # We have a comment prefix in this child, so splicing is needed. + comment_prefix = child.prefix + comment_lineno = child.lineno - comment_prefix.count( '\n' ) + comment_column = child.column + + # Remember the leading indentation of this prefix and clear it. + # Mopping up the prefix is important because we may go over this same + # child in the next iteration... + child_prefix = child.prefix.lstrip( '\n' ) + prefix_indent = child_prefix[ : child_prefix.find( '#' ) ] + if '\n' in prefix_indent: + prefix_indent = prefix_indent[ prefix_indent.rfind( '\n' ) + + 1 : ] + child.prefix = '' + + if child.type == token.NEWLINE: + # If the prefix was on a NEWLINE leaf, it's part of the line so it + # will be inserted after the previously encountered leaf. + # We can't just insert it before the NEWLINE node, because as a + # result of the way pytrees are organized, this node can be under + # an inappropriate parent. + comment_column -= len( comment_prefix.lstrip() ) + pytree_utils.InsertNodesAfter( + _CreateCommentsFromPrefix( + comment_prefix, + comment_lineno, + comment_column, + standalone = False ), prev_leaf[ 0 ] ) + elif child.type == token.DEDENT: + # Comment prefixes on DEDENT nodes also deserve special treatment, + # because their final placement depends on their prefix. + # We'll look for an ancestor of this child with a matching + # indentation, and insert the comment before it if the ancestor is + # on a DEDENT node and after it otherwise. + # + # lib2to3 places comments that should be separated into the same + # DEDENT node. For example, "comment 1" and "comment 2" will be + # combined. + # + # def _(): + # for x in y: + # pass + # # comment 1 + # + # # comment 2 + # pass + # + # In this case, we need to split them up ourselves. + + # Split into groups of comments at decreasing levels of indentation + comment_groups = [] + comment_column = None + for cmt in comment_prefix.split( '\n' ): + col = cmt.find( '#' ) + if col < 0: + if comment_column is None: + # Skip empty lines at the top of the first comment group + comment_lineno += 1 + continue + elif comment_column is None or col < comment_column: + comment_column = col + comment_indent = cmt[ : comment_column ] + comment_groups.append( + ( comment_column, comment_indent, [] ) ) + comment_groups[ -1 ][ -1 ].append( cmt ) + + # Insert a node for each group + for comment_column, comment_indent, comment_group in comment_groups: + ancestor_at_indent = _FindAncestorAtIndent( + child, comment_indent ) + if ancestor_at_indent.type == token.DEDENT: + InsertNodes = pytree_utils.InsertNodesBefore # pylint: disable=invalid-name # noqa + else: + InsertNodes = pytree_utils.InsertNodesAfter # pylint: disable=invalid-name # noqa + InsertNodes( + _CreateCommentsFromPrefix( + '\n'.join( comment_group ) + '\n', + comment_lineno, + comment_column, + standalone = True ), ancestor_at_indent ) + comment_lineno += len( comment_group ) + else: + # Otherwise there are two cases. + # + # 1. The comment is on its own line + # 2. The comment is part of an expression. + # + # Unfortunately, it's fairly difficult to distinguish between the + # two in lib2to3 trees. The algorithm here is to determine whether + # child is the first leaf in the statement it belongs to. If it is, + # then the comment (which is a prefix) belongs on a separate line. + # If it is not, it means the comment is buried deep in the statement + # and is part of some expression. + stmt_parent = _FindStmtParent( child ) + + for leaf_in_parent in stmt_parent.leaves(): + if leaf_in_parent.type == token.NEWLINE: + continue + elif id( leaf_in_parent ) == id( child ): + # This comment stands on its own line, and it has to be inserted + # into the appropriate parent. We'll have to find a suitable + # parent to insert into. See comments above + # _STANDALONE_LINE_NODES for more details. + node_with_line_parent = _FindNodeWithStandaloneLineParent( + child ) + + if pytree_utils.NodeName( + node_with_line_parent.parent ) in { 'funcdef', + 'classdef' + }: + # Keep a comment that's not attached to a function or class + # next to the object it is attached to. + comment_end = ( + comment_lineno + + comment_prefix.rstrip( '\n' ).count( '\n' ) ) + if comment_end < node_with_line_parent.lineno - 1: + node_with_line_parent = node_with_line_parent.parent + + pytree_utils.InsertNodesBefore( + _CreateCommentsFromPrefix( + comment_prefix, + comment_lineno, + 0, + standalone = True ), node_with_line_parent ) + break + else: + if comment_lineno == prev_leaf[ 0 ].lineno: + comment_lines = comment_prefix.splitlines() + value = comment_lines[ 0 ].lstrip() + if value.rstrip( '\n' ): + comment_column = prev_leaf[ 0 ].column + comment_column += len( prev_leaf[ 0 ].value ) + comment_column += ( + len( comment_lines[ 0 ] ) - + len( comment_lines[ 0 ].lstrip() ) ) + comment_leaf = pytree.Leaf( + type = token.COMMENT, + value = value.rstrip( '\n' ), + context = ( + '', ( comment_lineno, + comment_column ) ) ) + pytree_utils.InsertNodesAfter( + [ comment_leaf ], prev_leaf[ 0 ] ) + comment_prefix = '\n'.join( + comment_lines[ 1 : ] ) + comment_lineno += 1 + + rindex = ( + 0 if '\n' not in comment_prefix.rstrip() else + comment_prefix.rstrip().rindex( '\n' ) + 1 ) + comment_column = ( + len( comment_prefix[ rindex : ] ) - + len( comment_prefix[ rindex : ].lstrip() ) ) + comments = _CreateCommentsFromPrefix( + comment_prefix, + comment_lineno, + comment_column, + standalone = False ) + pytree_utils.InsertNodesBefore( comments, child ) + break + + prev_leaf[ 0 ] = child + + _VisitNodeRec( tree ) + + +def _CreateCommentsFromPrefix( + comment_prefix, comment_lineno, comment_column, standalone = False ): + """Create pytree nodes to represent the given comment prefix. Args: comment_prefix: (unicode) the text of the comment from the node's prefix. @@ -220,35 +233,35 @@ def _CreateCommentsFromPrefix(comment_prefix, new COMMENT leafs. The prefix may consist of multiple comment blocks, separated by blank lines. Each block gets its own leaf. """ - # The comment is stored in the prefix attribute, with no lineno of its - # own. So we only know at which line it ends. To find out at which line it - # starts, look at how many newlines the comment itself contains. - comments = [] - - lines = comment_prefix.split('\n') - index = 0 - while index < len(lines): - comment_block = [] - while index < len(lines) and lines[index].lstrip().startswith('#'): - comment_block.append(lines[index].strip()) - index += 1 - - if comment_block: - new_lineno = comment_lineno + index - 1 - comment_block[0] = comment_block[0].strip() - comment_block[-1] = comment_block[-1].strip() - comment_leaf = pytree.Leaf( - type=token.COMMENT, - value='\n'.join(comment_block), - context=('', (new_lineno, comment_column))) - comment_node = comment_leaf if not standalone else pytree.Node( - pygram.python_symbols.simple_stmt, [comment_leaf]) - comments.append(comment_node) - - while index < len(lines) and not lines[index].lstrip(): - index += 1 - - return comments + # The comment is stored in the prefix attribute, with no lineno of its + # own. So we only know at which line it ends. To find out at which line it + # starts, look at how many newlines the comment itself contains. + comments = [] + + lines = comment_prefix.split( '\n' ) + index = 0 + while index < len( lines ): + comment_block = [] + while index < len( lines ) and lines[ index ].lstrip().startswith( '#' ): + comment_block.append( lines[ index ].strip() ) + index += 1 + + if comment_block: + new_lineno = comment_lineno + index - 1 + comment_block[ 0 ] = comment_block[ 0 ].strip() + comment_block[ -1 ] = comment_block[ -1 ].strip() + comment_leaf = pytree.Leaf( + type = token.COMMENT, + value = '\n'.join( comment_block ), + context = ( '', ( new_lineno, comment_column ) ) ) + comment_node = comment_leaf if not standalone else pytree.Node( + pygram.python_symbols.simple_stmt, [ comment_leaf ] ) + comments.append( comment_node ) + + while index < len( lines ) and not lines[ index ].lstrip(): + index += 1 + + return comments # "Standalone line nodes" are tree nodes that have to start a new line in Python @@ -262,14 +275,15 @@ def _CreateCommentsFromPrefix(comment_prefix, # line, not on the same line with other code), it's important to insert it into # an appropriate parent of the node it's attached to. An appropriate parent # is the first "standalone line node" in the parent chain of a node. -_STANDALONE_LINE_NODES = frozenset([ - 'suite', 'if_stmt', 'while_stmt', 'for_stmt', 'try_stmt', 'with_stmt', - 'funcdef', 'classdef', 'decorated', 'file_input' -]) +_STANDALONE_LINE_NODES = frozenset( + [ + 'suite', 'if_stmt', 'while_stmt', 'for_stmt', 'try_stmt', 'with_stmt', + 'funcdef', 'classdef', 'decorated', 'file_input' + ] ) -def _FindNodeWithStandaloneLineParent(node): - """Find a node whose parent is a 'standalone line' node. +def _FindNodeWithStandaloneLineParent( node ): + """Find a node whose parent is a 'standalone line' node. See the comment above _STANDALONE_LINE_NODES for more details. @@ -279,21 +293,21 @@ def _FindNodeWithStandaloneLineParent(node): Returns: Suitable node that's either the node itself or one of its ancestors. """ - if pytree_utils.NodeName(node.parent) in _STANDALONE_LINE_NODES: - return node - else: - # This is guaranteed to terminate because 'file_input' is the root node of - # any pytree. - return _FindNodeWithStandaloneLineParent(node.parent) + if pytree_utils.NodeName( node.parent ) in _STANDALONE_LINE_NODES: + return node + else: + # This is guaranteed to terminate because 'file_input' is the root node of + # any pytree. + return _FindNodeWithStandaloneLineParent( node.parent ) # "Statement nodes" are standalone statements. The don't have to start a new # line. -_STATEMENT_NODES = frozenset(['simple_stmt']) | _STANDALONE_LINE_NODES +_STATEMENT_NODES = frozenset( [ 'simple_stmt' ] ) | _STANDALONE_LINE_NODES -def _FindStmtParent(node): - """Find the nearest parent of node that is a statement node. +def _FindStmtParent( node ): + """Find the nearest parent of node that is a statement node. Arguments: node: node to start from @@ -301,14 +315,14 @@ def _FindStmtParent(node): Returns: Nearest parent (or node itself, if suitable). """ - if pytree_utils.NodeName(node) in _STATEMENT_NODES: - return node - else: - return _FindStmtParent(node.parent) + if pytree_utils.NodeName( node ) in _STATEMENT_NODES: + return node + else: + return _FindStmtParent( node.parent ) -def _FindAncestorAtIndent(node, indent): - """Find an ancestor of node with the given indentation. +def _FindAncestorAtIndent( node, indent ): + """Find an ancestor of node with the given indentation. Arguments: node: node to start from. This must not be the tree root. @@ -319,27 +333,27 @@ def _FindAncestorAtIndent(node, indent): An ancestor node with suitable indentation. If no suitable ancestor is found, the closest ancestor to the tree root is returned. """ - if node.parent.parent is None: - # Our parent is the tree root, so there's nowhere else to go. - return node - - # If the parent has an indent annotation, and it's shorter than node's - # indent, this is a suitable ancestor. - # The reason for "shorter" rather than "equal" is that comments may be - # improperly indented (i.e. by three spaces, where surrounding statements - # have either zero or two or four), and we don't want to propagate them all - # the way to the root. - parent_indent = pytree_utils.GetNodeAnnotation( - node.parent, pytree_utils.Annotation.CHILD_INDENT) - if parent_indent is not None and indent.startswith(parent_indent): - return node - else: - # Keep looking up the tree. - return _FindAncestorAtIndent(node.parent, indent) - - -def _AnnotateIndents(tree): - """Annotate the tree with child_indent annotations. + if node.parent.parent is None: + # Our parent is the tree root, so there's nowhere else to go. + return node + + # If the parent has an indent annotation, and it's shorter than node's + # indent, this is a suitable ancestor. + # The reason for "shorter" rather than "equal" is that comments may be + # improperly indented (i.e. by three spaces, where surrounding statements + # have either zero or two or four), and we don't want to propagate them all + # the way to the root. + parent_indent = pytree_utils.GetNodeAnnotation( + node.parent, pytree_utils.Annotation.CHILD_INDENT ) + if parent_indent is not None and indent.startswith( parent_indent ): + return node + else: + # Keep looking up the tree. + return _FindAncestorAtIndent( node.parent, indent ) + + +def _AnnotateIndents( tree ): + """Annotate the tree with child_indent annotations. A child_indent annotation on a node specifies the indentation (as a string, like " ") of its children. It is inferred from the INDENT child of a node. @@ -350,16 +364,16 @@ def _AnnotateIndents(tree): Raises: RuntimeError: if the tree is malformed. """ - # Annotate the root of the tree with zero indent. - if tree.parent is None: - pytree_utils.SetNodeAnnotation(tree, pytree_utils.Annotation.CHILD_INDENT, - '') - for child in tree.children: - if child.type == token.INDENT: - child_indent = pytree_utils.GetNodeAnnotation( - tree, pytree_utils.Annotation.CHILD_INDENT) - if child_indent is not None and child_indent != child.value: - raise RuntimeError('inconsistent indentation for child', (tree, child)) - pytree_utils.SetNodeAnnotation(tree, pytree_utils.Annotation.CHILD_INDENT, - child.value) - _AnnotateIndents(child) + # Annotate the root of the tree with zero indent. + if tree.parent is None: + pytree_utils.SetNodeAnnotation( tree, pytree_utils.Annotation.CHILD_INDENT, '' ) + for child in tree.children: + if child.type == token.INDENT: + child_indent = pytree_utils.GetNodeAnnotation( + tree, pytree_utils.Annotation.CHILD_INDENT ) + if child_indent is not None and child_indent != child.value: + raise RuntimeError( + 'inconsistent indentation for child', ( tree, child ) ) + pytree_utils.SetNodeAnnotation( + tree, pytree_utils.Annotation.CHILD_INDENT, child.value ) + _AnnotateIndents( child ) diff --git a/yapf/pytree/continuation_splicer.py b/yapf/pytree/continuation_splicer.py index b86188cb5..dea4de29f 100644 --- a/yapf/pytree/continuation_splicer.py +++ b/yapf/pytree/continuation_splicer.py @@ -24,29 +24,29 @@ from yapf.yapflib import format_token -def SpliceContinuations(tree): - """Given a pytree, splice the continuation marker into nodes. +def SpliceContinuations( tree ): + """Given a pytree, splice the continuation marker into nodes. Arguments: tree: (pytree.Node) The tree to work on. The tree is modified by this function. """ - def RecSplicer(node): - """Inserts a continuation marker into the node.""" - if isinstance(node, pytree.Leaf): - if node.prefix.lstrip().startswith('\\\n'): - new_lineno = node.lineno - node.prefix.count('\n') - return pytree.Leaf( - type=format_token.CONTINUATION, - value=node.prefix, - context=('', (new_lineno, 0))) - return None - num_inserted = 0 - for index, child in enumerate(node.children[:]): - continuation_node = RecSplicer(child) - if continuation_node: - node.children.insert(index + num_inserted, continuation_node) - num_inserted += 1 - - RecSplicer(tree) + def RecSplicer( node ): + """Inserts a continuation marker into the node.""" + if isinstance( node, pytree.Leaf ): + if node.prefix.lstrip().startswith( '\\\n' ): + new_lineno = node.lineno - node.prefix.count( '\n' ) + return pytree.Leaf( + type = format_token.CONTINUATION, + value = node.prefix, + context = ( '', ( new_lineno, 0 ) ) ) + return None + num_inserted = 0 + for index, child in enumerate( node.children[ : ] ): + continuation_node = RecSplicer( child ) + if continuation_node: + node.children.insert( index + num_inserted, continuation_node ) + num_inserted += 1 + + RecSplicer( tree ) diff --git a/yapf/pytree/pytree_unwrapper.py b/yapf/pytree/pytree_unwrapper.py index 3fe4ade08..89618066b 100644 --- a/yapf/pytree/pytree_unwrapper.py +++ b/yapf/pytree/pytree_unwrapper.py @@ -40,12 +40,12 @@ from yapf.yapflib import style from yapf.yapflib import subtypes -_OPENING_BRACKETS = frozenset({'(', '[', '{'}) -_CLOSING_BRACKETS = frozenset({')', ']', '}'}) +_OPENING_BRACKETS = frozenset( { '(', '[', '{' } ) +_CLOSING_BRACKETS = frozenset( { ')', ']', '}' } ) -def UnwrapPyTree(tree): - """Create and return a list of logical lines from the given pytree. +def UnwrapPyTree( tree ): + """Create and return a list of logical lines from the given pytree. Arguments: tree: the top-level pytree node to unwrap.. @@ -53,22 +53,23 @@ def UnwrapPyTree(tree): Returns: A list of LogicalLine objects. """ - unwrapper = PyTreeUnwrapper() - unwrapper.Visit(tree) - llines = unwrapper.GetLogicalLines() - llines.sort(key=lambda x: x.lineno) - return llines + unwrapper = PyTreeUnwrapper() + unwrapper.Visit( tree ) + llines = unwrapper.GetLogicalLines() + llines.sort( key = lambda x: x.lineno ) + return llines # Grammar tokens considered as whitespace for the purpose of unwrapping. -_WHITESPACE_TOKENS = frozenset([ - grammar_token.NEWLINE, grammar_token.DEDENT, grammar_token.INDENT, - grammar_token.ENDMARKER -]) +_WHITESPACE_TOKENS = frozenset( + [ + grammar_token.NEWLINE, grammar_token.DEDENT, grammar_token.INDENT, + grammar_token.ENDMARKER + ] ) -class PyTreeUnwrapper(pytree_visitor.PyTreeVisitor): - """PyTreeUnwrapper - see file-level docstring for detailed description. +class PyTreeUnwrapper( pytree_visitor.PyTreeVisitor ): + """PyTreeUnwrapper - see file-level docstring for detailed description. Note: since this implements PyTreeVisitor and node names in lib2to3 are underscore_separated, the visiting methods of this class are named as @@ -82,77 +83,78 @@ class PyTreeUnwrapper(pytree_visitor.PyTreeVisitor): familiarity with the Python grammar is required. """ - def __init__(self): - # A list of all logical lines finished visiting so far. - self._logical_lines = [] + def __init__( self ): + # A list of all logical lines finished visiting so far. + self._logical_lines = [] - # Builds up a "current" logical line while visiting pytree nodes. Some nodes - # will finish a line and start a new one. - self._cur_logical_line = logical_line.LogicalLine(0) + # Builds up a "current" logical line while visiting pytree nodes. Some nodes + # will finish a line and start a new one. + self._cur_logical_line = logical_line.LogicalLine( 0 ) - # Current indentation depth. - self._cur_depth = 0 + # Current indentation depth. + self._cur_depth = 0 - def GetLogicalLines(self): - """Fetch the result of the tree walk. + def GetLogicalLines( self ): + """Fetch the result of the tree walk. Note: only call this after visiting the whole tree. Returns: A list of LogicalLine objects. """ - # Make sure the last line that was being populated is flushed. - self._StartNewLine() - return self._logical_lines + # Make sure the last line that was being populated is flushed. + self._StartNewLine() + return self._logical_lines - def _StartNewLine(self): - """Finish current line and start a new one. + def _StartNewLine( self ): + """Finish current line and start a new one. Place the currently accumulated line into the _logical_lines list and start a new one. """ - if self._cur_logical_line.tokens: - self._logical_lines.append(self._cur_logical_line) - _MatchBrackets(self._cur_logical_line) - _IdentifyParameterLists(self._cur_logical_line) - _AdjustSplitPenalty(self._cur_logical_line) - self._cur_logical_line = logical_line.LogicalLine(self._cur_depth) - - _STMT_TYPES = frozenset({ - 'if_stmt', - 'while_stmt', - 'for_stmt', - 'try_stmt', - 'expect_clause', - 'with_stmt', - 'funcdef', - 'classdef', - }) - - # pylint: disable=invalid-name,missing-docstring - def Visit_simple_stmt(self, node): - # A 'simple_stmt' conveniently represents a non-compound Python statement, - # i.e. a statement that does not contain other statements. - - # When compound nodes have a single statement as their suite, the parser - # can leave it in the tree directly without creating a suite. But we have - # to increase depth in these cases as well. However, don't increase the - # depth of we have a simple_stmt that's a comment node. This represents a - # standalone comment and in the case of it coming directly after the - # funcdef, it is a "top" comment for the whole function. - # TODO(eliben): add more relevant compound statements here. - single_stmt_suite = ( - node.parent and pytree_utils.NodeName(node.parent) in self._STMT_TYPES) - is_comment_stmt = pytree_utils.IsCommentStatement(node) - if single_stmt_suite and not is_comment_stmt: - self._cur_depth += 1 - self._StartNewLine() - self.DefaultNodeVisit(node) - if single_stmt_suite and not is_comment_stmt: - self._cur_depth -= 1 - - def _VisitCompoundStatement(self, node, substatement_names): - """Helper for visiting compound statements. + if self._cur_logical_line.tokens: + self._logical_lines.append( self._cur_logical_line ) + _MatchBrackets( self._cur_logical_line ) + _IdentifyParameterLists( self._cur_logical_line ) + _AdjustSplitPenalty( self._cur_logical_line ) + self._cur_logical_line = logical_line.LogicalLine( self._cur_depth ) + + _STMT_TYPES = frozenset( + { + 'if_stmt', + 'while_stmt', + 'for_stmt', + 'try_stmt', + 'expect_clause', + 'with_stmt', + 'funcdef', + 'classdef', + } ) + + # pylint: disable=invalid-name,missing-docstring + def Visit_simple_stmt( self, node ): + # A 'simple_stmt' conveniently represents a non-compound Python statement, + # i.e. a statement that does not contain other statements. + + # When compound nodes have a single statement as their suite, the parser + # can leave it in the tree directly without creating a suite. But we have + # to increase depth in these cases as well. However, don't increase the + # depth of we have a simple_stmt that's a comment node. This represents a + # standalone comment and in the case of it coming directly after the + # funcdef, it is a "top" comment for the whole function. + # TODO(eliben): add more relevant compound statements here. + single_stmt_suite = ( + node.parent and pytree_utils.NodeName( node.parent ) in self._STMT_TYPES ) + is_comment_stmt = pytree_utils.IsCommentStatement( node ) + if single_stmt_suite and not is_comment_stmt: + self._cur_depth += 1 + self._StartNewLine() + self.DefaultNodeVisit( node ) + if single_stmt_suite and not is_comment_stmt: + self._cur_depth -= 1 + + def _VisitCompoundStatement( self, node, substatement_names ): + """Helper for visiting compound statements. Python compound statements serve as containers for other statements. Thus, when we encounter a new compound statement, we start a new logical line. @@ -162,150 +164,150 @@ def _VisitCompoundStatement(self, node, substatement_names): substatement_names: set of node names. A compound statement will be recognized as a NAME node with a name in this set. """ - for child in node.children: - # A pytree is structured in such a way that a single 'if_stmt' node will - # contain all the 'if', 'elif' and 'else' nodes as children (similar - # structure applies to 'while' statements, 'try' blocks, etc). Therefore, - # we visit all children here and create a new line before the requested - # set of nodes. - if (child.type == grammar_token.NAME and - child.value in substatement_names): - self._StartNewLine() - self.Visit(child) + for child in node.children: + # A pytree is structured in such a way that a single 'if_stmt' node will + # contain all the 'if', 'elif' and 'else' nodes as children (similar + # structure applies to 'while' statements, 'try' blocks, etc). Therefore, + # we visit all children here and create a new line before the requested + # set of nodes. + if ( child.type == grammar_token.NAME and + child.value in substatement_names ): + self._StartNewLine() + self.Visit( child ) - _IF_STMT_ELEMS = frozenset({'if', 'else', 'elif'}) + _IF_STMT_ELEMS = frozenset( { 'if', 'else', 'elif' } ) - def Visit_if_stmt(self, node): # pylint: disable=invalid-name - self._VisitCompoundStatement(node, self._IF_STMT_ELEMS) + def Visit_if_stmt( self, node ): # pylint: disable=invalid-name + self._VisitCompoundStatement( node, self._IF_STMT_ELEMS ) - _WHILE_STMT_ELEMS = frozenset({'while', 'else'}) + _WHILE_STMT_ELEMS = frozenset( { 'while', 'else' } ) - def Visit_while_stmt(self, node): # pylint: disable=invalid-name - self._VisitCompoundStatement(node, self._WHILE_STMT_ELEMS) + def Visit_while_stmt( self, node ): # pylint: disable=invalid-name + self._VisitCompoundStatement( node, self._WHILE_STMT_ELEMS ) - _FOR_STMT_ELEMS = frozenset({'for', 'else'}) + _FOR_STMT_ELEMS = frozenset( { 'for', 'else' } ) - def Visit_for_stmt(self, node): # pylint: disable=invalid-name - self._VisitCompoundStatement(node, self._FOR_STMT_ELEMS) + def Visit_for_stmt( self, node ): # pylint: disable=invalid-name + self._VisitCompoundStatement( node, self._FOR_STMT_ELEMS ) - _TRY_STMT_ELEMS = frozenset({'try', 'except', 'else', 'finally'}) + _TRY_STMT_ELEMS = frozenset( { 'try', 'except', 'else', 'finally' } ) - def Visit_try_stmt(self, node): # pylint: disable=invalid-name - self._VisitCompoundStatement(node, self._TRY_STMT_ELEMS) + def Visit_try_stmt( self, node ): # pylint: disable=invalid-name + self._VisitCompoundStatement( node, self._TRY_STMT_ELEMS ) - _EXCEPT_STMT_ELEMS = frozenset({'except'}) + _EXCEPT_STMT_ELEMS = frozenset( { 'except' } ) - def Visit_except_clause(self, node): # pylint: disable=invalid-name - self._VisitCompoundStatement(node, self._EXCEPT_STMT_ELEMS) + def Visit_except_clause( self, node ): # pylint: disable=invalid-name + self._VisitCompoundStatement( node, self._EXCEPT_STMT_ELEMS ) - _FUNC_DEF_ELEMS = frozenset({'def'}) + _FUNC_DEF_ELEMS = frozenset( { 'def' } ) - def Visit_funcdef(self, node): # pylint: disable=invalid-name - self._VisitCompoundStatement(node, self._FUNC_DEF_ELEMS) + def Visit_funcdef( self, node ): # pylint: disable=invalid-name + self._VisitCompoundStatement( node, self._FUNC_DEF_ELEMS ) - def Visit_async_funcdef(self, node): # pylint: disable=invalid-name - self._StartNewLine() - index = 0 - for child in node.children: - index += 1 - self.Visit(child) - if child.type == grammar_token.ASYNC: - break - for child in node.children[index].children: - self.Visit(child) + def Visit_async_funcdef( self, node ): # pylint: disable=invalid-name + self._StartNewLine() + index = 0 + for child in node.children: + index += 1 + self.Visit( child ) + if child.type == grammar_token.ASYNC: + break + for child in node.children[ index ].children: + self.Visit( child ) - _CLASS_DEF_ELEMS = frozenset({'class'}) + _CLASS_DEF_ELEMS = frozenset( { 'class' } ) - def Visit_classdef(self, node): # pylint: disable=invalid-name - self._VisitCompoundStatement(node, self._CLASS_DEF_ELEMS) + def Visit_classdef( self, node ): # pylint: disable=invalid-name + self._VisitCompoundStatement( node, self._CLASS_DEF_ELEMS ) - def Visit_async_stmt(self, node): # pylint: disable=invalid-name - self._StartNewLine() - index = 0 - for child in node.children: - index += 1 - self.Visit(child) - if child.type == grammar_token.ASYNC: - break - for child in node.children[index].children: - if child.type == grammar_token.NAME and child.value == 'else': + def Visit_async_stmt( self, node ): # pylint: disable=invalid-name self._StartNewLine() - self.Visit(child) - - def Visit_decorator(self, node): # pylint: disable=invalid-name - for child in node.children: - self.Visit(child) - if child.type == grammar_token.COMMENT and child == node.children[0]: + index = 0 + for child in node.children: + index += 1 + self.Visit( child ) + if child.type == grammar_token.ASYNC: + break + for child in node.children[ index ].children: + if child.type == grammar_token.NAME and child.value == 'else': + self._StartNewLine() + self.Visit( child ) + + def Visit_decorator( self, node ): # pylint: disable=invalid-name + for child in node.children: + self.Visit( child ) + if child.type == grammar_token.COMMENT and child == node.children[ 0 ]: + self._StartNewLine() + + def Visit_decorators( self, node ): # pylint: disable=invalid-name + for child in node.children: + self._StartNewLine() + self.Visit( child ) + + def Visit_decorated( self, node ): # pylint: disable=invalid-name + for child in node.children: + self._StartNewLine() + self.Visit( child ) + + _WITH_STMT_ELEMS = frozenset( { 'with' } ) + + def Visit_with_stmt( self, node ): # pylint: disable=invalid-name + self._VisitCompoundStatement( node, self._WITH_STMT_ELEMS ) + + def Visit_suite( self, node ): # pylint: disable=invalid-name + # A 'suite' starts a new indentation level in Python. + self._cur_depth += 1 self._StartNewLine() + self.DefaultNodeVisit( node ) + self._cur_depth -= 1 - def Visit_decorators(self, node): # pylint: disable=invalid-name - for child in node.children: - self._StartNewLine() - self.Visit(child) - - def Visit_decorated(self, node): # pylint: disable=invalid-name - for child in node.children: - self._StartNewLine() - self.Visit(child) - - _WITH_STMT_ELEMS = frozenset({'with'}) - - def Visit_with_stmt(self, node): # pylint: disable=invalid-name - self._VisitCompoundStatement(node, self._WITH_STMT_ELEMS) - - def Visit_suite(self, node): # pylint: disable=invalid-name - # A 'suite' starts a new indentation level in Python. - self._cur_depth += 1 - self._StartNewLine() - self.DefaultNodeVisit(node) - self._cur_depth -= 1 - - def Visit_listmaker(self, node): # pylint: disable=invalid-name - _DetermineMustSplitAnnotation(node) - self.DefaultNodeVisit(node) + def Visit_listmaker( self, node ): # pylint: disable=invalid-name + _DetermineMustSplitAnnotation( node ) + self.DefaultNodeVisit( node ) - def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name - _DetermineMustSplitAnnotation(node) - self.DefaultNodeVisit(node) + def Visit_dictsetmaker( self, node ): # pylint: disable=invalid-name + _DetermineMustSplitAnnotation( node ) + self.DefaultNodeVisit( node ) - def Visit_import_as_names(self, node): # pylint: disable=invalid-name - if node.prev_sibling.value == '(': - _DetermineMustSplitAnnotation(node) - self.DefaultNodeVisit(node) + def Visit_import_as_names( self, node ): # pylint: disable=invalid-name + if node.prev_sibling.value == '(': + _DetermineMustSplitAnnotation( node ) + self.DefaultNodeVisit( node ) - def Visit_testlist_gexp(self, node): # pylint: disable=invalid-name - _DetermineMustSplitAnnotation(node) - self.DefaultNodeVisit(node) + def Visit_testlist_gexp( self, node ): # pylint: disable=invalid-name + _DetermineMustSplitAnnotation( node ) + self.DefaultNodeVisit( node ) - def Visit_arglist(self, node): # pylint: disable=invalid-name - _DetermineMustSplitAnnotation(node) - self.DefaultNodeVisit(node) + def Visit_arglist( self, node ): # pylint: disable=invalid-name + _DetermineMustSplitAnnotation( node ) + self.DefaultNodeVisit( node ) - def Visit_typedargslist(self, node): # pylint: disable=invalid-name - _DetermineMustSplitAnnotation(node) - self.DefaultNodeVisit(node) + def Visit_typedargslist( self, node ): # pylint: disable=invalid-name + _DetermineMustSplitAnnotation( node ) + self.DefaultNodeVisit( node ) - def DefaultLeafVisit(self, leaf): - """Default visitor for tree leaves. + def DefaultLeafVisit( self, leaf ): + """Default visitor for tree leaves. A tree leaf is always just gets appended to the current logical line. Arguments: leaf: the leaf to visit. """ - if leaf.type in _WHITESPACE_TOKENS: - self._StartNewLine() - elif leaf.type != grammar_token.COMMENT or leaf.value.strip(): - # Add non-whitespace tokens and comments that aren't empty. - self._cur_logical_line.AppendToken( - format_token.FormatToken(leaf, pytree_utils.NodeName(leaf))) + if leaf.type in _WHITESPACE_TOKENS: + self._StartNewLine() + elif leaf.type != grammar_token.COMMENT or leaf.value.strip(): + # Add non-whitespace tokens and comments that aren't empty. + self._cur_logical_line.AppendToken( + format_token.FormatToken( leaf, pytree_utils.NodeName( leaf ) ) ) -_BRACKET_MATCH = {')': '(', '}': '{', ']': '['} +_BRACKET_MATCH = { ')': '(', '}': '{', ']': '['} -def _MatchBrackets(line): - """Visit the node and match the brackets. +def _MatchBrackets( line ): + """Visit the node and match the brackets. For every open bracket ('[', '{', or '('), find the associated closing bracket and "match" them up. I.e., save in the token a pointer to its associated open @@ -314,23 +316,23 @@ def _MatchBrackets(line): Arguments: line: (LogicalLine) A logical line. """ - bracket_stack = [] - for token in line.tokens: - if token.value in _OPENING_BRACKETS: - bracket_stack.append(token) - elif token.value in _CLOSING_BRACKETS: - bracket_stack[-1].matching_bracket = token - token.matching_bracket = bracket_stack[-1] - bracket_stack.pop() + bracket_stack = [] + for token in line.tokens: + if token.value in _OPENING_BRACKETS: + bracket_stack.append( token ) + elif token.value in _CLOSING_BRACKETS: + bracket_stack[ -1 ].matching_bracket = token + token.matching_bracket = bracket_stack[ -1 ] + bracket_stack.pop() - for bracket in bracket_stack: - if id(pytree_utils.GetOpeningBracket(token.node)) == id(bracket.node): - bracket.container_elements.append(token) - token.container_opening = bracket + for bracket in bracket_stack: + if id( pytree_utils.GetOpeningBracket( token.node ) ) == id( bracket.node ): + bracket.container_elements.append( token ) + token.container_opening = bracket -def _IdentifyParameterLists(line): - """Visit the node to create a state for parameter lists. +def _IdentifyParameterLists( line ): + """Visit the node to create a state for parameter lists. For instance, a parameter is considered an "object" with its first and last token uniquely identifying the object. @@ -338,32 +340,32 @@ def _IdentifyParameterLists(line): Arguments: line: (LogicalLine) A logical line. """ - func_stack = [] - param_stack = [] - for tok in line.tokens: - # Identify parameter list objects. - if subtypes.FUNC_DEF in tok.subtypes: - assert tok.next_token.value == '(' - func_stack.append(tok.next_token) - continue + func_stack = [] + param_stack = [] + for tok in line.tokens: + # Identify parameter list objects. + if subtypes.FUNC_DEF in tok.subtypes: + assert tok.next_token.value == '(' + func_stack.append( tok.next_token ) + continue - if func_stack and tok.value == ')': - if tok == func_stack[-1].matching_bracket: - func_stack.pop() - continue + if func_stack and tok.value == ')': + if tok == func_stack[ -1 ].matching_bracket: + func_stack.pop() + continue - # Identify parameter objects. - if subtypes.PARAMETER_START in tok.subtypes: - param_stack.append(tok) + # Identify parameter objects. + if subtypes.PARAMETER_START in tok.subtypes: + param_stack.append( tok ) - # Not "elif", a parameter could be a single token. - if param_stack and subtypes.PARAMETER_STOP in tok.subtypes: - start = param_stack.pop() - func_stack[-1].parameters.append(object_state.Parameter(start, tok)) + # Not "elif", a parameter could be a single token. + if param_stack and subtypes.PARAMETER_STOP in tok.subtypes: + start = param_stack.pop() + func_stack[ -1 ].parameters.append( object_state.Parameter( start, tok ) ) -def _AdjustSplitPenalty(line): - """Visit the node and adjust the split penalties if needed. +def _AdjustSplitPenalty( line ): + """Visit the node and adjust the split penalties if needed. A token shouldn't be split if it's not within a bracket pair. Mark any token that's not within a bracket pair as "unbreakable". @@ -371,57 +373,56 @@ def _AdjustSplitPenalty(line): Arguments: line: (LogicalLine) An logical line. """ - bracket_level = 0 - for index, token in enumerate(line.tokens): - if index and not bracket_level: - pytree_utils.SetNodeAnnotation(token.node, - pytree_utils.Annotation.SPLIT_PENALTY, - split_penalty.UNBREAKABLE) - if token.value in _OPENING_BRACKETS: - bracket_level += 1 - elif token.value in _CLOSING_BRACKETS: - bracket_level -= 1 - - -def _DetermineMustSplitAnnotation(node): - """Enforce a split in the list if the list ends with a comma.""" - if style.Get('DISABLE_ENDING_COMMA_HEURISTIC'): - return - if not _ContainsComments(node): - token = next(node.parent.leaves()) - if token.value == '(': - if sum(1 for ch in node.children if ch.type == grammar_token.COMMA) < 2: + bracket_level = 0 + for index, token in enumerate( line.tokens ): + if index and not bracket_level: + pytree_utils.SetNodeAnnotation( + token.node, pytree_utils.Annotation.SPLIT_PENALTY, + split_penalty.UNBREAKABLE ) + if token.value in _OPENING_BRACKETS: + bracket_level += 1 + elif token.value in _CLOSING_BRACKETS: + bracket_level -= 1 + + +def _DetermineMustSplitAnnotation( node ): + """Enforce a split in the list if the list ends with a comma.""" + if style.Get( 'DISABLE_ENDING_COMMA_HEURISTIC' ): return - if (not isinstance(node.children[-1], pytree.Leaf) or - node.children[-1].value != ','): - return - num_children = len(node.children) - index = 0 - _SetMustSplitOnFirstLeaf(node.children[0]) - while index < num_children - 1: - child = node.children[index] - if isinstance(child, pytree.Leaf) and child.value == ',': - next_child = node.children[index + 1] - if next_child.type == grammar_token.COMMENT: + if not _ContainsComments( node ): + token = next( node.parent.leaves() ) + if token.value == '(': + if sum( 1 for ch in node.children if ch.type == grammar_token.COMMA ) < 2: + return + if ( not isinstance( node.children[ -1 ], pytree.Leaf ) or + node.children[ -1 ].value != ',' ): + return + num_children = len( node.children ) + index = 0 + _SetMustSplitOnFirstLeaf( node.children[ 0 ] ) + while index < num_children - 1: + child = node.children[ index ] + if isinstance( child, pytree.Leaf ) and child.value == ',': + next_child = node.children[ index + 1 ] + if next_child.type == grammar_token.COMMENT: + index += 1 + if index >= num_children - 1: + break + _SetMustSplitOnFirstLeaf( node.children[ index + 1 ] ) index += 1 - if index >= num_children - 1: - break - _SetMustSplitOnFirstLeaf(node.children[index + 1]) - index += 1 - - -def _ContainsComments(node): - """Return True if the list has a comment in it.""" - if isinstance(node, pytree.Leaf): - return node.type == grammar_token.COMMENT - for child in node.children: - if _ContainsComments(child): - return True - return False - - -def _SetMustSplitOnFirstLeaf(node): - """Set the "must split" annotation on the first leaf node.""" - pytree_utils.SetNodeAnnotation( - pytree_utils.FirstLeafNode(node), pytree_utils.Annotation.MUST_SPLIT, - True) + + +def _ContainsComments( node ): + """Return True if the list has a comment in it.""" + if isinstance( node, pytree.Leaf ): + return node.type == grammar_token.COMMENT + for child in node.children: + if _ContainsComments( child ): + return True + return False + + +def _SetMustSplitOnFirstLeaf( node ): + """Set the "must split" annotation on the first leaf node.""" + pytree_utils.SetNodeAnnotation( + pytree_utils.FirstLeafNode( node ), pytree_utils.Annotation.MUST_SPLIT, True ) diff --git a/yapf/pytree/pytree_utils.py b/yapf/pytree/pytree_utils.py index 66a54e617..710e0082d 100644 --- a/yapf/pytree/pytree_utils.py +++ b/yapf/pytree/pytree_utils.py @@ -37,20 +37,20 @@ # have a better understanding of what information we need from the tree. Then, # these tokens may be filtered out from the tree before the tree gets to the # unwrapper. -NONSEMANTIC_TOKENS = frozenset(['DEDENT', 'INDENT', 'NEWLINE', 'ENDMARKER']) +NONSEMANTIC_TOKENS = frozenset( [ 'DEDENT', 'INDENT', 'NEWLINE', 'ENDMARKER' ] ) -class Annotation(object): - """Annotation names associated with pytrees.""" - CHILD_INDENT = 'child_indent' - NEWLINES = 'newlines' - MUST_SPLIT = 'must_split' - SPLIT_PENALTY = 'split_penalty' - SUBTYPE = 'subtype' +class Annotation( object ): + """Annotation names associated with pytrees.""" + CHILD_INDENT = 'child_indent' + NEWLINES = 'newlines' + MUST_SPLIT = 'must_split' + SPLIT_PENALTY = 'split_penalty' + SUBTYPE = 'subtype' -def NodeName(node): - """Produce a string name for a given node. +def NodeName( node ): + """Produce a string name for a given node. For a Leaf this is the token name, and for a Node this is the type. @@ -60,23 +60,23 @@ def NodeName(node): Returns: Name as a string. """ - # Nodes with values < 256 are tokens. Values >= 256 are grammar symbols. - if node.type < 256: - return token.tok_name[node.type] - else: - return pygram.python_grammar.number2symbol[node.type] + # Nodes with values < 256 are tokens. Values >= 256 are grammar symbols. + if node.type < 256: + return token.tok_name[ node.type ] + else: + return pygram.python_grammar.number2symbol[ node.type ] -def FirstLeafNode(node): - if isinstance(node, pytree.Leaf): - return node - return FirstLeafNode(node.children[0]) +def FirstLeafNode( node ): + if isinstance( node, pytree.Leaf ): + return node + return FirstLeafNode( node.children[ 0 ] ) -def LastLeafNode(node): - if isinstance(node, pytree.Leaf): - return node - return LastLeafNode(node.children[-1]) +def LastLeafNode( node ): + if isinstance( node, pytree.Leaf ): + return node + return LastLeafNode( node.children[ -1 ] ) # lib2to3 thoughtfully provides pygram.python_grammar_no_print_statement for @@ -85,14 +85,14 @@ def LastLeafNode(node): # It forgets to do the same for 'exec' though. Luckily, Python is amenable to # monkey-patching. _GRAMMAR_FOR_PY3 = pygram.python_grammar_no_print_statement.copy() -del _GRAMMAR_FOR_PY3.keywords['exec'] +del _GRAMMAR_FOR_PY3.keywords[ 'exec' ] _GRAMMAR_FOR_PY2 = pygram.python_grammar.copy() -del _GRAMMAR_FOR_PY2.keywords['nonlocal'] +del _GRAMMAR_FOR_PY2.keywords[ 'nonlocal' ] -def ParseCodeToTree(code): - """Parse the given code to a lib2to3 pytree. +def ParseCodeToTree( code ): + """Parse the given code to a lib2to3 pytree. Arguments: code: a string with the code to parse. @@ -104,35 +104,35 @@ def ParseCodeToTree(code): Returns: The root node of the parsed tree. """ - # This function is tiny, but the incantation for invoking the parser correctly - # is sufficiently magical to be worth abstracting away. - if not code.endswith(os.linesep): - code += os.linesep - - try: - # Try to parse using a Python 3 grammar, which is more permissive (print and - # exec are not keywords). - parser_driver = driver.Driver(_GRAMMAR_FOR_PY3, convert=pytree.convert) - tree = parser_driver.parse_string(code, debug=False) - except parse.ParseError: - # Now try to parse using a Python 2 grammar; If this fails, then - # there's something else wrong with the code. + # This function is tiny, but the incantation for invoking the parser correctly + # is sufficiently magical to be worth abstracting away. + if not code.endswith( os.linesep ): + code += os.linesep + try: - parser_driver = driver.Driver(_GRAMMAR_FOR_PY2, convert=pytree.convert) - tree = parser_driver.parse_string(code, debug=False) + # Try to parse using a Python 3 grammar, which is more permissive (print and + # exec are not keywords). + parser_driver = driver.Driver( _GRAMMAR_FOR_PY3, convert = pytree.convert ) + tree = parser_driver.parse_string( code, debug = False ) except parse.ParseError: - # Raise a syntax error if the code is invalid python syntax. - try: - ast.parse(code) - except SyntaxError as e: - raise e - else: - raise - return _WrapEndMarker(tree) - - -def _WrapEndMarker(tree): - """Wrap a single ENDMARKER token in a "file_input" node. + # Now try to parse using a Python 2 grammar; If this fails, then + # there's something else wrong with the code. + try: + parser_driver = driver.Driver( _GRAMMAR_FOR_PY2, convert = pytree.convert ) + tree = parser_driver.parse_string( code, debug = False ) + except parse.ParseError: + # Raise a syntax error if the code is invalid python syntax. + try: + ast.parse( code ) + except SyntaxError as e: + raise e + else: + raise + return _WrapEndMarker( tree ) + + +def _WrapEndMarker( tree ): + """Wrap a single ENDMARKER token in a "file_input" node. Arguments: tree: (pytree.Node) The root node of the parsed tree. @@ -142,13 +142,13 @@ def _WrapEndMarker(tree): then that node is wrapped in a "file_input" node. That will ensure we don't skip comments attached to that node. """ - if isinstance(tree, pytree.Leaf) and tree.type == token.ENDMARKER: - return pytree.Node(pygram.python_symbols.file_input, [tree]) - return tree + if isinstance( tree, pytree.Leaf ) and tree.type == token.ENDMARKER: + return pytree.Node( pygram.python_symbols.file_input, [ tree ] ) + return tree -def InsertNodesBefore(new_nodes, target): - """Insert new_nodes before the given target location in the tree. +def InsertNodesBefore( new_nodes, target ): + """Insert new_nodes before the given target location in the tree. Arguments: new_nodes: a sequence of new nodes to insert (the nodes should not be in the @@ -158,12 +158,12 @@ def InsertNodesBefore(new_nodes, target): Raises: RuntimeError: if the tree is corrupted, or the insertion would corrupt it. """ - for node in new_nodes: - _InsertNodeAt(node, target, after=False) + for node in new_nodes: + _InsertNodeAt( node, target, after = False ) -def InsertNodesAfter(new_nodes, target): - """Insert new_nodes after the given target location in the tree. +def InsertNodesAfter( new_nodes, target ): + """Insert new_nodes after the given target location in the tree. Arguments: new_nodes: a sequence of new nodes to insert (the nodes should not be in the @@ -173,12 +173,12 @@ def InsertNodesAfter(new_nodes, target): Raises: RuntimeError: if the tree is corrupted, or the insertion would corrupt it. """ - for node in reversed(new_nodes): - _InsertNodeAt(node, target, after=True) + for node in reversed( new_nodes ): + _InsertNodeAt( node, target, after = True ) -def _InsertNodeAt(new_node, target, after=False): - """Underlying implementation for node insertion. +def _InsertNodeAt( new_node, target, after = False ): + """Underlying implementation for node insertion. Arguments: new_node: a new node to insert (this node should not be in the tree). @@ -193,24 +193,23 @@ def _InsertNodeAt(new_node, target, after=False): RuntimeError: if the tree is corrupted, or the insertion would corrupt it. """ - # Protect against attempts to insert nodes which already belong to some tree. - if new_node.parent is not None: - raise RuntimeError('inserting node which already has a parent', - (new_node, new_node.parent)) + # Protect against attempts to insert nodes which already belong to some tree. + if new_node.parent is not None: + raise RuntimeError( + 'inserting node which already has a parent', ( new_node, new_node.parent ) ) - # The code here is based on pytree.Base.next_sibling - parent_of_target = target.parent - if parent_of_target is None: - raise RuntimeError('expected target node to have a parent', (target,)) + # The code here is based on pytree.Base.next_sibling + parent_of_target = target.parent + if parent_of_target is None: + raise RuntimeError( 'expected target node to have a parent', ( target,) ) - for i, child in enumerate(parent_of_target.children): - if child is target: - insertion_index = i + 1 if after else i - parent_of_target.insert_child(insertion_index, new_node) - return + for i, child in enumerate( parent_of_target.children ): + if child is target: + insertion_index = i + 1 if after else i + parent_of_target.insert_child( insertion_index, new_node ) + return - raise RuntimeError('unable to find insertion point for target node', - (target,)) + raise RuntimeError( 'unable to find insertion point for target node', ( target,) ) # The following constant and functions implement a simple custom annotation @@ -220,20 +219,20 @@ def _InsertNodeAt(new_node, target, after=False): _NODE_ANNOTATION_PREFIX = '_yapf_annotation_' -def CopyYapfAnnotations(src, dst): - """Copy all YAPF annotations from the source node to the destination node. +def CopyYapfAnnotations( src, dst ): + """Copy all YAPF annotations from the source node to the destination node. Arguments: src: the source node. dst: the destination node. """ - for annotation in dir(src): - if annotation.startswith(_NODE_ANNOTATION_PREFIX): - setattr(dst, annotation, getattr(src, annotation, None)) + for annotation in dir( src ): + if annotation.startswith( _NODE_ANNOTATION_PREFIX ): + setattr( dst, annotation, getattr( src, annotation, None ) ) -def GetNodeAnnotation(node, annotation, default=None): - """Get annotation value from a node. +def GetNodeAnnotation( node, annotation, default = None ): + """Get annotation value from a node. Arguments: node: the node. @@ -244,48 +243,48 @@ def GetNodeAnnotation(node, annotation, default=None): Value of the annotation in the given node. If the node doesn't have this particular annotation name yet, returns default. """ - return getattr(node, _NODE_ANNOTATION_PREFIX + annotation, default) + return getattr( node, _NODE_ANNOTATION_PREFIX + annotation, default ) -def SetNodeAnnotation(node, annotation, value): - """Set annotation value on a node. +def SetNodeAnnotation( node, annotation, value ): + """Set annotation value on a node. Arguments: node: the node. annotation: annotation name - a string. value: annotation value to set. """ - setattr(node, _NODE_ANNOTATION_PREFIX + annotation, value) + setattr( node, _NODE_ANNOTATION_PREFIX + annotation, value ) -def AppendNodeAnnotation(node, annotation, value): - """Appends an annotation value to a list of annotations on the node. +def AppendNodeAnnotation( node, annotation, value ): + """Appends an annotation value to a list of annotations on the node. Arguments: node: the node. annotation: annotation name - a string. value: annotation value to set. """ - attr = GetNodeAnnotation(node, annotation, set()) - attr.add(value) - SetNodeAnnotation(node, annotation, attr) + attr = GetNodeAnnotation( node, annotation, set() ) + attr.add( value ) + SetNodeAnnotation( node, annotation, attr ) -def RemoveSubtypeAnnotation(node, value): - """Removes an annotation value from the subtype annotations on the node. +def RemoveSubtypeAnnotation( node, value ): + """Removes an annotation value from the subtype annotations on the node. Arguments: node: the node. value: annotation value to remove. """ - attr = GetNodeAnnotation(node, Annotation.SUBTYPE) - if attr and value in attr: - attr.remove(value) - SetNodeAnnotation(node, Annotation.SUBTYPE, attr) + attr = GetNodeAnnotation( node, Annotation.SUBTYPE ) + if attr and value in attr: + attr.remove( value ) + SetNodeAnnotation( node, Annotation.SUBTYPE, attr ) -def GetOpeningBracket(node): - """Get opening bracket value from a node. +def GetOpeningBracket( node ): + """Get opening bracket value from a node. Arguments: node: the node. @@ -293,21 +292,21 @@ def GetOpeningBracket(node): Returns: The opening bracket node or None if it couldn't find one. """ - return getattr(node, _NODE_ANNOTATION_PREFIX + 'container_bracket', None) + return getattr( node, _NODE_ANNOTATION_PREFIX + 'container_bracket', None ) -def SetOpeningBracket(node, bracket): - """Set opening bracket value for a node. +def SetOpeningBracket( node, bracket ): + """Set opening bracket value for a node. Arguments: node: the node. bracket: opening bracket to set. """ - setattr(node, _NODE_ANNOTATION_PREFIX + 'container_bracket', bracket) + setattr( node, _NODE_ANNOTATION_PREFIX + 'container_bracket', bracket ) -def DumpNodeToString(node): - """Dump a string representation of the given node. For debugging. +def DumpNodeToString( node ): + """Dump a string representation of the given node. For debugging. Arguments: node: the node. @@ -315,33 +314,35 @@ def DumpNodeToString(node): Returns: The string representation. """ - if isinstance(node, pytree.Leaf): - fmt = ('{name}({value}) [lineno={lineno}, column={column}, ' - 'prefix={prefix}, penalty={penalty}]') - return fmt.format( - name=NodeName(node), - value=_PytreeNodeRepr(node), - lineno=node.lineno, - column=node.column, - prefix=repr(node.prefix), - penalty=GetNodeAnnotation(node, Annotation.SPLIT_PENALTY, None)) - else: - fmt = '{node} [{len} children] [child_indent="{indent}"]' - return fmt.format( - node=NodeName(node), - len=len(node.children), - indent=GetNodeAnnotation(node, Annotation.CHILD_INDENT)) - - -def _PytreeNodeRepr(node): - """Like pytree.Node.__repr__, but names instead of numbers for tokens.""" - if isinstance(node, pytree.Node): - return '%s(%s, %r)' % (node.__class__.__name__, NodeName(node), - [_PytreeNodeRepr(c) for c in node.children]) - if isinstance(node, pytree.Leaf): - return '%s(%s, %r)' % (node.__class__.__name__, NodeName(node), node.value) - - -def IsCommentStatement(node): - return (NodeName(node) == 'simple_stmt' and - node.children[0].type == token.COMMENT) + if isinstance( node, pytree.Leaf ): + fmt = ( + '{name}({value}) [lineno={lineno}, column={column}, ' + 'prefix={prefix}, penalty={penalty}]' ) + return fmt.format( + name = NodeName( node ), + value = _PytreeNodeRepr( node ), + lineno = node.lineno, + column = node.column, + prefix = repr( node.prefix ), + penalty = GetNodeAnnotation( node, Annotation.SPLIT_PENALTY, None ) ) + else: + fmt = '{node} [{len} children] [child_indent="{indent}"]' + return fmt.format( + node = NodeName( node ), + len = len( node.children ), + indent = GetNodeAnnotation( node, Annotation.CHILD_INDENT ) ) + + +def _PytreeNodeRepr( node ): + """Like pytree.Node.__repr__, but names instead of numbers for tokens.""" + if isinstance( node, pytree.Node ): + return '%s(%s, %r)' % ( + node.__class__.__name__, NodeName( node ), + [ _PytreeNodeRepr( c ) for c in node.children ] ) + if isinstance( node, pytree.Leaf ): + return '%s(%s, %r)' % ( node.__class__.__name__, NodeName( node ), node.value ) + + +def IsCommentStatement( node ): + return ( + NodeName( node ) == 'simple_stmt' and node.children[ 0 ].type == token.COMMENT ) diff --git a/yapf/pytree/pytree_visitor.py b/yapf/pytree/pytree_visitor.py index 314431e84..5b816f3e4 100644 --- a/yapf/pytree/pytree_visitor.py +++ b/yapf/pytree/pytree_visitor.py @@ -31,8 +31,8 @@ from yapf.pytree import pytree_utils -class PyTreeVisitor(object): - """Visitor pattern for pytree trees. +class PyTreeVisitor( object ): + """Visitor pattern for pytree trees. Methods named Visit_XXX will be invoked when a node with type XXX is encountered in the tree. The type is either a token type (for Leaf nodes) or @@ -54,42 +54,42 @@ class PyTreeVisitor(object): that may have children - otherwise the children will not be visited. """ - def Visit(self, node): - """Visit a node.""" - method = 'Visit_{0}'.format(pytree_utils.NodeName(node)) - if hasattr(self, method): - # Found a specific visitor for this node - getattr(self, method)(node) - else: - if isinstance(node, pytree.Leaf): - self.DefaultLeafVisit(node) - else: - self.DefaultNodeVisit(node) - - def DefaultNodeVisit(self, node): - """Default visitor for Node: visits the node's children depth-first. + def Visit( self, node ): + """Visit a node.""" + method = 'Visit_{0}'.format( pytree_utils.NodeName( node ) ) + if hasattr( self, method ): + # Found a specific visitor for this node + getattr( self, method )( node ) + else: + if isinstance( node, pytree.Leaf ): + self.DefaultLeafVisit( node ) + else: + self.DefaultNodeVisit( node ) + + def DefaultNodeVisit( self, node ): + """Default visitor for Node: visits the node's children depth-first. This method is invoked when no specific visitor for the node is defined. Arguments: node: the node to visit """ - for child in node.children: - self.Visit(child) + for child in node.children: + self.Visit( child ) - def DefaultLeafVisit(self, leaf): - """Default visitor for Leaf: no-op. + def DefaultLeafVisit( self, leaf ): + """Default visitor for Leaf: no-op. This method is invoked when no specific visitor for the leaf is defined. Arguments: leaf: the leaf to visit """ - pass + pass -def DumpPyTree(tree, target_stream=sys.stdout): - """Convenience function for dumping a given pytree. +def DumpPyTree( tree, target_stream = sys.stdout ): + """Convenience function for dumping a given pytree. This function presents a very minimal interface. For more configurability (for example, controlling how specific node types are displayed), use PyTreeDumper @@ -100,36 +100,36 @@ def DumpPyTree(tree, target_stream=sys.stdout): target_stream: the stream to dump the tree to. A file-like object. By default will dump into stdout. """ - dumper = PyTreeDumper(target_stream) - dumper.Visit(tree) + dumper = PyTreeDumper( target_stream ) + dumper.Visit( tree ) -class PyTreeDumper(PyTreeVisitor): - """Visitor that dumps the tree to a stream. +class PyTreeDumper( PyTreeVisitor ): + """Visitor that dumps the tree to a stream. Implements the PyTreeVisitor interface. """ - def __init__(self, target_stream=sys.stdout): - """Create a tree dumper. + def __init__( self, target_stream = sys.stdout ): + """Create a tree dumper. Arguments: target_stream: the stream to dump the tree to. A file-like object. By default will dump into stdout. """ - self._target_stream = target_stream - self._current_indent = 0 - - def _DumpString(self, s): - self._target_stream.write('{0}{1}\n'.format(' ' * self._current_indent, s)) - - def DefaultNodeVisit(self, node): - # Dump information about the current node, and then use the generic - # DefaultNodeVisit visitor to dump each of its children. - self._DumpString(pytree_utils.DumpNodeToString(node)) - self._current_indent += 2 - super(PyTreeDumper, self).DefaultNodeVisit(node) - self._current_indent -= 2 - - def DefaultLeafVisit(self, leaf): - self._DumpString(pytree_utils.DumpNodeToString(leaf)) + self._target_stream = target_stream + self._current_indent = 0 + + def _DumpString( self, s ): + self._target_stream.write( '{0}{1}\n'.format( ' ' * self._current_indent, s ) ) + + def DefaultNodeVisit( self, node ): + # Dump information about the current node, and then use the generic + # DefaultNodeVisit visitor to dump each of its children. + self._DumpString( pytree_utils.DumpNodeToString( node ) ) + self._current_indent += 2 + super( PyTreeDumper, self ).DefaultNodeVisit( node ) + self._current_indent -= 2 + + def DefaultLeafVisit( self, leaf ): + self._DumpString( pytree_utils.DumpNodeToString( leaf ) ) diff --git a/yapf/pytree/split_penalty.py b/yapf/pytree/split_penalty.py index b53ffbf85..8b5598390 100644 --- a/yapf/pytree/split_penalty.py +++ b/yapf/pytree/split_penalty.py @@ -26,565 +26,574 @@ # TODO(morbo): Document the annotations in a centralized place. E.g., the # README file. -UNBREAKABLE = 1000 * 1000 -NAMED_ASSIGN = 15000 -DOTTED_NAME = 4000 +UNBREAKABLE = 1000 * 1000 +NAMED_ASSIGN = 15000 +DOTTED_NAME = 4000 VERY_STRONGLY_CONNECTED = 3500 -STRONGLY_CONNECTED = 3000 -CONNECTED = 500 -TOGETHER = 100 - -OR_TEST = 1000 -AND_TEST = 1100 -NOT_TEST = 1200 -COMPARISON = 1300 -STAR_EXPR = 1300 -EXPR = 1400 -XOR_EXPR = 1500 -AND_EXPR = 1700 -SHIFT_EXPR = 1800 -ARITH_EXPR = 1900 -TERM = 2000 -FACTOR = 2100 -POWER = 2200 -ATOM = 2300 +STRONGLY_CONNECTED = 3000 +CONNECTED = 500 +TOGETHER = 100 + +OR_TEST = 1000 +AND_TEST = 1100 +NOT_TEST = 1200 +COMPARISON = 1300 +STAR_EXPR = 1300 +EXPR = 1400 +XOR_EXPR = 1500 +AND_EXPR = 1700 +SHIFT_EXPR = 1800 +ARITH_EXPR = 1900 +TERM = 2000 +FACTOR = 2100 +POWER = 2200 +ATOM = 2300 ONE_ELEMENT_ARGUMENT = 500 -SUBSCRIPT = 6000 +SUBSCRIPT = 6000 -def ComputeSplitPenalties(tree): - """Compute split penalties on tokens in the given parse tree. +def ComputeSplitPenalties( tree ): + """Compute split penalties on tokens in the given parse tree. Arguments: tree: the top-level pytree node to annotate with penalties. """ - _SplitPenaltyAssigner().Visit(tree) + _SplitPenaltyAssigner().Visit( tree ) -class _SplitPenaltyAssigner(pytree_visitor.PyTreeVisitor): - """Assigns split penalties to tokens, based on parse tree structure. +class _SplitPenaltyAssigner( pytree_visitor.PyTreeVisitor ): + """Assigns split penalties to tokens, based on parse tree structure. Split penalties are attached as annotations to tokens. """ - def Visit(self, node): - if not hasattr(node, 'is_pseudo'): # Ignore pseudo tokens. - super(_SplitPenaltyAssigner, self).Visit(node) - - def Visit_import_as_names(self, node): # pyline: disable=invalid-name - # import_as_names ::= import_as_name (',' import_as_name)* [','] - self.DefaultNodeVisit(node) - prev_child = None - for child in node.children: - if (prev_child and isinstance(prev_child, pytree.Leaf) and - prev_child.value == ','): - _SetSplitPenalty(child, style.Get('SPLIT_PENALTY_IMPORT_NAMES')) - prev_child = child - - def Visit_classdef(self, node): # pylint: disable=invalid-name - # classdef ::= 'class' NAME ['(' [arglist] ')'] ':' suite - # - # NAME - _SetUnbreakable(node.children[1]) - if len(node.children) > 4: - # opening '(' - _SetUnbreakable(node.children[2]) - # ':' - _SetUnbreakable(node.children[-2]) - self.DefaultNodeVisit(node) - - def Visit_funcdef(self, node): # pylint: disable=invalid-name - # funcdef ::= 'def' NAME parameters ['->' test] ':' suite - # - # Can't break before the function name and before the colon. The parameters - # are handled by child iteration. - colon_idx = 1 - while pytree_utils.NodeName(node.children[colon_idx]) == 'simple_stmt': - colon_idx += 1 - _SetUnbreakable(node.children[colon_idx]) - arrow_idx = -1 - while colon_idx < len(node.children): - if isinstance(node.children[colon_idx], pytree.Leaf): - if node.children[colon_idx].value == ':': - break - if node.children[colon_idx].value == '->': - arrow_idx = colon_idx - colon_idx += 1 - _SetUnbreakable(node.children[colon_idx]) - self.DefaultNodeVisit(node) - if arrow_idx > 0: - _SetSplitPenalty( - pytree_utils.LastLeafNode(node.children[arrow_idx - 1]), 0) - _SetUnbreakable(node.children[arrow_idx]) - _SetStronglyConnected(node.children[arrow_idx + 1]) - - def Visit_lambdef(self, node): # pylint: disable=invalid-name - # lambdef ::= 'lambda' [varargslist] ':' test - # Loop over the lambda up to and including the colon. - allow_multiline_lambdas = style.Get('ALLOW_MULTILINE_LAMBDAS') - if not allow_multiline_lambdas: - for child in node.children: - if child.type == grammar_token.COMMENT: - if re.search(r'pylint:.*disable=.*\bg-long-lambda', child.value): - allow_multiline_lambdas = True - break - - if allow_multiline_lambdas: - _SetExpressionPenalty(node, STRONGLY_CONNECTED) - else: - _SetExpressionPenalty(node, VERY_STRONGLY_CONNECTED) - - def Visit_parameters(self, node): # pylint: disable=invalid-name - # parameters ::= '(' [typedargslist] ')' - self.DefaultNodeVisit(node) - - # Can't break before the opening paren of a parameter list. - _SetUnbreakable(node.children[0]) - if not (style.Get('INDENT_CLOSING_BRACKETS') or - style.Get('DEDENT_CLOSING_BRACKETS')): - _SetStronglyConnected(node.children[-1]) - - def Visit_arglist(self, node): # pylint: disable=invalid-name - # arglist ::= argument (',' argument)* [','] - if node.children[0].type == grammar_token.STAR: - # Python 3 treats a star expression as a specific expression type. - # Process it in that method. - self.Visit_star_expr(node) - return - - self.DefaultNodeVisit(node) - - for index in py3compat.range(1, len(node.children)): - child = node.children[index] - if isinstance(child, pytree.Leaf) and child.value == ',': - _SetUnbreakable(child) - - for child in node.children: - if pytree_utils.NodeName(child) == 'atom': - _IncreasePenalty(child, CONNECTED) - - def Visit_argument(self, node): # pylint: disable=invalid-name - # argument ::= test [comp_for] | test '=' test # Really [keyword '='] test - self.DefaultNodeVisit(node) - - for index in py3compat.range(1, len(node.children) - 1): - child = node.children[index] - if isinstance(child, pytree.Leaf) and child.value == '=': - _SetSplitPenalty( - pytree_utils.FirstLeafNode(node.children[index]), NAMED_ASSIGN) - _SetSplitPenalty( - pytree_utils.FirstLeafNode(node.children[index + 1]), NAMED_ASSIGN) - - def Visit_tname(self, node): # pylint: disable=invalid-name - # tname ::= NAME [':' test] - self.DefaultNodeVisit(node) - - for index in py3compat.range(1, len(node.children) - 1): - child = node.children[index] - if isinstance(child, pytree.Leaf) and child.value == ':': - _SetSplitPenalty( - pytree_utils.FirstLeafNode(node.children[index]), NAMED_ASSIGN) - _SetSplitPenalty( - pytree_utils.FirstLeafNode(node.children[index + 1]), NAMED_ASSIGN) - - def Visit_dotted_name(self, node): # pylint: disable=invalid-name - # dotted_name ::= NAME ('.' NAME)* - for child in node.children: - self.Visit(child) - start = 2 if hasattr(node.children[0], 'is_pseudo') else 1 - for i in py3compat.range(start, len(node.children)): - _SetUnbreakable(node.children[i]) - - def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name - # dictsetmaker ::= ( (test ':' test - # (comp_for | (',' test ':' test)* [','])) | - # (test (comp_for | (',' test)* [','])) ) - for child in node.children: - self.Visit(child) - if child.type == grammar_token.COLON: - # This is a key to a dictionary. We don't want to split the key if at - # all possible. - _SetStronglyConnected(child) - - def Visit_trailer(self, node): # pylint: disable=invalid-name - # trailer ::= '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME - if node.children[0].value == '.': - before = style.Get('SPLIT_BEFORE_DOT') - _SetSplitPenalty(node.children[0], - VERY_STRONGLY_CONNECTED if before else DOTTED_NAME) - _SetSplitPenalty(node.children[1], - DOTTED_NAME if before else VERY_STRONGLY_CONNECTED) - elif len(node.children) == 2: - # Don't split an empty argument list if at all possible. - _SetSplitPenalty(node.children[1], VERY_STRONGLY_CONNECTED) - elif len(node.children) == 3: - name = pytree_utils.NodeName(node.children[1]) - if name in {'argument', 'comparison'}: - # Don't split an argument list with one element if at all possible. - _SetStronglyConnected(node.children[1]) - if (len(node.children[1].children) > 1 and - pytree_utils.NodeName(node.children[1].children[1]) == 'comp_for'): - # Don't penalize splitting before a comp_for expression. - _SetSplitPenalty(pytree_utils.FirstLeafNode(node.children[1]), 0) + def Visit( self, node ): + if not hasattr( node, 'is_pseudo' ): # Ignore pseudo tokens. + super( _SplitPenaltyAssigner, self ).Visit( node ) + + def Visit_import_as_names( self, node ): # pyline: disable=invalid-name + # import_as_names ::= import_as_name (',' import_as_name)* [','] + self.DefaultNodeVisit( node ) + prev_child = None + for child in node.children: + if ( prev_child and isinstance( prev_child, pytree.Leaf ) and + prev_child.value == ',' ): + _SetSplitPenalty( child, style.Get( 'SPLIT_PENALTY_IMPORT_NAMES' ) ) + prev_child = child + + def Visit_classdef( self, node ): # pylint: disable=invalid-name + # classdef ::= 'class' NAME ['(' [arglist] ')'] ':' suite + # + # NAME + _SetUnbreakable( node.children[ 1 ] ) + if len( node.children ) > 4: + # opening '(' + _SetUnbreakable( node.children[ 2 ] ) + # ':' + _SetUnbreakable( node.children[ -2 ] ) + self.DefaultNodeVisit( node ) + + def Visit_funcdef( self, node ): # pylint: disable=invalid-name + # funcdef ::= 'def' NAME parameters ['->' test] ':' suite + # + # Can't break before the function name and before the colon. The parameters + # are handled by child iteration. + colon_idx = 1 + while pytree_utils.NodeName( node.children[ colon_idx ] ) == 'simple_stmt': + colon_idx += 1 + _SetUnbreakable( node.children[ colon_idx ] ) + arrow_idx = -1 + while colon_idx < len( node.children ): + if isinstance( node.children[ colon_idx ], pytree.Leaf ): + if node.children[ colon_idx ].value == ':': + break + if node.children[ colon_idx ].value == '->': + arrow_idx = colon_idx + colon_idx += 1 + _SetUnbreakable( node.children[ colon_idx ] ) + self.DefaultNodeVisit( node ) + if arrow_idx > 0: + _SetSplitPenalty( + pytree_utils.LastLeafNode( node.children[ arrow_idx - 1 ] ), 0 ) + _SetUnbreakable( node.children[ arrow_idx ] ) + _SetStronglyConnected( node.children[ arrow_idx + 1 ] ) + + def Visit_lambdef( self, node ): # pylint: disable=invalid-name + # lambdef ::= 'lambda' [varargslist] ':' test + # Loop over the lambda up to and including the colon. + allow_multiline_lambdas = style.Get( 'ALLOW_MULTILINE_LAMBDAS' ) + if not allow_multiline_lambdas: + for child in node.children: + if child.type == grammar_token.COMMENT: + if re.search( r'pylint:.*disable=.*\bg-long-lambda', child.value ): + allow_multiline_lambdas = True + break + + if allow_multiline_lambdas: + _SetExpressionPenalty( node, STRONGLY_CONNECTED ) else: - _SetSplitPenalty( - pytree_utils.FirstLeafNode(node.children[1]), - ONE_ELEMENT_ARGUMENT) - elif (node.children[0].type == grammar_token.LSQB and - len(node.children[1].children) > 2 and - (name.endswith('_test') or name.endswith('_expr'))): - _SetStronglyConnected(node.children[1].children[0]) - _SetStronglyConnected(node.children[1].children[2]) - - # Still allow splitting around the operator. - split_before = ((name.endswith('_test') and - style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR')) or - (name.endswith('_expr') and - style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'))) - if split_before: - _SetSplitPenalty( - pytree_utils.LastLeafNode(node.children[1].children[1]), 0) - else: - _SetSplitPenalty( - pytree_utils.FirstLeafNode(node.children[1].children[2]), 0) - - # Don't split the ending bracket of a subscript list. - _RecAnnotate(node.children[-1], pytree_utils.Annotation.SPLIT_PENALTY, - VERY_STRONGLY_CONNECTED) - elif name not in { - 'arglist', 'argument', 'term', 'or_test', 'and_test', 'comparison', - 'atom', 'power' - }: - # Don't split an argument list with one element if at all possible. - stypes = pytree_utils.GetNodeAnnotation( - pytree_utils.FirstLeafNode(node), pytree_utils.Annotation.SUBTYPE) - if stypes and subtypes.SUBSCRIPT_BRACKET in stypes: - _IncreasePenalty(node, SUBSCRIPT) - - # Bump up the split penalty for the first part of a subscript. We - # would rather not split there. - _IncreasePenalty(node.children[1], CONNECTED) - else: - _SetStronglyConnected(node.children[1], node.children[2]) - - if name == 'arglist': - _SetStronglyConnected(node.children[-1]) - - self.DefaultNodeVisit(node) - - def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring - # power ::= atom trailer* ['**' factor] - self.DefaultNodeVisit(node) - - # When atom is followed by a trailer, we can not break between them. - # E.g. arr[idx] - no break allowed between 'arr' and '['. - if (len(node.children) > 1 and - pytree_utils.NodeName(node.children[1]) == 'trailer'): - # children[1] itself is a whole trailer: we don't want to - # mark all of it as unbreakable, only its first token: (, [ or . - first = pytree_utils.FirstLeafNode(node.children[1]) - if first.value != '.': - _SetUnbreakable(node.children[1].children[0]) - - # A special case when there are more trailers in the sequence. Given: - # atom tr1 tr2 - # The last token of tr1 and the first token of tr2 comprise an unbreakable - # region. For example: foo.bar.baz(1) - # We can't put breaks between either of the '.', '(', or '[' and the names - # *preceding* them. - prev_trailer_idx = 1 - while prev_trailer_idx < len(node.children) - 1: - cur_trailer_idx = prev_trailer_idx + 1 - cur_trailer = node.children[cur_trailer_idx] - if pytree_utils.NodeName(cur_trailer) != 'trailer': - break - - # Now we know we have two trailers one after the other - prev_trailer = node.children[prev_trailer_idx] - if prev_trailer.children[-1].value != ')': - # Set the previous node unbreakable if it's not a function call: - # atom tr1() tr2 - # It may be necessary (though undesirable) to split up a previous - # function call's parentheses to the next line. - _SetStronglyConnected(prev_trailer.children[-1]) - _SetStronglyConnected(cur_trailer.children[0]) - prev_trailer_idx = cur_trailer_idx - - # We don't want to split before the last ')' of a function call. This also - # takes care of the special case of: - # atom tr1 tr2 ... trn - # where the 'tr#' are trailers that may end in a ')'. - for trailer in node.children[1:]: - if pytree_utils.NodeName(trailer) != 'trailer': - break - if trailer.children[0].value in '([': - if len(trailer.children) > 2: - stypes = pytree_utils.GetNodeAnnotation( - trailer.children[0], pytree_utils.Annotation.SUBTYPE) - if stypes and subtypes.SUBSCRIPT_BRACKET in stypes: - _SetStronglyConnected( - pytree_utils.FirstLeafNode(trailer.children[1])) - - last_child_node = pytree_utils.LastLeafNode(trailer) - if last_child_node.value.strip().startswith('#'): - last_child_node = last_child_node.prev_sibling - if not (style.Get('INDENT_CLOSING_BRACKETS') or - style.Get('DEDENT_CLOSING_BRACKETS')): - last = pytree_utils.LastLeafNode(last_child_node.prev_sibling) - if last.value != ',': - if last_child_node.value == ']': - _SetUnbreakable(last_child_node) - else: - _SetSplitPenalty(last_child_node, VERY_STRONGLY_CONNECTED) - else: - # If the trailer's children are '()', then make it a strongly - # connected region. It's sometimes necessary, though undesirable, to - # split the two. - _SetStronglyConnected(trailer.children[-1]) - - def Visit_subscriptlist(self, node): # pylint: disable=invalid-name - # subscriptlist ::= subscript (',' subscript)* [','] - self.DefaultNodeVisit(node) - _SetSplitPenalty(pytree_utils.FirstLeafNode(node), 0) - prev_child = None - for child in node.children: - if prev_child and prev_child.type == grammar_token.COMMA: - _SetSplitPenalty(pytree_utils.FirstLeafNode(child), 0) - prev_child = child - - def Visit_subscript(self, node): # pylint: disable=invalid-name - # subscript ::= test | [test] ':' [test] [sliceop] - _SetStronglyConnected(*node.children) - self.DefaultNodeVisit(node) - - def Visit_comp_for(self, node): # pylint: disable=invalid-name - # comp_for ::= 'for' exprlist 'in' testlist_safe [comp_iter] - _SetSplitPenalty(pytree_utils.FirstLeafNode(node), 0) - _SetStronglyConnected(*node.children[1:]) - self.DefaultNodeVisit(node) - - def Visit_old_comp_for(self, node): # pylint: disable=invalid-name - # Python 3.7 - self.Visit_comp_for(node) - - def Visit_comp_if(self, node): # pylint: disable=invalid-name - # comp_if ::= 'if' old_test [comp_iter] - _SetSplitPenalty(node.children[0], - style.Get('SPLIT_PENALTY_BEFORE_IF_EXPR')) - _SetStronglyConnected(*node.children[1:]) - self.DefaultNodeVisit(node) - - def Visit_old_comp_if(self, node): # pylint: disable=invalid-name - # Python 3.7 - self.Visit_comp_if(node) - - def Visit_test(self, node): # pylint: disable=invalid-name - # test ::= or_test ['if' or_test 'else' test] | lambdef - _IncreasePenalty(node, OR_TEST) - self.DefaultNodeVisit(node) - - def Visit_or_test(self, node): # pylint: disable=invalid-name - # or_test ::= and_test ('or' and_test)* - self.DefaultNodeVisit(node) - _IncreasePenalty(node, OR_TEST) - index = 1 - while index + 1 < len(node.children): - if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'): - _DecrementSplitPenalty( - pytree_utils.FirstLeafNode(node.children[index]), OR_TEST) - else: - _DecrementSplitPenalty( - pytree_utils.FirstLeafNode(node.children[index + 1]), OR_TEST) - index += 2 - - def Visit_and_test(self, node): # pylint: disable=invalid-name - # and_test ::= not_test ('and' not_test)* - self.DefaultNodeVisit(node) - _IncreasePenalty(node, AND_TEST) - index = 1 - while index + 1 < len(node.children): - if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'): - _DecrementSplitPenalty( - pytree_utils.FirstLeafNode(node.children[index]), AND_TEST) - else: - _DecrementSplitPenalty( - pytree_utils.FirstLeafNode(node.children[index + 1]), AND_TEST) - index += 2 - - def Visit_not_test(self, node): # pylint: disable=invalid-name - # not_test ::= 'not' not_test | comparison - self.DefaultNodeVisit(node) - _IncreasePenalty(node, NOT_TEST) - - def Visit_comparison(self, node): # pylint: disable=invalid-name - # comparison ::= expr (comp_op expr)* - self.DefaultNodeVisit(node) - if len(node.children) == 3 and _StronglyConnectedCompOp(node): - _IncreasePenalty(node.children[1], VERY_STRONGLY_CONNECTED) - _SetSplitPenalty( - pytree_utils.FirstLeafNode(node.children[2]), STRONGLY_CONNECTED) - else: - _IncreasePenalty(node, COMPARISON) - - def Visit_star_expr(self, node): # pylint: disable=invalid-name - # star_expr ::= '*' expr - self.DefaultNodeVisit(node) - _IncreasePenalty(node, STAR_EXPR) - - def Visit_expr(self, node): # pylint: disable=invalid-name - # expr ::= xor_expr ('|' xor_expr)* - self.DefaultNodeVisit(node) - _IncreasePenalty(node, EXPR) - _SetBitwiseOperandPenalty(node, '|') - - def Visit_xor_expr(self, node): # pylint: disable=invalid-name - # xor_expr ::= and_expr ('^' and_expr)* - self.DefaultNodeVisit(node) - _IncreasePenalty(node, XOR_EXPR) - _SetBitwiseOperandPenalty(node, '^') - - def Visit_and_expr(self, node): # pylint: disable=invalid-name - # and_expr ::= shift_expr ('&' shift_expr)* - self.DefaultNodeVisit(node) - _IncreasePenalty(node, AND_EXPR) - _SetBitwiseOperandPenalty(node, '&') - - def Visit_shift_expr(self, node): # pylint: disable=invalid-name - # shift_expr ::= arith_expr (('<<'|'>>') arith_expr)* - self.DefaultNodeVisit(node) - _IncreasePenalty(node, SHIFT_EXPR) - - _ARITH_OPS = frozenset({'PLUS', 'MINUS'}) - - def Visit_arith_expr(self, node): # pylint: disable=invalid-name - # arith_expr ::= term (('+'|'-') term)* - self.DefaultNodeVisit(node) - _IncreasePenalty(node, ARITH_EXPR) - _SetExpressionOperandPenalty(node, self._ARITH_OPS) - - _TERM_OPS = frozenset({'STAR', 'AT', 'SLASH', 'PERCENT', 'DOUBLESLASH'}) - - def Visit_term(self, node): # pylint: disable=invalid-name - # term ::= factor (('*'|'@'|'/'|'%'|'//') factor)* - self.DefaultNodeVisit(node) - _IncreasePenalty(node, TERM) - _SetExpressionOperandPenalty(node, self._TERM_OPS) - - def Visit_factor(self, node): # pyline: disable=invalid-name - # factor ::= ('+'|'-'|'~') factor | power - self.DefaultNodeVisit(node) - _IncreasePenalty(node, FACTOR) - - def Visit_atom(self, node): # pylint: disable=invalid-name - # atom ::= ('(' [yield_expr|testlist_gexp] ')' - # '[' [listmaker] ']' | - # '{' [dictsetmaker] '}') - self.DefaultNodeVisit(node) - if (node.children[0].value == '(' and - not hasattr(node.children[0], 'is_pseudo')): - if node.children[-1].value == ')': - if pytree_utils.NodeName(node.parent) == 'if_stmt': - _SetSplitPenalty(node.children[-1], STRONGLY_CONNECTED) + _SetExpressionPenalty( node, VERY_STRONGLY_CONNECTED ) + + def Visit_parameters( self, node ): # pylint: disable=invalid-name + # parameters ::= '(' [typedargslist] ')' + self.DefaultNodeVisit( node ) + + # Can't break before the opening paren of a parameter list. + _SetUnbreakable( node.children[ 0 ] ) + if not ( style.Get( 'INDENT_CLOSING_BRACKETS' ) or + style.Get( 'DEDENT_CLOSING_BRACKETS' ) ): + _SetStronglyConnected( node.children[ -1 ] ) + + def Visit_arglist( self, node ): # pylint: disable=invalid-name + # arglist ::= argument (',' argument)* [','] + if node.children[ 0 ].type == grammar_token.STAR: + # Python 3 treats a star expression as a specific expression type. + # Process it in that method. + self.Visit_star_expr( node ) + return + + self.DefaultNodeVisit( node ) + + for index in py3compat.range( 1, len( node.children ) ): + child = node.children[ index ] + if isinstance( child, pytree.Leaf ) and child.value == ',': + _SetUnbreakable( child ) + + for child in node.children: + if pytree_utils.NodeName( child ) == 'atom': + _IncreasePenalty( child, CONNECTED ) + + def Visit_argument( self, node ): # pylint: disable=invalid-name + # argument ::= test [comp_for] | test '=' test # Really [keyword '='] test + self.DefaultNodeVisit( node ) + + for index in py3compat.range( 1, len( node.children ) - 1 ): + child = node.children[ index ] + if isinstance( child, pytree.Leaf ) and child.value == '=': + _SetSplitPenalty( + pytree_utils.FirstLeafNode( node.children[ index ] ), NAMED_ASSIGN ) + _SetSplitPenalty( + pytree_utils.FirstLeafNode( node.children[ index + 1 ] ), + NAMED_ASSIGN ) + + def Visit_tname( self, node ): # pylint: disable=invalid-name + # tname ::= NAME [':' test] + self.DefaultNodeVisit( node ) + + for index in py3compat.range( 1, len( node.children ) - 1 ): + child = node.children[ index ] + if isinstance( child, pytree.Leaf ) and child.value == ':': + _SetSplitPenalty( + pytree_utils.FirstLeafNode( node.children[ index ] ), NAMED_ASSIGN ) + _SetSplitPenalty( + pytree_utils.FirstLeafNode( node.children[ index + 1 ] ), + NAMED_ASSIGN ) + + def Visit_dotted_name( self, node ): # pylint: disable=invalid-name + # dotted_name ::= NAME ('.' NAME)* + for child in node.children: + self.Visit( child ) + start = 2 if hasattr( node.children[ 0 ], 'is_pseudo' ) else 1 + for i in py3compat.range( start, len( node.children ) ): + _SetUnbreakable( node.children[ i ] ) + + def Visit_dictsetmaker( self, node ): # pylint: disable=invalid-name + # dictsetmaker ::= ( (test ':' test + # (comp_for | (',' test ':' test)* [','])) | + # (test (comp_for | (',' test)* [','])) ) + for child in node.children: + self.Visit( child ) + if child.type == grammar_token.COLON: + # This is a key to a dictionary. We don't want to split the key if at + # all possible. + _SetStronglyConnected( child ) + + def Visit_trailer( self, node ): # pylint: disable=invalid-name + # trailer ::= '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME + if node.children[ 0 ].value == '.': + before = style.Get( 'SPLIT_BEFORE_DOT' ) + _SetSplitPenalty( + node.children[ 0 ], VERY_STRONGLY_CONNECTED if before else DOTTED_NAME ) + _SetSplitPenalty( + node.children[ 1 ], DOTTED_NAME if before else VERY_STRONGLY_CONNECTED ) + elif len( node.children ) == 2: + # Don't split an empty argument list if at all possible. + _SetSplitPenalty( node.children[ 1 ], VERY_STRONGLY_CONNECTED ) + elif len( node.children ) == 3: + name = pytree_utils.NodeName( node.children[ 1 ] ) + if name in { 'argument', 'comparison' }: + # Don't split an argument list with one element if at all possible. + _SetStronglyConnected( node.children[ 1 ] ) + if ( len( node.children[ 1 ].children ) > 1 and pytree_utils.NodeName( + node.children[ 1 ].children[ 1 ] ) == 'comp_for' ): + # Don't penalize splitting before a comp_for expression. + _SetSplitPenalty( + pytree_utils.FirstLeafNode( node.children[ 1 ] ), 0 ) + else: + _SetSplitPenalty( + pytree_utils.FirstLeafNode( node.children[ 1 ] ), + ONE_ELEMENT_ARGUMENT ) + elif ( node.children[ 0 ].type == grammar_token.LSQB and + len( node.children[ 1 ].children ) > 2 and + ( name.endswith( '_test' ) or name.endswith( '_expr' ) ) ): + _SetStronglyConnected( node.children[ 1 ].children[ 0 ] ) + _SetStronglyConnected( node.children[ 1 ].children[ 2 ] ) + + # Still allow splitting around the operator. + split_before = ( + ( + name.endswith( '_test' ) and + style.Get( 'SPLIT_BEFORE_LOGICAL_OPERATOR' ) ) or ( + name.endswith( '_expr' ) and + style.Get( 'SPLIT_BEFORE_BITWISE_OPERATOR' ) ) ) + if split_before: + _SetSplitPenalty( + pytree_utils.LastLeafNode( node.children[ 1 ].children[ 1 ] ), + 0 ) + else: + _SetSplitPenalty( + pytree_utils.FirstLeafNode( node.children[ 1 ].children[ 2 ] ), + 0 ) + + # Don't split the ending bracket of a subscript list. + _RecAnnotate( + node.children[ -1 ], pytree_utils.Annotation.SPLIT_PENALTY, + VERY_STRONGLY_CONNECTED ) + elif name not in { 'arglist', 'argument', 'term', 'or_test', 'and_test', + 'comparison', 'atom', 'power' }: + # Don't split an argument list with one element if at all possible. + stypes = pytree_utils.GetNodeAnnotation( + pytree_utils.FirstLeafNode( node ), + pytree_utils.Annotation.SUBTYPE ) + if stypes and subtypes.SUBSCRIPT_BRACKET in stypes: + _IncreasePenalty( node, SUBSCRIPT ) + + # Bump up the split penalty for the first part of a subscript. We + # would rather not split there. + _IncreasePenalty( node.children[ 1 ], CONNECTED ) + else: + _SetStronglyConnected( node.children[ 1 ], node.children[ 2 ] ) + + if name == 'arglist': + _SetStronglyConnected( node.children[ -1 ] ) + + self.DefaultNodeVisit( node ) + + def Visit_power( self, node ): # pylint: disable=invalid-name,missing-docstring + # power ::= atom trailer* ['**' factor] + self.DefaultNodeVisit( node ) + + # When atom is followed by a trailer, we can not break between them. + # E.g. arr[idx] - no break allowed between 'arr' and '['. + if ( len( node.children ) > 1 and + pytree_utils.NodeName( node.children[ 1 ] ) == 'trailer' ): + # children[1] itself is a whole trailer: we don't want to + # mark all of it as unbreakable, only its first token: (, [ or . + first = pytree_utils.FirstLeafNode( node.children[ 1 ] ) + if first.value != '.': + _SetUnbreakable( node.children[ 1 ].children[ 0 ] ) + + # A special case when there are more trailers in the sequence. Given: + # atom tr1 tr2 + # The last token of tr1 and the first token of tr2 comprise an unbreakable + # region. For example: foo.bar.baz(1) + # We can't put breaks between either of the '.', '(', or '[' and the names + # *preceding* them. + prev_trailer_idx = 1 + while prev_trailer_idx < len( node.children ) - 1: + cur_trailer_idx = prev_trailer_idx + 1 + cur_trailer = node.children[ cur_trailer_idx ] + if pytree_utils.NodeName( cur_trailer ) != 'trailer': + break + + # Now we know we have two trailers one after the other + prev_trailer = node.children[ prev_trailer_idx ] + if prev_trailer.children[ -1 ].value != ')': + # Set the previous node unbreakable if it's not a function call: + # atom tr1() tr2 + # It may be necessary (though undesirable) to split up a previous + # function call's parentheses to the next line. + _SetStronglyConnected( prev_trailer.children[ -1 ] ) + _SetStronglyConnected( cur_trailer.children[ 0 ] ) + prev_trailer_idx = cur_trailer_idx + + # We don't want to split before the last ')' of a function call. This also + # takes care of the special case of: + # atom tr1 tr2 ... trn + # where the 'tr#' are trailers that may end in a ')'. + for trailer in node.children[ 1 : ]: + if pytree_utils.NodeName( trailer ) != 'trailer': + break + if trailer.children[ 0 ].value in '([': + if len( trailer.children ) > 2: + stypes = pytree_utils.GetNodeAnnotation( + trailer.children[ 0 ], pytree_utils.Annotation.SUBTYPE ) + if stypes and subtypes.SUBSCRIPT_BRACKET in stypes: + _SetStronglyConnected( + pytree_utils.FirstLeafNode( trailer.children[ 1 ] ) ) + + last_child_node = pytree_utils.LastLeafNode( trailer ) + if last_child_node.value.strip().startswith( '#' ): + last_child_node = last_child_node.prev_sibling + if not ( style.Get( 'INDENT_CLOSING_BRACKETS' ) or + style.Get( 'DEDENT_CLOSING_BRACKETS' ) ): + last = pytree_utils.LastLeafNode( last_child_node.prev_sibling ) + if last.value != ',': + if last_child_node.value == ']': + _SetUnbreakable( last_child_node ) + else: + _SetSplitPenalty( + last_child_node, VERY_STRONGLY_CONNECTED ) + else: + # If the trailer's children are '()', then make it a strongly + # connected region. It's sometimes necessary, though undesirable, to + # split the two. + _SetStronglyConnected( trailer.children[ -1 ] ) + + def Visit_subscriptlist( self, node ): # pylint: disable=invalid-name + # subscriptlist ::= subscript (',' subscript)* [','] + self.DefaultNodeVisit( node ) + _SetSplitPenalty( pytree_utils.FirstLeafNode( node ), 0 ) + prev_child = None + for child in node.children: + if prev_child and prev_child.type == grammar_token.COMMA: + _SetSplitPenalty( pytree_utils.FirstLeafNode( child ), 0 ) + prev_child = child + + def Visit_subscript( self, node ): # pylint: disable=invalid-name + # subscript ::= test | [test] ':' [test] [sliceop] + _SetStronglyConnected( *node.children ) + self.DefaultNodeVisit( node ) + + def Visit_comp_for( self, node ): # pylint: disable=invalid-name + # comp_for ::= 'for' exprlist 'in' testlist_safe [comp_iter] + _SetSplitPenalty( pytree_utils.FirstLeafNode( node ), 0 ) + _SetStronglyConnected( *node.children[ 1 : ] ) + self.DefaultNodeVisit( node ) + + def Visit_old_comp_for( self, node ): # pylint: disable=invalid-name + # Python 3.7 + self.Visit_comp_for( node ) + + def Visit_comp_if( self, node ): # pylint: disable=invalid-name + # comp_if ::= 'if' old_test [comp_iter] + _SetSplitPenalty( + node.children[ 0 ], style.Get( 'SPLIT_PENALTY_BEFORE_IF_EXPR' ) ) + _SetStronglyConnected( *node.children[ 1 : ] ) + self.DefaultNodeVisit( node ) + + def Visit_old_comp_if( self, node ): # pylint: disable=invalid-name + # Python 3.7 + self.Visit_comp_if( node ) + + def Visit_test( self, node ): # pylint: disable=invalid-name + # test ::= or_test ['if' or_test 'else' test] | lambdef + _IncreasePenalty( node, OR_TEST ) + self.DefaultNodeVisit( node ) + + def Visit_or_test( self, node ): # pylint: disable=invalid-name + # or_test ::= and_test ('or' and_test)* + self.DefaultNodeVisit( node ) + _IncreasePenalty( node, OR_TEST ) + index = 1 + while index + 1 < len( node.children ): + if style.Get( 'SPLIT_BEFORE_LOGICAL_OPERATOR' ): + _DecrementSplitPenalty( + pytree_utils.FirstLeafNode( node.children[ index ] ), OR_TEST ) + else: + _DecrementSplitPenalty( + pytree_utils.FirstLeafNode( node.children[ index + 1 ] ), OR_TEST ) + index += 2 + + def Visit_and_test( self, node ): # pylint: disable=invalid-name + # and_test ::= not_test ('and' not_test)* + self.DefaultNodeVisit( node ) + _IncreasePenalty( node, AND_TEST ) + index = 1 + while index + 1 < len( node.children ): + if style.Get( 'SPLIT_BEFORE_LOGICAL_OPERATOR' ): + _DecrementSplitPenalty( + pytree_utils.FirstLeafNode( node.children[ index ] ), AND_TEST ) + else: + _DecrementSplitPenalty( + pytree_utils.FirstLeafNode( node.children[ index + 1 ] ), AND_TEST ) + index += 2 + + def Visit_not_test( self, node ): # pylint: disable=invalid-name + # not_test ::= 'not' not_test | comparison + self.DefaultNodeVisit( node ) + _IncreasePenalty( node, NOT_TEST ) + + def Visit_comparison( self, node ): # pylint: disable=invalid-name + # comparison ::= expr (comp_op expr)* + self.DefaultNodeVisit( node ) + if len( node.children ) == 3 and _StronglyConnectedCompOp( node ): + _IncreasePenalty( node.children[ 1 ], VERY_STRONGLY_CONNECTED ) + _SetSplitPenalty( + pytree_utils.FirstLeafNode( node.children[ 2 ] ), STRONGLY_CONNECTED ) else: - if len(node.children) > 2: - _SetSplitPenalty(pytree_utils.FirstLeafNode(node.children[1]), EXPR) - _SetSplitPenalty(node.children[-1], ATOM) - elif node.children[0].value in '[{' and len(node.children) == 2: - # Keep empty containers together if we can. - _SetUnbreakable(node.children[-1]) - - def Visit_testlist_gexp(self, node): # pylint: disable=invalid-name - self.DefaultNodeVisit(node) - prev_was_comma = False - for child in node.children: - if isinstance(child, pytree.Leaf) and child.value == ',': - _SetUnbreakable(child) - prev_was_comma = True - else: - if prev_was_comma: - _SetSplitPenalty(pytree_utils.FirstLeafNode(child), TOGETHER) + _IncreasePenalty( node, COMPARISON ) + + def Visit_star_expr( self, node ): # pylint: disable=invalid-name + # star_expr ::= '*' expr + self.DefaultNodeVisit( node ) + _IncreasePenalty( node, STAR_EXPR ) + + def Visit_expr( self, node ): # pylint: disable=invalid-name + # expr ::= xor_expr ('|' xor_expr)* + self.DefaultNodeVisit( node ) + _IncreasePenalty( node, EXPR ) + _SetBitwiseOperandPenalty( node, '|' ) + + def Visit_xor_expr( self, node ): # pylint: disable=invalid-name + # xor_expr ::= and_expr ('^' and_expr)* + self.DefaultNodeVisit( node ) + _IncreasePenalty( node, XOR_EXPR ) + _SetBitwiseOperandPenalty( node, '^' ) + + def Visit_and_expr( self, node ): # pylint: disable=invalid-name + # and_expr ::= shift_expr ('&' shift_expr)* + self.DefaultNodeVisit( node ) + _IncreasePenalty( node, AND_EXPR ) + _SetBitwiseOperandPenalty( node, '&' ) + + def Visit_shift_expr( self, node ): # pylint: disable=invalid-name + # shift_expr ::= arith_expr (('<<'|'>>') arith_expr)* + self.DefaultNodeVisit( node ) + _IncreasePenalty( node, SHIFT_EXPR ) + + _ARITH_OPS = frozenset( { 'PLUS', 'MINUS' } ) + + def Visit_arith_expr( self, node ): # pylint: disable=invalid-name + # arith_expr ::= term (('+'|'-') term)* + self.DefaultNodeVisit( node ) + _IncreasePenalty( node, ARITH_EXPR ) + _SetExpressionOperandPenalty( node, self._ARITH_OPS ) + + _TERM_OPS = frozenset( { 'STAR', 'AT', 'SLASH', 'PERCENT', 'DOUBLESLASH' } ) + + def Visit_term( self, node ): # pylint: disable=invalid-name + # term ::= factor (('*'|'@'|'/'|'%'|'//') factor)* + self.DefaultNodeVisit( node ) + _IncreasePenalty( node, TERM ) + _SetExpressionOperandPenalty( node, self._TERM_OPS ) + + def Visit_factor( self, node ): # pyline: disable=invalid-name + # factor ::= ('+'|'-'|'~') factor | power + self.DefaultNodeVisit( node ) + _IncreasePenalty( node, FACTOR ) + + def Visit_atom( self, node ): # pylint: disable=invalid-name + # atom ::= ('(' [yield_expr|testlist_gexp] ')' + # '[' [listmaker] ']' | + # '{' [dictsetmaker] '}') + self.DefaultNodeVisit( node ) + if ( node.children[ 0 ].value == '(' and + not hasattr( node.children[ 0 ], 'is_pseudo' ) ): + if node.children[ -1 ].value == ')': + if pytree_utils.NodeName( node.parent ) == 'if_stmt': + _SetSplitPenalty( node.children[ -1 ], STRONGLY_CONNECTED ) + else: + if len( node.children ) > 2: + _SetSplitPenalty( + pytree_utils.FirstLeafNode( node.children[ 1 ] ), EXPR ) + _SetSplitPenalty( node.children[ -1 ], ATOM ) + elif node.children[ 0 ].value in '[{' and len( node.children ) == 2: + # Keep empty containers together if we can. + _SetUnbreakable( node.children[ -1 ] ) + + def Visit_testlist_gexp( self, node ): # pylint: disable=invalid-name + self.DefaultNodeVisit( node ) prev_was_comma = False + for child in node.children: + if isinstance( child, pytree.Leaf ) and child.value == ',': + _SetUnbreakable( child ) + prev_was_comma = True + else: + if prev_was_comma: + _SetSplitPenalty( pytree_utils.FirstLeafNode( child ), TOGETHER ) + prev_was_comma = False -def _SetUnbreakable(node): - """Set an UNBREAKABLE penalty annotation for the given node.""" - _RecAnnotate(node, pytree_utils.Annotation.SPLIT_PENALTY, UNBREAKABLE) - - -def _SetStronglyConnected(*nodes): - """Set a STRONGLY_CONNECTED penalty annotation for the given nodes.""" - for node in nodes: - _RecAnnotate(node, pytree_utils.Annotation.SPLIT_PENALTY, - STRONGLY_CONNECTED) +def _SetUnbreakable( node ): + """Set an UNBREAKABLE penalty annotation for the given node.""" + _RecAnnotate( node, pytree_utils.Annotation.SPLIT_PENALTY, UNBREAKABLE ) -def _SetExpressionPenalty(node, penalty): - """Set a penalty annotation on children nodes.""" +def _SetStronglyConnected( *nodes ): + """Set a STRONGLY_CONNECTED penalty annotation for the given nodes.""" + for node in nodes: + _RecAnnotate( node, pytree_utils.Annotation.SPLIT_PENALTY, STRONGLY_CONNECTED ) - def RecExpression(node, first_child_leaf): - if node is first_child_leaf: - return - if isinstance(node, pytree.Leaf): - if node.value in {'(', 'for', 'if'}: - return - penalty_annotation = pytree_utils.GetNodeAnnotation( - node, pytree_utils.Annotation.SPLIT_PENALTY, default=0) - if penalty_annotation < penalty: - _SetSplitPenalty(node, penalty) - else: - for child in node.children: - RecExpression(child, first_child_leaf) +def _SetExpressionPenalty( node, penalty ): + """Set a penalty annotation on children nodes.""" - RecExpression(node, pytree_utils.FirstLeafNode(node)) + def RecExpression( node, first_child_leaf ): + if node is first_child_leaf: + return + if isinstance( node, pytree.Leaf ): + if node.value in { '(', 'for', 'if' }: + return + penalty_annotation = pytree_utils.GetNodeAnnotation( + node, pytree_utils.Annotation.SPLIT_PENALTY, default = 0 ) + if penalty_annotation < penalty: + _SetSplitPenalty( node, penalty ) + else: + for child in node.children: + RecExpression( child, first_child_leaf ) + + RecExpression( node, pytree_utils.FirstLeafNode( node ) ) + + +def _SetBitwiseOperandPenalty( node, op ): + for index in py3compat.range( 1, len( node.children ) - 1 ): + child = node.children[ index ] + if isinstance( child, pytree.Leaf ) and child.value == op: + if style.Get( 'SPLIT_BEFORE_BITWISE_OPERATOR' ): + _SetSplitPenalty( child, style.Get( 'SPLIT_PENALTY_BITWISE_OPERATOR' ) ) + else: + _SetSplitPenalty( + pytree_utils.FirstLeafNode( node.children[ index + 1 ] ), + style.Get( 'SPLIT_PENALTY_BITWISE_OPERATOR' ) ) + + +def _SetExpressionOperandPenalty( node, ops ): + for index in py3compat.range( 1, len( node.children ) - 1 ): + child = node.children[ index ] + if pytree_utils.NodeName( child ) in ops: + if style.Get( 'SPLIT_BEFORE_ARITHMETIC_OPERATOR' ): + _SetSplitPenalty( + child, style.Get( 'SPLIT_PENALTY_ARITHMETIC_OPERATOR' ) ) + else: + _SetSplitPenalty( + pytree_utils.FirstLeafNode( node.children[ index + 1 ] ), + style.Get( 'SPLIT_PENALTY_ARITHMETIC_OPERATOR' ) ) + + +def _IncreasePenalty( node, amt ): + """Increase a penalty annotation on children nodes.""" + + def RecExpression( node, first_child_leaf ): + if node is first_child_leaf: + return + + if isinstance( node, pytree.Leaf ): + if node.value in { '(', 'for' }: + return + penalty = pytree_utils.GetNodeAnnotation( + node, pytree_utils.Annotation.SPLIT_PENALTY, default = 0 ) + _SetSplitPenalty( node, penalty + amt ) + else: + for child in node.children: + RecExpression( child, first_child_leaf ) -def _SetBitwiseOperandPenalty(node, op): - for index in py3compat.range(1, len(node.children) - 1): - child = node.children[index] - if isinstance(child, pytree.Leaf) and child.value == op: - if style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'): - _SetSplitPenalty(child, style.Get('SPLIT_PENALTY_BITWISE_OPERATOR')) - else: - _SetSplitPenalty( - pytree_utils.FirstLeafNode(node.children[index + 1]), - style.Get('SPLIT_PENALTY_BITWISE_OPERATOR')) - - -def _SetExpressionOperandPenalty(node, ops): - for index in py3compat.range(1, len(node.children) - 1): - child = node.children[index] - if pytree_utils.NodeName(child) in ops: - if style.Get('SPLIT_BEFORE_ARITHMETIC_OPERATOR'): - _SetSplitPenalty(child, style.Get('SPLIT_PENALTY_ARITHMETIC_OPERATOR')) - else: - _SetSplitPenalty( - pytree_utils.FirstLeafNode(node.children[index + 1]), - style.Get('SPLIT_PENALTY_ARITHMETIC_OPERATOR')) - - -def _IncreasePenalty(node, amt): - """Increase a penalty annotation on children nodes.""" - - def RecExpression(node, first_child_leaf): - if node is first_child_leaf: - return - - if isinstance(node, pytree.Leaf): - if node.value in {'(', 'for'}: - return - penalty = pytree_utils.GetNodeAnnotation( - node, pytree_utils.Annotation.SPLIT_PENALTY, default=0) - _SetSplitPenalty(node, penalty + amt) - else: - for child in node.children: - RecExpression(child, first_child_leaf) - - RecExpression(node, pytree_utils.FirstLeafNode(node)) + RecExpression( node, pytree_utils.FirstLeafNode( node ) ) -def _RecAnnotate(tree, annotate_name, annotate_value): - """Recursively set the given annotation on all leafs of the subtree. +def _RecAnnotate( tree, annotate_name, annotate_value ): + """Recursively set the given annotation on all leafs of the subtree. Takes care to only increase the penalty. If the node already has a higher or equal penalty associated with it, this is a no-op. @@ -594,40 +603,40 @@ def _RecAnnotate(tree, annotate_name, annotate_value): annotate_name: name of the annotation to set annotate_value: value of the annotation to set """ - for child in tree.children: - _RecAnnotate(child, annotate_name, annotate_value) - if isinstance(tree, pytree.Leaf): - cur_annotate = pytree_utils.GetNodeAnnotation( - tree, annotate_name, default=0) - if cur_annotate < annotate_value: - pytree_utils.SetNodeAnnotation(tree, annotate_name, annotate_value) - - -_COMP_OPS = frozenset({'==', '!=', '<=', '<', '>', '>=', '<>', 'in', 'is'}) - - -def _StronglyConnectedCompOp(op): - if (len(op.children[1].children) == 2 and - pytree_utils.NodeName(op.children[1]) == 'comp_op'): - if (pytree_utils.FirstLeafNode(op.children[1]).value == 'not' and - pytree_utils.LastLeafNode(op.children[1]).value == 'in'): - return True - if (pytree_utils.FirstLeafNode(op.children[1]).value == 'is' and - pytree_utils.LastLeafNode(op.children[1]).value == 'not'): - return True - if (isinstance(op.children[1], pytree.Leaf) and - op.children[1].value in _COMP_OPS): - return True - return False - - -def _DecrementSplitPenalty(node, amt): - penalty = pytree_utils.GetNodeAnnotation( - node, pytree_utils.Annotation.SPLIT_PENALTY, default=amt) - penalty = penalty - amt if amt < penalty else 0 - _SetSplitPenalty(node, penalty) - - -def _SetSplitPenalty(node, penalty): - pytree_utils.SetNodeAnnotation(node, pytree_utils.Annotation.SPLIT_PENALTY, - penalty) + for child in tree.children: + _RecAnnotate( child, annotate_name, annotate_value ) + if isinstance( tree, pytree.Leaf ): + cur_annotate = pytree_utils.GetNodeAnnotation( + tree, annotate_name, default = 0 ) + if cur_annotate < annotate_value: + pytree_utils.SetNodeAnnotation( tree, annotate_name, annotate_value ) + + +_COMP_OPS = frozenset( { '==', '!=', '<=', '<', '>', '>=', '<>', 'in', 'is' } ) + + +def _StronglyConnectedCompOp( op ): + if ( len( op.children[ 1 ].children ) == 2 and + pytree_utils.NodeName( op.children[ 1 ] ) == 'comp_op' ): + if ( pytree_utils.FirstLeafNode( op.children[ 1 ] ).value == 'not' and + pytree_utils.LastLeafNode( op.children[ 1 ] ).value == 'in' ): + return True + if ( pytree_utils.FirstLeafNode( op.children[ 1 ] ).value == 'is' and + pytree_utils.LastLeafNode( op.children[ 1 ] ).value == 'not' ): + return True + if ( isinstance( op.children[ 1 ], pytree.Leaf ) and + op.children[ 1 ].value in _COMP_OPS ): + return True + return False + + +def _DecrementSplitPenalty( node, amt ): + penalty = pytree_utils.GetNodeAnnotation( + node, pytree_utils.Annotation.SPLIT_PENALTY, default = amt ) + penalty = penalty - amt if amt < penalty else 0 + _SetSplitPenalty( node, penalty ) + + +def _SetSplitPenalty( node, penalty ): + pytree_utils.SetNodeAnnotation( + node, pytree_utils.Annotation.SPLIT_PENALTY, penalty ) diff --git a/yapf/pytree/subtype_assigner.py b/yapf/pytree/subtype_assigner.py index 0ee247a82..19c65b323 100644 --- a/yapf/pytree/subtype_assigner.py +++ b/yapf/pytree/subtype_assigner.py @@ -34,14 +34,14 @@ from yapf.yapflib import subtypes -def AssignSubtypes(tree): - """Run the subtype assigner visitor over the tree, modifying it in place. +def AssignSubtypes( tree ): + """Run the subtype assigner visitor over the tree, modifying it in place. Arguments: tree: the top-level pytree node to annotate with subtypes. """ - subtype_assigner = _SubtypeAssigner() - subtype_assigner.Visit(tree) + subtype_assigner = _SubtypeAssigner() + subtype_assigner.Visit( tree ) # Map tokens in argument lists to their respective subtype. @@ -53,447 +53,448 @@ def AssignSubtypes(tree): } -class _SubtypeAssigner(pytree_visitor.PyTreeVisitor): - """_SubtypeAssigner - see file-level docstring for detailed description. +class _SubtypeAssigner( pytree_visitor.PyTreeVisitor ): + """_SubtypeAssigner - see file-level docstring for detailed description. The subtype is added as an annotation to the pytree token. """ - def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name - # dictsetmaker ::= (test ':' test (comp_for | - # (',' test ':' test)* [','])) | - # (test (comp_for | (',' test)* [','])) - for child in node.children: - self.Visit(child) - - comp_for = False - dict_maker = False - - for child in node.children: - if pytree_utils.NodeName(child) == 'comp_for': - comp_for = True - _AppendFirstLeafTokenSubtype(child, subtypes.DICT_SET_GENERATOR) - elif child.type in (grammar_token.COLON, grammar_token.DOUBLESTAR): - dict_maker = True - - if not comp_for and dict_maker: - last_was_colon = False - unpacking = False - for child in node.children: - if child.type == grammar_token.DOUBLESTAR: - _AppendFirstLeafTokenSubtype(child, subtypes.KWARGS_STAR_STAR) - if last_was_colon: - if style.Get('INDENT_DICTIONARY_VALUE'): - _InsertPseudoParentheses(child) - else: - _AppendFirstLeafTokenSubtype(child, subtypes.DICTIONARY_VALUE) - elif (isinstance(child, pytree.Node) or - (not child.value.startswith('#') and child.value not in '{:,')): - # Mark the first leaf of a key entry as a DICTIONARY_KEY. We - # normally want to split before them if the dictionary cannot exist - # on a single line. - if not unpacking or pytree_utils.FirstLeafNode(child).value == '**': - _AppendFirstLeafTokenSubtype(child, subtypes.DICTIONARY_KEY) - _AppendSubtypeRec(child, subtypes.DICTIONARY_KEY_PART) - last_was_colon = child.type == grammar_token.COLON - if child.type == grammar_token.DOUBLESTAR: - unpacking = True - elif last_was_colon: - unpacking = False - - def Visit_expr_stmt(self, node): # pylint: disable=invalid-name - # expr_stmt ::= testlist_star_expr (augassign (yield_expr|testlist) - # | ('=' (yield_expr|testlist_star_expr))*) - for child in node.children: - self.Visit(child) - if isinstance(child, pytree.Leaf) and child.value == '=': - _AppendTokenSubtype(child, subtypes.ASSIGN_OPERATOR) - - def Visit_or_test(self, node): # pylint: disable=invalid-name - # or_test ::= and_test ('or' and_test)* - for child in node.children: - self.Visit(child) - if isinstance(child, pytree.Leaf) and child.value == 'or': - _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) - - def Visit_and_test(self, node): # pylint: disable=invalid-name - # and_test ::= not_test ('and' not_test)* - for child in node.children: - self.Visit(child) - if isinstance(child, pytree.Leaf) and child.value == 'and': - _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) - - def Visit_not_test(self, node): # pylint: disable=invalid-name - # not_test ::= 'not' not_test | comparison - for child in node.children: - self.Visit(child) - if isinstance(child, pytree.Leaf) and child.value == 'not': - _AppendTokenSubtype(child, subtypes.UNARY_OPERATOR) - - def Visit_comparison(self, node): # pylint: disable=invalid-name - # comparison ::= expr (comp_op expr)* - # comp_op ::= '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not in'|'is'|'is not' - for child in node.children: - self.Visit(child) - if (isinstance(child, pytree.Leaf) and - child.value in {'<', '>', '==', '>=', '<=', '<>', '!=', 'in', 'is'}): - _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) - elif pytree_utils.NodeName(child) == 'comp_op': - for grandchild in child.children: - _AppendTokenSubtype(grandchild, subtypes.BINARY_OPERATOR) - - def Visit_star_expr(self, node): # pylint: disable=invalid-name - # star_expr ::= '*' expr - for child in node.children: - self.Visit(child) - if isinstance(child, pytree.Leaf) and child.value == '*': - _AppendTokenSubtype(child, subtypes.UNARY_OPERATOR) - _AppendTokenSubtype(child, subtypes.VARARGS_STAR) - - def Visit_expr(self, node): # pylint: disable=invalid-name - # expr ::= xor_expr ('|' xor_expr)* - for child in node.children: - self.Visit(child) - if isinstance(child, pytree.Leaf) and child.value == '|': - _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) - - def Visit_xor_expr(self, node): # pylint: disable=invalid-name - # xor_expr ::= and_expr ('^' and_expr)* - for child in node.children: - self.Visit(child) - if isinstance(child, pytree.Leaf) and child.value == '^': - _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) - - def Visit_and_expr(self, node): # pylint: disable=invalid-name - # and_expr ::= shift_expr ('&' shift_expr)* - for child in node.children: - self.Visit(child) - if isinstance(child, pytree.Leaf) and child.value == '&': - _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) - - def Visit_shift_expr(self, node): # pylint: disable=invalid-name - # shift_expr ::= arith_expr (('<<'|'>>') arith_expr)* - for child in node.children: - self.Visit(child) - if isinstance(child, pytree.Leaf) and child.value in {'<<', '>>'}: - _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) - - def Visit_arith_expr(self, node): # pylint: disable=invalid-name - # arith_expr ::= term (('+'|'-') term)* - for child in node.children: - self.Visit(child) - if _IsAExprOperator(child): - _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) - - if _IsSimpleExpression(node): - for child in node.children: - if _IsAExprOperator(child): - _AppendTokenSubtype(child, subtypes.SIMPLE_EXPRESSION) - - def Visit_term(self, node): # pylint: disable=invalid-name - # term ::= factor (('*'|'/'|'%'|'//'|'@') factor)* - for child in node.children: - self.Visit(child) - if _IsMExprOperator(child): - _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) - - if _IsSimpleExpression(node): - for child in node.children: - if _IsMExprOperator(child): - _AppendTokenSubtype(child, subtypes.SIMPLE_EXPRESSION) - - def Visit_factor(self, node): # pylint: disable=invalid-name - # factor ::= ('+'|'-'|'~') factor | power - for child in node.children: - self.Visit(child) - if isinstance(child, pytree.Leaf) and child.value in '+-~': - _AppendTokenSubtype(child, subtypes.UNARY_OPERATOR) - - def Visit_power(self, node): # pylint: disable=invalid-name - # power ::= atom trailer* ['**' factor] - for child in node.children: - self.Visit(child) - if isinstance(child, pytree.Leaf) and child.value == '**': - _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) + def Visit_dictsetmaker( self, node ): # pylint: disable=invalid-name + # dictsetmaker ::= (test ':' test (comp_for | + # (',' test ':' test)* [','])) | + # (test (comp_for | (',' test)* [','])) + for child in node.children: + self.Visit( child ) + + comp_for = False + dict_maker = False + + for child in node.children: + if pytree_utils.NodeName( child ) == 'comp_for': + comp_for = True + _AppendFirstLeafTokenSubtype( child, subtypes.DICT_SET_GENERATOR ) + elif child.type in ( grammar_token.COLON, grammar_token.DOUBLESTAR ): + dict_maker = True + + if not comp_for and dict_maker: + last_was_colon = False + unpacking = False + for child in node.children: + if child.type == grammar_token.DOUBLESTAR: + _AppendFirstLeafTokenSubtype( child, subtypes.KWARGS_STAR_STAR ) + if last_was_colon: + if style.Get( 'INDENT_DICTIONARY_VALUE' ): + _InsertPseudoParentheses( child ) + else: + _AppendFirstLeafTokenSubtype( child, subtypes.DICTIONARY_VALUE ) + elif ( isinstance( child, pytree.Node ) or + ( not child.value.startswith( '#' ) and + child.value not in '{:,' ) ): + # Mark the first leaf of a key entry as a DICTIONARY_KEY. We + # normally want to split before them if the dictionary cannot exist + # on a single line. + if not unpacking or pytree_utils.FirstLeafNode( + child ).value == '**': + _AppendFirstLeafTokenSubtype( child, subtypes.DICTIONARY_KEY ) + _AppendSubtypeRec( child, subtypes.DICTIONARY_KEY_PART ) + last_was_colon = child.type == grammar_token.COLON + if child.type == grammar_token.DOUBLESTAR: + unpacking = True + elif last_was_colon: + unpacking = False + + def Visit_expr_stmt( self, node ): # pylint: disable=invalid-name + # expr_stmt ::= testlist_star_expr (augassign (yield_expr|testlist) + # | ('=' (yield_expr|testlist_star_expr))*) + for child in node.children: + self.Visit( child ) + if isinstance( child, pytree.Leaf ) and child.value == '=': + _AppendTokenSubtype( child, subtypes.ASSIGN_OPERATOR ) + + def Visit_or_test( self, node ): # pylint: disable=invalid-name + # or_test ::= and_test ('or' and_test)* + for child in node.children: + self.Visit( child ) + if isinstance( child, pytree.Leaf ) and child.value == 'or': + _AppendTokenSubtype( child, subtypes.BINARY_OPERATOR ) + + def Visit_and_test( self, node ): # pylint: disable=invalid-name + # and_test ::= not_test ('and' not_test)* + for child in node.children: + self.Visit( child ) + if isinstance( child, pytree.Leaf ) and child.value == 'and': + _AppendTokenSubtype( child, subtypes.BINARY_OPERATOR ) + + def Visit_not_test( self, node ): # pylint: disable=invalid-name + # not_test ::= 'not' not_test | comparison + for child in node.children: + self.Visit( child ) + if isinstance( child, pytree.Leaf ) and child.value == 'not': + _AppendTokenSubtype( child, subtypes.UNARY_OPERATOR ) + + def Visit_comparison( self, node ): # pylint: disable=invalid-name + # comparison ::= expr (comp_op expr)* + # comp_op ::= '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not in'|'is'|'is not' + for child in node.children: + self.Visit( child ) + if ( isinstance( child, pytree.Leaf ) and child.value + in { '<', '>', '==', '>=', '<=', '<>', '!=', 'in', 'is' } ): + _AppendTokenSubtype( child, subtypes.BINARY_OPERATOR ) + elif pytree_utils.NodeName( child ) == 'comp_op': + for grandchild in child.children: + _AppendTokenSubtype( grandchild, subtypes.BINARY_OPERATOR ) + + def Visit_star_expr( self, node ): # pylint: disable=invalid-name + # star_expr ::= '*' expr + for child in node.children: + self.Visit( child ) + if isinstance( child, pytree.Leaf ) and child.value == '*': + _AppendTokenSubtype( child, subtypes.UNARY_OPERATOR ) + _AppendTokenSubtype( child, subtypes.VARARGS_STAR ) + + def Visit_expr( self, node ): # pylint: disable=invalid-name + # expr ::= xor_expr ('|' xor_expr)* + for child in node.children: + self.Visit( child ) + if isinstance( child, pytree.Leaf ) and child.value == '|': + _AppendTokenSubtype( child, subtypes.BINARY_OPERATOR ) + + def Visit_xor_expr( self, node ): # pylint: disable=invalid-name + # xor_expr ::= and_expr ('^' and_expr)* + for child in node.children: + self.Visit( child ) + if isinstance( child, pytree.Leaf ) and child.value == '^': + _AppendTokenSubtype( child, subtypes.BINARY_OPERATOR ) + + def Visit_and_expr( self, node ): # pylint: disable=invalid-name + # and_expr ::= shift_expr ('&' shift_expr)* + for child in node.children: + self.Visit( child ) + if isinstance( child, pytree.Leaf ) and child.value == '&': + _AppendTokenSubtype( child, subtypes.BINARY_OPERATOR ) + + def Visit_shift_expr( self, node ): # pylint: disable=invalid-name + # shift_expr ::= arith_expr (('<<'|'>>') arith_expr)* + for child in node.children: + self.Visit( child ) + if isinstance( child, pytree.Leaf ) and child.value in { '<<', '>>' }: + _AppendTokenSubtype( child, subtypes.BINARY_OPERATOR ) + + def Visit_arith_expr( self, node ): # pylint: disable=invalid-name + # arith_expr ::= term (('+'|'-') term)* + for child in node.children: + self.Visit( child ) + if _IsAExprOperator( child ): + _AppendTokenSubtype( child, subtypes.BINARY_OPERATOR ) + + if _IsSimpleExpression( node ): + for child in node.children: + if _IsAExprOperator( child ): + _AppendTokenSubtype( child, subtypes.SIMPLE_EXPRESSION ) + + def Visit_term( self, node ): # pylint: disable=invalid-name + # term ::= factor (('*'|'/'|'%'|'//'|'@') factor)* + for child in node.children: + self.Visit( child ) + if _IsMExprOperator( child ): + _AppendTokenSubtype( child, subtypes.BINARY_OPERATOR ) + + if _IsSimpleExpression( node ): + for child in node.children: + if _IsMExprOperator( child ): + _AppendTokenSubtype( child, subtypes.SIMPLE_EXPRESSION ) + + def Visit_factor( self, node ): # pylint: disable=invalid-name + # factor ::= ('+'|'-'|'~') factor | power + for child in node.children: + self.Visit( child ) + if isinstance( child, pytree.Leaf ) and child.value in '+-~': + _AppendTokenSubtype( child, subtypes.UNARY_OPERATOR ) + + def Visit_power( self, node ): # pylint: disable=invalid-name + # power ::= atom trailer* ['**' factor] + for child in node.children: + self.Visit( child ) + if isinstance( child, pytree.Leaf ) and child.value == '**': + _AppendTokenSubtype( child, subtypes.BINARY_OPERATOR ) + + def Visit_trailer( self, node ): # pylint: disable=invalid-name + for child in node.children: + self.Visit( child ) + if isinstance( child, pytree.Leaf ) and child.value in '[]': + _AppendTokenSubtype( child, subtypes.SUBSCRIPT_BRACKET ) + + def Visit_subscript( self, node ): # pylint: disable=invalid-name + # subscript ::= test | [test] ':' [test] [sliceop] + for child in node.children: + self.Visit( child ) + if isinstance( child, pytree.Leaf ) and child.value == ':': + _AppendTokenSubtype( child, subtypes.SUBSCRIPT_COLON ) + + def Visit_sliceop( self, node ): # pylint: disable=invalid-name + # sliceop ::= ':' [test] + for child in node.children: + self.Visit( child ) + if isinstance( child, pytree.Leaf ) and child.value == ':': + _AppendTokenSubtype( child, subtypes.SUBSCRIPT_COLON ) + + def Visit_argument( self, node ): # pylint: disable=invalid-name + # argument ::= + # test [comp_for] | test '=' test + self._ProcessArgLists( node ) + #TODO add a subtype to each argument? + + def Visit_arglist( self, node ): # pylint: disable=invalid-name + # arglist ::= + # (argument ',')* (argument [','] + # | '*' test (',' argument)* [',' '**' test] + # | '**' test) + self._ProcessArgLists( node ) + _SetArgListSubtype( + node, subtypes.DEFAULT_OR_NAMED_ASSIGN, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST ) + + def Visit_tname( self, node ): # pylint: disable=invalid-name + self._ProcessArgLists( node ) + _SetArgListSubtype( + node, subtypes.DEFAULT_OR_NAMED_ASSIGN, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST ) + + def Visit_decorator( self, node ): # pylint: disable=invalid-name + # decorator ::= + # '@' dotted_name [ '(' [arglist] ')' ] NEWLINE + for child in node.children: + if isinstance( child, pytree.Leaf ) and child.value == '@': + _AppendTokenSubtype( child, subtype = subtypes.DECORATOR ) + self.Visit( child ) + + def Visit_funcdef( self, node ): # pylint: disable=invalid-name + # funcdef ::= + # 'def' NAME parameters ['->' test] ':' suite + for child in node.children: + if child.type == grammar_token.NAME and child.value != 'def': + _AppendTokenSubtype( child, subtypes.FUNC_DEF ) + break + for child in node.children: + self.Visit( child ) + + def Visit_parameters( self, node ): # pylint: disable=invalid-name + # parameters ::= '(' [typedargslist] ')' + self._ProcessArgLists( node ) + if len( node.children ) > 2: + _AppendFirstLeafTokenSubtype( node.children[ 1 ], subtypes.PARAMETER_START ) + _AppendLastLeafTokenSubtype( node.children[ -2 ], subtypes.PARAMETER_STOP ) + + def Visit_typedargslist( self, node ): # pylint: disable=invalid-name + # typedargslist ::= + # ((tfpdef ['=' test] ',')* + # ('*' [tname] (',' tname ['=' test])* [',' '**' tname] + # | '**' tname) + # | tfpdef ['=' test] (',' tfpdef ['=' test])* [',']) + self._ProcessArgLists( node ) + _SetArgListSubtype( + node, subtypes.DEFAULT_OR_NAMED_ASSIGN, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST ) + tname = False + if not node.children: + return + + _AppendFirstLeafTokenSubtype( node.children[ 0 ], subtypes.PARAMETER_START ) + _AppendLastLeafTokenSubtype( node.children[ -1 ], subtypes.PARAMETER_STOP ) + + tname = pytree_utils.NodeName( node.children[ 0 ] ) == 'tname' + for i in range( 1, len( node.children ) ): + prev_child = node.children[ i - 1 ] + child = node.children[ i ] + if prev_child.type == grammar_token.COMMA: + _AppendFirstLeafTokenSubtype( child, subtypes.PARAMETER_START ) + elif child.type == grammar_token.COMMA: + _AppendLastLeafTokenSubtype( prev_child, subtypes.PARAMETER_STOP ) + + if pytree_utils.NodeName( child ) == 'tname': + tname = True + _SetArgListSubtype( + child, subtypes.TYPED_NAME, subtypes.TYPED_NAME_ARG_LIST ) + elif child.type == grammar_token.COMMA: + tname = False + elif child.type == grammar_token.EQUAL and tname: + _AppendTokenSubtype( child, subtype = subtypes.TYPED_NAME ) + tname = False + + def Visit_varargslist( self, node ): # pylint: disable=invalid-name + # varargslist ::= + # ((vfpdef ['=' test] ',')* + # ('*' [vname] (',' vname ['=' test])* [',' '**' vname] + # | '**' vname) + # | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) + self._ProcessArgLists( node ) + for child in node.children: + self.Visit( child ) + if isinstance( child, pytree.Leaf ) and child.value == '=': + _AppendTokenSubtype( child, subtypes.VARARGS_LIST ) + + def Visit_comp_for( self, node ): # pylint: disable=invalid-name + # comp_for ::= 'for' exprlist 'in' testlist_safe [comp_iter] + _AppendSubtypeRec( node, subtypes.COMP_FOR ) + # Mark the previous node as COMP_EXPR unless this is a nested comprehension + # as these will have the outer comprehension as their previous node. + attr = pytree_utils.GetNodeAnnotation( + node.parent, pytree_utils.Annotation.SUBTYPE ) + if not attr or subtypes.COMP_FOR not in attr: + _AppendSubtypeRec( node.parent.children[ 0 ], subtypes.COMP_EXPR ) + self.DefaultNodeVisit( node ) + + def Visit_old_comp_for( self, node ): # pylint: disable=invalid-name + # Python 3.7 + self.Visit_comp_for( node ) + + def Visit_comp_if( self, node ): # pylint: disable=invalid-name + # comp_if ::= 'if' old_test [comp_iter] + _AppendSubtypeRec( node, subtypes.COMP_IF ) + self.DefaultNodeVisit( node ) + + def Visit_old_comp_if( self, node ): # pylint: disable=invalid-name + # Python 3.7 + self.Visit_comp_if( node ) + + def _ProcessArgLists( self, node ): + """Common method for processing argument lists.""" + for child in node.children: + self.Visit( child ) + if isinstance( child, pytree.Leaf ): + _AppendTokenSubtype( + child, + subtype = _ARGLIST_TOKEN_TO_SUBTYPE.get( + child.value, subtypes.NONE ) ) + + +def _SetArgListSubtype( node, node_subtype, list_subtype ): + """Set named assign subtype on elements in a arg list.""" + + def HasSubtype( node ): + """Return True if the arg list has a named assign subtype.""" + if isinstance( node, pytree.Leaf ): + return node_subtype in pytree_utils.GetNodeAnnotation( + node, pytree_utils.Annotation.SUBTYPE, set() ) + + for child in node.children: + node_name = pytree_utils.NodeName( child ) + if node_name not in { 'atom', 'arglist', 'power' }: + if HasSubtype( child ): + return True + + return False + + if not HasSubtype( node ): + return - def Visit_trailer(self, node): # pylint: disable=invalid-name for child in node.children: - self.Visit(child) - if isinstance(child, pytree.Leaf) and child.value in '[]': - _AppendTokenSubtype(child, subtypes.SUBSCRIPT_BRACKET) + node_name = pytree_utils.NodeName( child ) + if node_name not in { 'atom', 'COMMA' }: + _AppendFirstLeafTokenSubtype( child, list_subtype ) - def Visit_subscript(self, node): # pylint: disable=invalid-name - # subscript ::= test | [test] ':' [test] [sliceop] - for child in node.children: - self.Visit(child) - if isinstance(child, pytree.Leaf) and child.value == ':': - _AppendTokenSubtype(child, subtypes.SUBSCRIPT_COLON) - def Visit_sliceop(self, node): # pylint: disable=invalid-name - # sliceop ::= ':' [test] - for child in node.children: - self.Visit(child) - if isinstance(child, pytree.Leaf) and child.value == ':': - _AppendTokenSubtype(child, subtypes.SUBSCRIPT_COLON) - - def Visit_argument(self, node): # pylint: disable=invalid-name - # argument ::= - # test [comp_for] | test '=' test - self._ProcessArgLists(node) - #TODO add a subtype to each argument? - - def Visit_arglist(self, node): # pylint: disable=invalid-name - # arglist ::= - # (argument ',')* (argument [','] - # | '*' test (',' argument)* [',' '**' test] - # | '**' test) - self._ProcessArgLists(node) - _SetArgListSubtype(node, subtypes.DEFAULT_OR_NAMED_ASSIGN, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) - - def Visit_tname(self, node): # pylint: disable=invalid-name - self._ProcessArgLists(node) - _SetArgListSubtype(node, subtypes.DEFAULT_OR_NAMED_ASSIGN, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) - - def Visit_decorator(self, node): # pylint: disable=invalid-name - # decorator ::= - # '@' dotted_name [ '(' [arglist] ')' ] NEWLINE - for child in node.children: - if isinstance(child, pytree.Leaf) and child.value == '@': - _AppendTokenSubtype(child, subtype=subtypes.DECORATOR) - self.Visit(child) +def _AppendTokenSubtype( node, subtype ): + """Append the token's subtype only if it's not already set.""" + pytree_utils.AppendNodeAnnotation( node, pytree_utils.Annotation.SUBTYPE, subtype ) - def Visit_funcdef(self, node): # pylint: disable=invalid-name - # funcdef ::= - # 'def' NAME parameters ['->' test] ':' suite - for child in node.children: - if child.type == grammar_token.NAME and child.value != 'def': - _AppendTokenSubtype(child, subtypes.FUNC_DEF) - break - for child in node.children: - self.Visit(child) - - def Visit_parameters(self, node): # pylint: disable=invalid-name - # parameters ::= '(' [typedargslist] ')' - self._ProcessArgLists(node) - if len(node.children) > 2: - _AppendFirstLeafTokenSubtype(node.children[1], subtypes.PARAMETER_START) - _AppendLastLeafTokenSubtype(node.children[-2], subtypes.PARAMETER_STOP) - - def Visit_typedargslist(self, node): # pylint: disable=invalid-name - # typedargslist ::= - # ((tfpdef ['=' test] ',')* - # ('*' [tname] (',' tname ['=' test])* [',' '**' tname] - # | '**' tname) - # | tfpdef ['=' test] (',' tfpdef ['=' test])* [',']) - self._ProcessArgLists(node) - _SetArgListSubtype(node, subtypes.DEFAULT_OR_NAMED_ASSIGN, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) - tname = False - if not node.children: - return - - _AppendFirstLeafTokenSubtype(node.children[0], subtypes.PARAMETER_START) - _AppendLastLeafTokenSubtype(node.children[-1], subtypes.PARAMETER_STOP) - - tname = pytree_utils.NodeName(node.children[0]) == 'tname' - for i in range(1, len(node.children)): - prev_child = node.children[i - 1] - child = node.children[i] - if prev_child.type == grammar_token.COMMA: - _AppendFirstLeafTokenSubtype(child, subtypes.PARAMETER_START) - elif child.type == grammar_token.COMMA: - _AppendLastLeafTokenSubtype(prev_child, subtypes.PARAMETER_STOP) - - if pytree_utils.NodeName(child) == 'tname': - tname = True - _SetArgListSubtype(child, subtypes.TYPED_NAME, - subtypes.TYPED_NAME_ARG_LIST) - # NOTE Every element of the tynamme argument - # should have this list type - _AppendSubtypeRec(child, subtypes.TYPED_NAME_ARG_LIST) - - elif child.type == grammar_token.COMMA: - tname = False - elif child.type == grammar_token.EQUAL and tname: - _AppendTokenSubtype(child, subtype=subtypes.TYPED_NAME) - tname = False - def Visit_varargslist(self, node): # pylint: disable=invalid-name - # varargslist ::= - # ((vfpdef ['=' test] ',')* - # ('*' [vname] (',' vname ['=' test])* [',' '**' vname] - # | '**' vname) - # | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) - self._ProcessArgLists(node) - for child in node.children: - self.Visit(child) - if isinstance(child, pytree.Leaf) and child.value == '=': - _AppendTokenSubtype(child, subtypes.VARARGS_LIST) - - def Visit_comp_for(self, node): # pylint: disable=invalid-name - # comp_for ::= 'for' exprlist 'in' testlist_safe [comp_iter] - _AppendSubtypeRec(node, subtypes.COMP_FOR) - # Mark the previous node as COMP_EXPR unless this is a nested comprehension - # as these will have the outer comprehension as their previous node. - attr = pytree_utils.GetNodeAnnotation(node.parent, - pytree_utils.Annotation.SUBTYPE) - if not attr or subtypes.COMP_FOR not in attr: - _AppendSubtypeRec(node.parent.children[0], subtypes.COMP_EXPR) - self.DefaultNodeVisit(node) - - def Visit_old_comp_for(self, node): # pylint: disable=invalid-name - # Python 3.7 - self.Visit_comp_for(node) - - def Visit_comp_if(self, node): # pylint: disable=invalid-name - # comp_if ::= 'if' old_test [comp_iter] - _AppendSubtypeRec(node, subtypes.COMP_IF) - self.DefaultNodeVisit(node) - - def Visit_old_comp_if(self, node): # pylint: disable=invalid-name - # Python 3.7 - self.Visit_comp_if(node) - - def _ProcessArgLists(self, node): - """Common method for processing argument lists.""" - for child in node.children: - self.Visit(child) - if isinstance(child, pytree.Leaf): - _AppendTokenSubtype( - child, - subtype=_ARGLIST_TOKEN_TO_SUBTYPE.get(child.value, subtypes.NONE)) +def _AppendFirstLeafTokenSubtype( node, subtype ): + """Append the first leaf token's subtypes.""" + if isinstance( node, pytree.Leaf ): + _AppendTokenSubtype( node, subtype ) + return + _AppendFirstLeafTokenSubtype( node.children[ 0 ], subtype ) -def _SetArgListSubtype(node, node_subtype, list_subtype): - """Set named assign subtype on elements in a arg list.""" +def _AppendLastLeafTokenSubtype( node, subtype ): + """Append the last leaf token's subtypes.""" + if isinstance( node, pytree.Leaf ): + _AppendTokenSubtype( node, subtype ) + return + _AppendLastLeafTokenSubtype( node.children[ -1 ], subtype ) - def HasSubtype(node): - """Return True if the arg list has a named assign subtype.""" - if isinstance(node, pytree.Leaf): - return node_subtype in pytree_utils.GetNodeAnnotation( - node, pytree_utils.Annotation.SUBTYPE, set()) +def _AppendSubtypeRec( node, subtype, force = True ): + """Append the leafs in the node to the given subtype.""" + if isinstance( node, pytree.Leaf ): + _AppendTokenSubtype( node, subtype ) + return for child in node.children: - node_name = pytree_utils.NodeName(child) - if node_name not in {'atom', 'arglist', 'power'}: - if HasSubtype(child): - return True - - return False - - if not HasSubtype(node): - return - - for child in node.children: - node_name = pytree_utils.NodeName(child) - if node_name not in {'atom', 'COMMA'}: - _AppendFirstLeafTokenSubtype(child, list_subtype) - - -def _AppendTokenSubtype(node, subtype): - """Append the token's subtype only if it's not already set.""" - pytree_utils.AppendNodeAnnotation(node, pytree_utils.Annotation.SUBTYPE, - subtype) - - -def _AppendFirstLeafTokenSubtype(node, subtype): - """Append the first leaf token's subtypes.""" - if isinstance(node, pytree.Leaf): - _AppendTokenSubtype(node, subtype) - return - _AppendFirstLeafTokenSubtype(node.children[0], subtype) - - -def _AppendLastLeafTokenSubtype(node, subtype): - """Append the last leaf token's subtypes.""" - if isinstance(node, pytree.Leaf): - _AppendTokenSubtype(node, subtype) - return - _AppendLastLeafTokenSubtype(node.children[-1], subtype) - - -def _AppendSubtypeRec(node, subtype, force=True): - """Append the leafs in the node to the given subtype.""" - if isinstance(node, pytree.Leaf): - _AppendTokenSubtype(node, subtype) - return - for child in node.children: - _AppendSubtypeRec(child, subtype, force=force) - - -def _InsertPseudoParentheses(node): - """Insert pseudo parentheses so that dicts can be formatted correctly.""" - comment_node = None - if isinstance(node, pytree.Node): - if node.children[-1].type == grammar_token.COMMENT: - comment_node = node.children[-1].clone() - node.children[-1].remove() - - first = pytree_utils.FirstLeafNode(node) - last = pytree_utils.LastLeafNode(node) - - if first == last and first.type == grammar_token.COMMENT: - # A comment was inserted before the value, which is a pytree.Leaf. - # Encompass the dictionary's value into an ATOM node. - last = first.next_sibling - last_clone = last.clone() - new_node = pytree.Node(syms.atom, [first.clone(), last_clone]) - for orig_leaf, clone_leaf in zip(last.leaves(), last_clone.leaves()): - pytree_utils.CopyYapfAnnotations(orig_leaf, clone_leaf) - if hasattr(orig_leaf, 'is_pseudo'): - clone_leaf.is_pseudo = orig_leaf.is_pseudo - - node.replace(new_node) - node = new_node - last.remove() - - first = pytree_utils.FirstLeafNode(node) - last = pytree_utils.LastLeafNode(node) - - lparen = pytree.Leaf( - grammar_token.LPAR, - u'(', - context=('', (first.get_lineno(), first.column - 1))) - last_lineno = last.get_lineno() - if last.type == grammar_token.STRING and '\n' in last.value: - last_lineno += last.value.count('\n') - - if last.type == grammar_token.STRING and '\n' in last.value: - last_column = len(last.value.split('\n')[-1]) + 1 - else: - last_column = last.column + len(last.value) + 1 - rparen = pytree.Leaf( - grammar_token.RPAR, u')', context=('', (last_lineno, last_column))) - - lparen.is_pseudo = True - rparen.is_pseudo = True - - if isinstance(node, pytree.Node): - node.insert_child(0, lparen) - node.append_child(rparen) - if comment_node: - node.append_child(comment_node) - _AppendFirstLeafTokenSubtype(node, subtypes.DICTIONARY_VALUE) - else: - clone = node.clone() - for orig_leaf, clone_leaf in zip(node.leaves(), clone.leaves()): - pytree_utils.CopyYapfAnnotations(orig_leaf, clone_leaf) - new_node = pytree.Node(syms.atom, [lparen, clone, rparen]) - node.replace(new_node) - _AppendFirstLeafTokenSubtype(clone, subtypes.DICTIONARY_VALUE) - - -def _IsAExprOperator(node): - return isinstance(node, pytree.Leaf) and node.value in {'+', '-'} - - -def _IsMExprOperator(node): - return isinstance(node, - pytree.Leaf) and node.value in {'*', '/', '%', '//', '@'} - - -def _IsSimpleExpression(node): - """A node with only leafs as children.""" - return all(isinstance(child, pytree.Leaf) for child in node.children) + _AppendSubtypeRec( child, subtype, force = force ) + + +def _InsertPseudoParentheses( node ): + """Insert pseudo parentheses so that dicts can be formatted correctly.""" + comment_node = None + if isinstance( node, pytree.Node ): + if node.children[ -1 ].type == grammar_token.COMMENT: + comment_node = node.children[ -1 ].clone() + node.children[ -1 ].remove() + + first = pytree_utils.FirstLeafNode( node ) + last = pytree_utils.LastLeafNode( node ) + + if first == last and first.type == grammar_token.COMMENT: + # A comment was inserted before the value, which is a pytree.Leaf. + # Encompass the dictionary's value into an ATOM node. + last = first.next_sibling + last_clone = last.clone() + new_node = pytree.Node( syms.atom, [ first.clone(), last_clone ] ) + for orig_leaf, clone_leaf in zip( last.leaves(), last_clone.leaves() ): + pytree_utils.CopyYapfAnnotations( orig_leaf, clone_leaf ) + if hasattr( orig_leaf, 'is_pseudo' ): + clone_leaf.is_pseudo = orig_leaf.is_pseudo + + node.replace( new_node ) + node = new_node + last.remove() + + first = pytree_utils.FirstLeafNode( node ) + last = pytree_utils.LastLeafNode( node ) + + lparen = pytree.Leaf( + grammar_token.LPAR, + u'(', + context = ( '', ( first.get_lineno(), first.column - 1 ) ) ) + last_lineno = last.get_lineno() + if last.type == grammar_token.STRING and '\n' in last.value: + last_lineno += last.value.count( '\n' ) + + if last.type == grammar_token.STRING and '\n' in last.value: + last_column = len( last.value.split( '\n' )[ -1 ] ) + 1 + else: + last_column = last.column + len( last.value ) + 1 + rparen = pytree.Leaf( + grammar_token.RPAR, u')', context = ( '', ( last_lineno, last_column ) ) ) + + lparen.is_pseudo = True + rparen.is_pseudo = True + + if isinstance( node, pytree.Node ): + node.insert_child( 0, lparen ) + node.append_child( rparen ) + if comment_node: + node.append_child( comment_node ) + _AppendFirstLeafTokenSubtype( node, subtypes.DICTIONARY_VALUE ) + else: + clone = node.clone() + for orig_leaf, clone_leaf in zip( node.leaves(), clone.leaves() ): + pytree_utils.CopyYapfAnnotations( orig_leaf, clone_leaf ) + new_node = pytree.Node( syms.atom, [ lparen, clone, rparen ] ) + node.replace( new_node ) + _AppendFirstLeafTokenSubtype( clone, subtypes.DICTIONARY_VALUE ) + + +def _IsAExprOperator( node ): + return isinstance( node, pytree.Leaf ) and node.value in { '+', '-' } + + +def _IsMExprOperator( node ): + return isinstance( node, + pytree.Leaf ) and node.value in { '*', '/', '%', '//', '@' } + + +def _IsSimpleExpression( node ): + """A node with only leafs as children.""" + return all( isinstance( child, pytree.Leaf ) for child in node.children ) diff --git a/yapf/third_party/yapf_diff/yapf_diff.py b/yapf/third_party/yapf_diff/yapf_diff.py index 810a6a2d4..afd3ebc91 100644 --- a/yapf/third_party/yapf_diff/yapf_diff.py +++ b/yapf/third_party/yapf_diff/yapf_diff.py @@ -33,113 +33,114 @@ import sys if sys.version_info.major >= 3: - from io import StringIO + from io import StringIO else: - from io import BytesIO as StringIO + from io import BytesIO as StringIO def main(): - parser = argparse.ArgumentParser( - description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) - parser.add_argument( - '-i', - '--in-place', - action='store_true', - default=False, - help='apply edits to files instead of displaying a diff') - parser.add_argument( - '-p', - '--prefix', - metavar='NUM', - default=1, - help='strip the smallest prefix containing P slashes') - parser.add_argument( - '--regex', - metavar='PATTERN', - default=None, - help='custom pattern selecting file paths to reformat ' - '(case sensitive, overrides -iregex)') - parser.add_argument( - '--iregex', - metavar='PATTERN', - default=r'.*\.(py)', - help='custom pattern selecting file paths to reformat ' - '(case insensitive, overridden by -regex)') - parser.add_argument( - '-v', - '--verbose', - action='store_true', - help='be more verbose, ineffective without -i') - parser.add_argument( - '--style', - help='specify formatting style: either a style name (for ' - 'example "pep8" or "google"), or the name of a file with ' - 'style settings. The default is pep8 unless a ' - '.style.yapf or setup.cfg file located in one of the ' - 'parent directories of the source file (or current ' - 'directory for stdin)') - parser.add_argument( - '--binary', default='yapf', help='location of binary to use for yapf') - args = parser.parse_args() + parser = argparse.ArgumentParser( + description = __doc__, formatter_class = argparse.RawDescriptionHelpFormatter ) + parser.add_argument( + '-i', + '--in-place', + action = 'store_true', + default = False, + help = 'apply edits to files instead of displaying a diff' ) + parser.add_argument( + '-p', + '--prefix', + metavar = 'NUM', + default = 1, + help = 'strip the smallest prefix containing P slashes' ) + parser.add_argument( + '--regex', + metavar = 'PATTERN', + default = None, + help = 'custom pattern selecting file paths to reformat ' + '(case sensitive, overrides -iregex)' ) + parser.add_argument( + '--iregex', + metavar = 'PATTERN', + default = r'.*\.(py)', + help = 'custom pattern selecting file paths to reformat ' + '(case insensitive, overridden by -regex)' ) + parser.add_argument( + '-v', + '--verbose', + action = 'store_true', + help = 'be more verbose, ineffective without -i' ) + parser.add_argument( + '--style', + help = 'specify formatting style: either a style name (for ' + 'example "pep8" or "google"), or the name of a file with ' + 'style settings. The default is pep8 unless a ' + '.style.yapf or setup.cfg file located in one of the ' + 'parent directories of the source file (or current ' + 'directory for stdin)' ) + parser.add_argument( + '--binary', default = 'yapf', help = 'location of binary to use for yapf' ) + args = parser.parse_args() - # Extract changed lines for each file. - filename = None - lines_by_file = {} - for line in sys.stdin: - match = re.search(r'^\+\+\+\ (.*?/){%s}(\S*)' % args.prefix, line) - if match: - filename = match.group(2) - if filename is None: - continue + # Extract changed lines for each file. + filename = None + lines_by_file = {} + for line in sys.stdin: + match = re.search( r'^\+\+\+\ (.*?/){%s}(\S*)' % args.prefix, line ) + if match: + filename = match.group( 2 ) + if filename is None: + continue - if args.regex is not None: - if not re.match('^%s$' % args.regex, filename): - continue - elif not re.match('^%s$' % args.iregex, filename, re.IGNORECASE): - continue + if args.regex is not None: + if not re.match( '^%s$' % args.regex, filename ): + continue + elif not re.match( '^%s$' % args.iregex, filename, re.IGNORECASE ): + continue - match = re.search(r'^@@.*\+(\d+)(,(\d+))?', line) - if match: - start_line = int(match.group(1)) - line_count = 1 - if match.group(3): - line_count = int(match.group(3)) - if line_count == 0: - continue - end_line = start_line + line_count - 1 - lines_by_file.setdefault(filename, []).extend( - ['--lines', str(start_line) + '-' + str(end_line)]) + match = re.search( r'^@@.*\+(\d+)(,(\d+))?', line ) + if match: + start_line = int( match.group( 1 ) ) + line_count = 1 + if match.group( 3 ): + line_count = int( match.group( 3 ) ) + if line_count == 0: + continue + end_line = start_line + line_count - 1 + lines_by_file.setdefault( filename, [] ).extend( + [ '--lines', str( start_line ) + '-' + str( end_line ) ] ) - # Reformat files containing changes in place. - for filename, lines in lines_by_file.items(): - if args.in_place and args.verbose: - print('Formatting {}'.format(filename)) - command = [args.binary, filename] - if args.in_place: - command.append('-i') - command.extend(lines) - if args.style: - command.extend(['--style', args.style]) - p = subprocess.Popen( - command, - stdout=subprocess.PIPE, - stderr=None, - stdin=subprocess.PIPE, - universal_newlines=True) - stdout, stderr = p.communicate() - if p.returncode != 0: - sys.exit(p.returncode) + # Reformat files containing changes in place. + for filename, lines in lines_by_file.items(): + if args.in_place and args.verbose: + print( 'Formatting {}'.format( filename ) ) + command = [ args.binary, filename ] + if args.in_place: + command.append( '-i' ) + command.extend( lines ) + if args.style: + command.extend( [ '--style', args.style ] ) + p = subprocess.Popen( + command, + stdout = subprocess.PIPE, + stderr = None, + stdin = subprocess.PIPE, + universal_newlines = True ) + stdout, stderr = p.communicate() + if p.returncode != 0: + sys.exit( p.returncode ) - if not args.in_place: - with open(filename) as f: - code = f.readlines() - formatted_code = StringIO(stdout).readlines() - diff = difflib.unified_diff(code, formatted_code, filename, filename, - '(before formatting)', '(after formatting)') - diff_string = ''.join(diff) - if len(diff_string) > 0: - sys.stdout.write(diff_string) + if not args.in_place: + with open( filename ) as f: + code = f.readlines() + formatted_code = StringIO( stdout ).readlines() + diff = difflib.unified_diff( + code, formatted_code, filename, filename, '(before formatting)', + '(after formatting)' ) + diff_string = ''.join( diff ) + if len( diff_string ) > 0: + sys.stdout.write( diff_string ) if __name__ == '__main__': - main() + main() diff --git a/yapf/yapflib/errors.py b/yapf/yapflib/errors.py index 99e88d9c0..8864b49c6 100644 --- a/yapf/yapflib/errors.py +++ b/yapf/yapflib/errors.py @@ -16,8 +16,8 @@ from lib2to3.pgen2 import tokenize -def FormatErrorMsg(e): - """Convert an exception into a standard format. +def FormatErrorMsg( e ): + """Convert an exception into a standard format. The standard error message format is: @@ -29,18 +29,19 @@ def FormatErrorMsg(e): Returns: A properly formatted error message string. """ - if isinstance(e, SyntaxError): - return '{}:{}:{}: {}'.format(e.filename, e.lineno, e.offset, e.msg) - if isinstance(e, tokenize.TokenError): - return '{}:{}:{}: {}'.format(e.filename, e.args[1][0], e.args[1][1], - e.args[0]) - return '{}:{}:{}: {}'.format(e.args[1][0], e.args[1][1], e.args[1][2], e.msg) + if isinstance( e, SyntaxError ): + return '{}:{}:{}: {}'.format( e.filename, e.lineno, e.offset, e.msg ) + if isinstance( e, tokenize.TokenError ): + return '{}:{}:{}: {}'.format( + e.filename, e.args[ 1 ][ 0 ], e.args[ 1 ][ 1 ], e.args[ 0 ] ) + return '{}:{}:{}: {}'.format( + e.args[ 1 ][ 0 ], e.args[ 1 ][ 1 ], e.args[ 1 ][ 2 ], e.msg ) -class YapfError(Exception): - """Parent class for user errors or input errors. +class YapfError( Exception ): + """Parent class for user errors or input errors. Exceptions of this type are handled by the command line tool and result in clear error messages, as opposed to backtraces. """ - pass + pass diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index b5e2612bd..07ee951a2 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -25,49 +25,48 @@ from yapf.yapflib import py3compat from yapf.yapflib import style -CR = '\r' -LF = '\n' +CR = '\r' +LF = '\n' CRLF = '\r\n' -def _GetExcludePatternsFromYapfIgnore(filename): - """Get a list of file patterns to ignore from .yapfignore.""" - ignore_patterns = [] - if os.path.isfile(filename) and os.access(filename, os.R_OK): - with open(filename, 'r') as fd: - for line in fd: - if line.strip() and not line.startswith('#'): - ignore_patterns.append(line.strip()) +def _GetExcludePatternsFromYapfIgnore( filename ): + """Get a list of file patterns to ignore from .yapfignore.""" + ignore_patterns = [] + if os.path.isfile( filename ) and os.access( filename, os.R_OK ): + with open( filename, 'r' ) as fd: + for line in fd: + if line.strip() and not line.startswith( '#' ): + ignore_patterns.append( line.strip() ) - if any(e.startswith('./') for e in ignore_patterns): - raise errors.YapfError('path in .yapfignore should not start with ./') + if any( e.startswith( './' ) for e in ignore_patterns ): + raise errors.YapfError( 'path in .yapfignore should not start with ./' ) - return ignore_patterns + return ignore_patterns -def _GetExcludePatternsFromPyprojectToml(filename): - """Get a list of file patterns to ignore from pyproject.toml.""" - ignore_patterns = [] - try: - import toml - except ImportError: - raise errors.YapfError( - "toml package is needed for using pyproject.toml as a " - "configuration file") +def _GetExcludePatternsFromPyprojectToml( filename ): + """Get a list of file patterns to ignore from pyproject.toml.""" + ignore_patterns = [] + try: + import toml + except ImportError: + raise errors.YapfError( + "toml package is needed for using pyproject.toml as a " + "configuration file" ) - if os.path.isfile(filename) and os.access(filename, os.R_OK): - pyproject_toml = toml.load(filename) - ignore_patterns = pyproject_toml.get('tool', - {}).get('yapfignore', - {}).get('ignore_patterns', []) - if any(e.startswith('./') for e in ignore_patterns): - raise errors.YapfError('path in pyproject.toml should not start with ./') + if os.path.isfile( filename ) and os.access( filename, os.R_OK ): + pyproject_toml = toml.load( filename ) + ignore_patterns = pyproject_toml.get( 'tool', {} ).get( 'yapfignore', {} ).get( + 'ignore_patterns', [] ) + if any( e.startswith( './' ) for e in ignore_patterns ): + raise errors.YapfError( 'path in pyproject.toml should not start with ./' ) - return ignore_patterns + return ignore_patterns -def GetExcludePatternsForDir(dirname): - """Return patterns of files to exclude from ignorefile in a given directory. +def GetExcludePatternsForDir( dirname ): + """Return patterns of files to exclude from ignorefile in a given directory. Looks for .yapfignore in the directory dirname. @@ -78,20 +77,20 @@ def GetExcludePatternsForDir(dirname): A List of file patterns to exclude if ignore file is found, otherwise empty List. """ - ignore_patterns = [] + ignore_patterns = [] - yapfignore_file = os.path.join(dirname, '.yapfignore') - if os.path.exists(yapfignore_file): - ignore_patterns += _GetExcludePatternsFromYapfIgnore(yapfignore_file) + yapfignore_file = os.path.join( dirname, '.yapfignore' ) + if os.path.exists( yapfignore_file ): + ignore_patterns += _GetExcludePatternsFromYapfIgnore( yapfignore_file ) - pyproject_toml_file = os.path.join(dirname, 'pyproject.toml') - if os.path.exists(pyproject_toml_file): - ignore_patterns += _GetExcludePatternsFromPyprojectToml(pyproject_toml_file) - return ignore_patterns + pyproject_toml_file = os.path.join( dirname, 'pyproject.toml' ) + if os.path.exists( pyproject_toml_file ): + ignore_patterns += _GetExcludePatternsFromPyprojectToml( pyproject_toml_file ) + return ignore_patterns -def GetDefaultStyleForDir(dirname, default_style=style.DEFAULT_STYLE): - """Return default style name for a given directory. +def GetDefaultStyleForDir( dirname, default_style = style.DEFAULT_STYLE ): + """Return default style name for a given directory. Looks for .style.yapf or setup.cfg or pyproject.toml in the parent directories. @@ -104,68 +103,65 @@ def GetDefaultStyleForDir(dirname, default_style=style.DEFAULT_STYLE): Returns: The filename if found, otherwise return the default style. """ - dirname = os.path.abspath(dirname) - while True: - # See if we have a .style.yapf file. - style_file = os.path.join(dirname, style.LOCAL_STYLE) - if os.path.exists(style_file): - return style_file - - # See if we have a setup.cfg file with a '[yapf]' section. - config_file = os.path.join(dirname, style.SETUP_CONFIG) - try: - fd = open(config_file) - except IOError: - pass # It's okay if it's not there. - else: - with fd: - config = py3compat.ConfigParser() - config.read_file(fd) - if config.has_section('yapf'): - return config_file - - # See if we have a pyproject.toml file with a '[tool.yapf]' section. - config_file = os.path.join(dirname, style.PYPROJECT_TOML) - try: - fd = open(config_file) - except IOError: - pass # It's okay if it's not there. - else: - with fd: + dirname = os.path.abspath( dirname ) + while True: + # See if we have a .style.yapf file. + style_file = os.path.join( dirname, style.LOCAL_STYLE ) + if os.path.exists( style_file ): + return style_file + + # See if we have a setup.cfg file with a '[yapf]' section. + config_file = os.path.join( dirname, style.SETUP_CONFIG ) try: - import toml - except ImportError: - raise errors.YapfError( - "toml package is needed for using pyproject.toml as a " - "configuration file") + fd = open( config_file ) + except IOError: + pass # It's okay if it's not there. + else: + with fd: + config = py3compat.ConfigParser() + config.read_file( fd ) + if config.has_section( 'yapf' ): + return config_file + + # See if we have a pyproject.toml file with a '[tool.yapf]' section. + config_file = os.path.join( dirname, style.PYPROJECT_TOML ) + try: + fd = open( config_file ) + except IOError: + pass # It's okay if it's not there. + else: + with fd: + try: + import toml + except ImportError: + raise errors.YapfError( + "toml package is needed for using pyproject.toml as a " + "configuration file" ) - pyproject_toml = toml.load(config_file) - style_dict = pyproject_toml.get('tool', {}).get('yapf', None) - if style_dict is not None: - return config_file + pyproject_toml = toml.load( config_file ) + style_dict = pyproject_toml.get( 'tool', {} ).get( 'yapf', None ) + if style_dict is not None: + return config_file - if (not dirname or not os.path.basename(dirname) or - dirname == os.path.abspath(os.path.sep)): - break - dirname = os.path.dirname(dirname) + if ( not dirname or not os.path.basename( dirname ) or + dirname == os.path.abspath( os.path.sep ) ): + break + dirname = os.path.dirname( dirname ) - global_file = os.path.expanduser(style.GLOBAL_STYLE) - if os.path.exists(global_file): - return global_file + global_file = os.path.expanduser( style.GLOBAL_STYLE ) + if os.path.exists( global_file ): + return global_file - return default_style + return default_style -def GetCommandLineFiles(command_line_file_list, recursive, exclude): - """Return the list of files specified on the command line.""" - return _FindPythonFiles(command_line_file_list, recursive, exclude) +def GetCommandLineFiles( command_line_file_list, recursive, exclude ): + """Return the list of files specified on the command line.""" + return _FindPythonFiles( command_line_file_list, recursive, exclude ) -def WriteReformattedCode(filename, - reformatted_code, - encoding='', - in_place=False): - """Emit the reformatted code. +def WriteReformattedCode( filename, reformatted_code, encoding = '', in_place = False ): + """Emit the reformatted code. Write the reformatted code into the file, if in_place is True. Otherwise, write to stdout. @@ -176,117 +172,117 @@ def WriteReformattedCode(filename, encoding: (unicode) The encoding of the file. in_place: (bool) If True, then write the reformatted code to the file. """ - if in_place: - with py3compat.open_with_encoding( - filename, mode='w', encoding=encoding, newline='') as fd: - fd.write(reformatted_code) - else: - py3compat.EncodeAndWriteToStdout(reformatted_code) - - -def LineEnding(lines): - """Retrieve the line ending of the original source.""" - endings = {CRLF: 0, CR: 0, LF: 0} - for line in lines: - if line.endswith(CRLF): - endings[CRLF] += 1 - elif line.endswith(CR): - endings[CR] += 1 - elif line.endswith(LF): - endings[LF] += 1 - return (sorted(endings, key=endings.get, reverse=True) or [LF])[0] - - -def _FindPythonFiles(filenames, recursive, exclude): - """Find all Python files.""" - if exclude and any(e.startswith('./') for e in exclude): - raise errors.YapfError("path in '--exclude' should not start with ./") - exclude = exclude and [e.rstrip("/" + os.path.sep) for e in exclude] - - python_files = [] - for filename in filenames: - if filename != '.' and exclude and IsIgnored(filename, exclude): - continue - if os.path.isdir(filename): - if not recursive: - raise errors.YapfError( - "directory specified without '--recursive' flag: %s" % filename) - - # TODO(morbo): Look into a version of os.walk that can handle recursion. - excluded_dirs = [] - for dirpath, dirnames, filelist in os.walk(filename): - if dirpath != '.' and exclude and IsIgnored(dirpath, exclude): - excluded_dirs.append(dirpath) - continue - elif any(dirpath.startswith(e) for e in excluded_dirs): - continue - for f in filelist: - filepath = os.path.join(dirpath, f) - if exclude and IsIgnored(filepath, exclude): + if in_place: + with py3compat.open_with_encoding( filename, mode = 'w', encoding = encoding, + newline = '' ) as fd: + fd.write( reformatted_code ) + else: + py3compat.EncodeAndWriteToStdout( reformatted_code ) + + +def LineEnding( lines ): + """Retrieve the line ending of the original source.""" + endings = { CRLF: 0, CR: 0, LF: 0} + for line in lines: + if line.endswith( CRLF ): + endings[ CRLF ] += 1 + elif line.endswith( CR ): + endings[ CR ] += 1 + elif line.endswith( LF ): + endings[ LF ] += 1 + return ( sorted( endings, key = endings.get, reverse = True ) or [ LF ] )[ 0 ] + + +def _FindPythonFiles( filenames, recursive, exclude ): + """Find all Python files.""" + if exclude and any( e.startswith( './' ) for e in exclude ): + raise errors.YapfError( "path in '--exclude' should not start with ./" ) + exclude = exclude and [ e.rstrip( "/" + os.path.sep ) for e in exclude ] + + python_files = [] + for filename in filenames: + if filename != '.' and exclude and IsIgnored( filename, exclude ): continue - if IsPythonFile(filepath): - python_files.append(filepath) - # To prevent it from scanning the contents excluded folders, os.walk() - # lets you amend its list of child dirs `dirnames`. These edits must be - # made in-place instead of creating a modified copy of `dirnames`. - # list.remove() is slow and list.pop() is a headache. Instead clear - # `dirnames` then repopulate it. - dirnames_ = [dirnames.pop(0) for i in range(len(dirnames))] - for dirname in dirnames_: - dir_ = os.path.join(dirpath, dirname) - if IsIgnored(dir_, exclude): - excluded_dirs.append(dir_) - else: - dirnames.append(dirname) - - elif os.path.isfile(filename): - python_files.append(filename) - - return python_files - - -def IsIgnored(path, exclude): - """Return True if filename matches any patterns in exclude.""" - if exclude is None: - return False - path = path.lstrip(os.path.sep) - while path.startswith('.' + os.path.sep): - path = path[2:] - return any(fnmatch.fnmatch(path, e.rstrip(os.path.sep)) for e in exclude) - - -def IsPythonFile(filename): - """Return True if filename is a Python file.""" - if os.path.splitext(filename)[1] == '.py': - return True - - try: - with open(filename, 'rb') as fd: - encoding = py3compat.detect_encoding(fd.readline)[0] - - # Check for correctness of encoding. - with py3compat.open_with_encoding( - filename, mode='r', encoding=encoding) as fd: - fd.read() - except UnicodeDecodeError: - encoding = 'latin-1' - except (IOError, SyntaxError): - # If we fail to detect encoding (or the encoding cookie is incorrect - which - # will make detect_encoding raise SyntaxError), assume it's not a Python - # file. - return False - - try: - with py3compat.open_with_encoding( - filename, mode='r', encoding=encoding) as fd: - first_line = fd.readline(256) - except IOError: - return False - - return re.match(r'^#!.*\bpython[23]?\b', first_line) - - -def FileEncoding(filename): - """Return the file's encoding.""" - with open(filename, 'rb') as fd: - return py3compat.detect_encoding(fd.readline)[0] + if os.path.isdir( filename ): + if not recursive: + raise errors.YapfError( + "directory specified without '--recursive' flag: %s" % filename ) + + # TODO(morbo): Look into a version of os.walk that can handle recursion. + excluded_dirs = [] + for dirpath, dirnames, filelist in os.walk( filename ): + if dirpath != '.' and exclude and IsIgnored( dirpath, exclude ): + excluded_dirs.append( dirpath ) + continue + elif any( dirpath.startswith( e ) for e in excluded_dirs ): + continue + for f in filelist: + filepath = os.path.join( dirpath, f ) + if exclude and IsIgnored( filepath, exclude ): + continue + if IsPythonFile( filepath ): + python_files.append( filepath ) + # To prevent it from scanning the contents excluded folders, os.walk() + # lets you amend its list of child dirs `dirnames`. These edits must be + # made in-place instead of creating a modified copy of `dirnames`. + # list.remove() is slow and list.pop() is a headache. Instead clear + # `dirnames` then repopulate it. + dirnames_ = [ dirnames.pop( 0 ) for i in range( len( dirnames ) ) ] + for dirname in dirnames_: + dir_ = os.path.join( dirpath, dirname ) + if IsIgnored( dir_, exclude ): + excluded_dirs.append( dir_ ) + else: + dirnames.append( dirname ) + + elif os.path.isfile( filename ): + python_files.append( filename ) + + return python_files + + +def IsIgnored( path, exclude ): + """Return True if filename matches any patterns in exclude.""" + if exclude is None: + return False + path = path.lstrip( os.path.sep ) + while path.startswith( '.' + os.path.sep ): + path = path[ 2 : ] + return any( fnmatch.fnmatch( path, e.rstrip( os.path.sep ) ) for e in exclude ) + + +def IsPythonFile( filename ): + """Return True if filename is a Python file.""" + if os.path.splitext( filename )[ 1 ] == '.py': + return True + + try: + with open( filename, 'rb' ) as fd: + encoding = py3compat.detect_encoding( fd.readline )[ 0 ] + + # Check for correctness of encoding. + with py3compat.open_with_encoding( filename, mode = 'r', + encoding = encoding ) as fd: + fd.read() + except UnicodeDecodeError: + encoding = 'latin-1' + except ( IOError, SyntaxError ): + # If we fail to detect encoding (or the encoding cookie is incorrect - which + # will make detect_encoding raise SyntaxError), assume it's not a Python + # file. + return False + + try: + with py3compat.open_with_encoding( filename, mode = 'r', + encoding = encoding ) as fd: + first_line = fd.readline( 256 ) + except IOError: + return False + + return re.match( r'^#!.*\bpython[23]?\b', first_line ) + + +def FileEncoding( filename ): + """Return the file's encoding.""" + with open( filename, 'rb' ) as fd: + return py3compat.detect_encoding( fd.readline )[ 0 ] diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index efcef0ba4..bd08aa9ba 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -33,8 +33,8 @@ from yapf.yapflib import subtypes -class FormatDecisionState(object): - """The current state when indenting a logical line. +class FormatDecisionState( object ): + """The current state when indenting a logical line. The FormatDecisionState object is meant to be copied instead of referenced. @@ -56,8 +56,8 @@ class FormatDecisionState(object): column_limit: The column limit specified by the style. """ - def __init__(self, line, first_indent): - """Initializer. + def __init__( self, line, first_indent ): + """Initializer. Initializes to the state after placing the first token from 'line' at 'first_indent'. @@ -66,62 +66,64 @@ def __init__(self, line, first_indent): line: (LogicalLine) The logical line we're currently processing. first_indent: (int) The indent of the first token. """ - self.next_token = line.first - self.column = first_indent - self.line = line - self.paren_level = 0 - self.lowest_level_on_line = 0 - self.ignore_stack_for_comparison = False - self.stack = [_ParenState(first_indent, first_indent)] - self.comp_stack = [] - self.param_list_stack = [] - self.first_indent = first_indent - self.column_limit = style.Get('COLUMN_LIMIT') - - def Clone(self): - """Clones a FormatDecisionState object.""" - new = FormatDecisionState(self.line, self.first_indent) - new.next_token = self.next_token - new.column = self.column - new.line = self.line - new.paren_level = self.paren_level - new.line.depth = self.line.depth - new.lowest_level_on_line = self.lowest_level_on_line - new.ignore_stack_for_comparison = self.ignore_stack_for_comparison - new.first_indent = self.first_indent - new.stack = [state.Clone() for state in self.stack] - new.comp_stack = [state.Clone() for state in self.comp_stack] - new.param_list_stack = [state.Clone() for state in self.param_list_stack] - return new - - def __eq__(self, other): - # Note: 'first_indent' is implicit in the stack. Also, we ignore 'previous', - # because it shouldn't have a bearing on this comparison. (I.e., it will - # report equal if 'next_token' does.) - return (self.next_token == other.next_token and - self.column == other.column and + self.next_token = line.first + self.column = first_indent + self.line = line + self.paren_level = 0 + self.lowest_level_on_line = 0 + self.ignore_stack_for_comparison = False + self.stack = [ _ParenState( first_indent, first_indent ) ] + self.comp_stack = [] + self.param_list_stack = [] + self.first_indent = first_indent + self.column_limit = style.Get( 'COLUMN_LIMIT' ) + + def Clone( self ): + """Clones a FormatDecisionState object.""" + new = FormatDecisionState( self.line, self.first_indent ) + new.next_token = self.next_token + new.column = self.column + new.line = self.line + new.paren_level = self.paren_level + new.line.depth = self.line.depth + new.lowest_level_on_line = self.lowest_level_on_line + new.ignore_stack_for_comparison = self.ignore_stack_for_comparison + new.first_indent = self.first_indent + new.stack = [ state.Clone() for state in self.stack ] + new.comp_stack = [ state.Clone() for state in self.comp_stack ] + new.param_list_stack = [ state.Clone() for state in self.param_list_stack ] + return new + + def __eq__( self, other ): + # Note: 'first_indent' is implicit in the stack. Also, we ignore 'previous', + # because it shouldn't have a bearing on this comparison. (I.e., it will + # report equal if 'next_token' does.) + return ( + self.next_token == other.next_token and self.column == other.column and self.paren_level == other.paren_level and self.line.depth == other.line.depth and - self.lowest_level_on_line == other.lowest_level_on_line and - (self.ignore_stack_for_comparison or - other.ignore_stack_for_comparison or self.stack == other.stack and - self.comp_stack == other.comp_stack and - self.param_list_stack == other.param_list_stack)) + self.lowest_level_on_line == other.lowest_level_on_line and ( + self.ignore_stack_for_comparison or other.ignore_stack_for_comparison or + self.stack == other.stack and self.comp_stack == other.comp_stack and + self.param_list_stack == other.param_list_stack ) ) - def __ne__(self, other): - return not self == other + def __ne__( self, other ): + return not self == other - def __hash__(self): - return hash((self.next_token, self.column, self.paren_level, - self.line.depth, self.lowest_level_on_line)) + def __hash__( self ): + return hash( + ( + self.next_token, self.column, self.paren_level, self.line.depth, + self.lowest_level_on_line ) ) - def __repr__(self): - return ('column::%d, next_token::%s, paren_level::%d, stack::[\n\t%s' % - (self.column, repr(self.next_token), self.paren_level, - '\n\t'.join(repr(s) for s in self.stack) + ']')) + def __repr__( self ): + return ( + 'column::%d, next_token::%s, paren_level::%d, stack::[\n\t%s' % ( + self.column, repr( self.next_token ), self.paren_level, + '\n\t'.join( repr( s ) for s in self.stack ) + ']' ) ) - def CanSplit(self, must_split): - """Determine if we can split before the next token. + def CanSplit( self, must_split ): + """Determine if we can split before the next token. Arguments: must_split: (bool) A newline was required before this token. @@ -129,436 +131,443 @@ def CanSplit(self, must_split): Returns: True if the line can be split before the next token. """ - current = self.next_token - previous = current.previous_token - - if current.is_pseudo: - return False - - if (not must_split and subtypes.DICTIONARY_KEY_PART in current.subtypes and - subtypes.DICTIONARY_KEY not in current.subtypes and - not style.Get('ALLOW_MULTILINE_DICTIONARY_KEYS')): - # In some situations, a dictionary may be multiline, but pylint doesn't - # like it. So don't allow it unless forced to. - return False - - if (not must_split and subtypes.DICTIONARY_VALUE in current.subtypes and - not style.Get('ALLOW_SPLIT_BEFORE_DICT_VALUE')): - return False - - if previous and previous.value == '(' and current.value == ')': - # Don't split an empty function call list if we aren't splitting before - # dict values. - token = previous.previous_token - while token: - prev = token.previous_token - if not prev or prev.name not in {'NAME', 'DOT'}: - break - token = token.previous_token - if token and subtypes.DICTIONARY_VALUE in token.subtypes: - if not style.Get('ALLOW_SPLIT_BEFORE_DICT_VALUE'): - return False - - if previous and previous.value == '.' and current.value == '.': - return False - - return current.can_break_before - - def MustSplit(self): - """Returns True if the line must split before the next token.""" - current = self.next_token - previous = current.previous_token - - if current.is_pseudo: - return False - - if current.must_break_before: - return True - - if not previous: - return False - - if style.Get('SPLIT_ALL_COMMA_SEPARATED_VALUES') and previous.value == ',': - return True - - if (style.Get('SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES') and - previous.value == ','): - # Avoid breaking in a container that fits in the current line if possible - opening = _GetOpeningBracket(current) - - # Can't find opening bracket, behave the same way as - # SPLIT_ALL_COMMA_SEPARATED_VALUES. - if not opening: - return True - - if current.is_comment: - # Don't require splitting before a comment, since it may be related to - # the current line. - return False + current = self.next_token + previous = current.previous_token - # Allow the fallthrough code to handle the closing bracket. - if current != opening.matching_bracket: - # If the container doesn't fit in the current line, must split - return not self._ContainerFitsOnStartLine(opening) - - if (self.stack[-1].split_before_closing_bracket and - (current.value in '}]' and style.Get('SPLIT_BEFORE_CLOSING_BRACKET') or - current.value in '}])' and style.Get('INDENT_CLOSING_BRACKETS'))): - # Split before the closing bracket if we can. - if subtypes.SUBSCRIPT_BRACKET not in current.subtypes: - return current.node_split_penalty != split_penalty.UNBREAKABLE - - if (current.value == ')' and previous.value == ',' and - not _IsSingleElementTuple(current.matching_bracket)): - return True - - # Prevent splitting before the first argument in compound statements - # with the exception of function declarations. - if (style.Get('SPLIT_BEFORE_FIRST_ARGUMENT') and - _IsCompoundStatement(self.line.first) and - not _IsFunctionDef(self.line.first)): - return False - - ########################################################################### - # List Splitting - if (style.Get('DEDENT_CLOSING_BRACKETS') or - style.Get('INDENT_CLOSING_BRACKETS') or - style.Get('SPLIT_BEFORE_FIRST_ARGUMENT')): - bracket = current if current.ClosesScope() else previous - if subtypes.SUBSCRIPT_BRACKET not in bracket.subtypes: - if bracket.OpensScope(): - if style.Get('COALESCE_BRACKETS'): - if current.OpensScope(): - # Prefer to keep all opening brackets together. - return False - - if (not _IsLastScopeInLine(bracket) or - logical_line.IsSurroundedByBrackets(bracket)): - last_token = bracket.matching_bracket - else: - last_token = _LastTokenInLine(bracket.matching_bracket) - - if not self._FitsOnLine(bracket, last_token): - # Split before the first element if the whole list can't fit on a - # single line. - self.stack[-1].split_before_closing_bracket = True - return True - - elif (style.Get('DEDENT_CLOSING_BRACKETS') or - style.Get('INDENT_CLOSING_BRACKETS')) and current.ClosesScope(): - # Split before and dedent the closing bracket. - return self.stack[-1].split_before_closing_bracket - - if (style.Get('SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN') and - current.is_name): - # An expression that's surrounded by parens gets split after the opening - # parenthesis. - def SurroundedByParens(token): - """Check if it's an expression surrounded by parentheses.""" - while token: - if token.value == ',': + if current.is_pseudo: return False - if token.value == ')': - return not token.next_token - if token.OpensScope(): - token = token.matching_bracket.next_token - else: - token = token.next_token - return False - if (previous.value == '(' and not previous.is_pseudo and - not logical_line.IsSurroundedByBrackets(previous)): - pptoken = previous.previous_token - if (pptoken and not pptoken.is_name and not pptoken.is_keyword and - SurroundedByParens(current)): - return True - - if (current.is_name or current.is_string) and previous.value == ',': - # If the list has function calls in it and the full list itself cannot - # fit on the line, then we want to split. Otherwise, we'll get something - # like this: - # - # X = [ - # Bar(xxx='some string', - # yyy='another long string', - # zzz='a third long string'), Bar( - # xxx='some string', - # yyy='another long string', - # zzz='a third long string') - # ] - # - # or when a string formatting syntax. - func_call_or_string_format = False - tok = current.next_token - if current.is_name: - while tok and (tok.is_name or tok.value == '.'): - tok = tok.next_token - func_call_or_string_format = tok and tok.value == '(' - elif current.is_string: - while tok and tok.is_string: - tok = tok.next_token - func_call_or_string_format = tok and tok.value == '%' - if func_call_or_string_format: - open_bracket = logical_line.IsSurroundedByBrackets(current) - if open_bracket: - if open_bracket.value in '[{': - if not self._FitsOnLine(open_bracket, - open_bracket.matching_bracket): - return True - elif tok.value == '(': - if not self._FitsOnLine(current, tok.matching_bracket): - return True - - if (current.OpensScope() and previous.value == ',' and - subtypes.DICTIONARY_KEY not in current.next_token.subtypes): - # If we have a list of tuples, then we can get a similar look as above. If - # the full list cannot fit on the line, then we want a split. - open_bracket = logical_line.IsSurroundedByBrackets(current) - if (open_bracket and open_bracket.value in '[{' and - subtypes.SUBSCRIPT_BRACKET not in open_bracket.subtypes): - if not self._FitsOnLine(current, current.matching_bracket): - return True - - ########################################################################### - # Dict/Set Splitting - if (style.Get('EACH_DICT_ENTRY_ON_SEPARATE_LINE') and - subtypes.DICTIONARY_KEY in current.subtypes and not current.is_comment): - # Place each dictionary entry onto its own line. - if previous.value == '{' and previous.previous_token: - opening = _GetOpeningBracket(previous.previous_token) - if (opening and opening.value == '(' and opening.previous_token and - opening.previous_token.is_name): - # This is a dictionary that's an argument to a function. - if (self._FitsOnLine(previous, previous.matching_bracket) and - previous.matching_bracket.next_token and - (not opening.matching_bracket.next_token or - opening.matching_bracket.next_token.value != '.') and - _ScopeHasNoCommas(previous)): - # Don't split before the key if: - # - The dictionary fits on a line, and - # - The function call isn't part of a builder-style call and - # - The dictionary has one entry and no trailing comma + if ( not must_split and subtypes.DICTIONARY_KEY_PART in current.subtypes and + subtypes.DICTIONARY_KEY not in current.subtypes and + not style.Get( 'ALLOW_MULTILINE_DICTIONARY_KEYS' ) ): + # In some situations, a dictionary may be multiline, but pylint doesn't + # like it. So don't allow it unless forced to. return False - return True - - if (style.Get('SPLIT_BEFORE_DICT_SET_GENERATOR') and - subtypes.DICT_SET_GENERATOR in current.subtypes): - # Split before a dict/set generator. - return True - - if (subtypes.DICTIONARY_VALUE in current.subtypes or - (previous.is_pseudo and previous.value == '(' and - not current.is_comment)): - # Split before the dictionary value if we can't fit every dictionary - # entry on its own line. - if not current.OpensScope(): - opening = _GetOpeningBracket(current) - if not self._EachDictEntryFitsOnOneLine(opening): - return style.Get('ALLOW_SPLIT_BEFORE_DICT_VALUE') - - if previous.value == '{': - # Split if the dict/set cannot fit on one line and ends in a comma. - closing = previous.matching_bracket - if (not self._FitsOnLine(previous, closing) and - closing.previous_token.value == ','): - self.stack[-1].split_before_closing_bracket = True - return True - - ########################################################################### - # Argument List Splitting - if (style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and not current.is_comment and - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in current.subtypes): - if (previous.value not in {'=', ':', '*', '**'} and - current.value not in ':=,)' and not _IsFunctionDefinition(previous)): - # If we're going to split the lines because of named arguments, then we - # want to split after the opening bracket as well. But not when this is - # part of a function definition. - if previous.value == '(': - # Make sure we don't split after the opening bracket if the - # continuation indent is greater than the opening bracket: - # - # a( - # b=1, - # c=2) - if (self._FitsOnLine(previous, previous.matching_bracket) and - logical_line.IsSurroundedByBrackets(previous)): - # An argument to a function is a function call with named - # assigns. + + if ( not must_split and subtypes.DICTIONARY_VALUE in current.subtypes and + not style.Get( 'ALLOW_SPLIT_BEFORE_DICT_VALUE' ) ): return False - # Don't split if not required - if (not style.Get('SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN') and - not style.Get('SPLIT_BEFORE_FIRST_ARGUMENT')): + if previous and previous.value == '(' and current.value == ')': + # Don't split an empty function call list if we aren't splitting before + # dict values. + token = previous.previous_token + while token: + prev = token.previous_token + if not prev or prev.name not in { 'NAME', 'DOT' }: + break + token = token.previous_token + if token and subtypes.DICTIONARY_VALUE in token.subtypes: + if not style.Get( 'ALLOW_SPLIT_BEFORE_DICT_VALUE' ): + return False + + if previous and previous.value == '.' and current.value == '.': return False - column = self.column - self.stack[-1].last_space - return column > style.Get('CONTINUATION_INDENT_WIDTH') + return current.can_break_before - opening = _GetOpeningBracket(current) - if opening: - return not self._ContainerFitsOnStartLine(opening) + def MustSplit( self ): + """Returns True if the line must split before the next token.""" + current = self.next_token + previous = current.previous_token - if (current.value not in '{)' and previous.value == '(' and - self._ArgumentListHasDictionaryEntry(current)): - return True + if current.is_pseudo: + return False - if style.Get('SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED'): - # Split before arguments in a function call or definition if the - # arguments are terminated by a comma. - opening = _GetOpeningBracket(current) - if opening and opening.previous_token and opening.previous_token.is_name: - if previous.value in '(,': - if opening.matching_bracket.previous_token.value == ',': + if current.must_break_before: return True - if ((current.is_name or current.value in {'*', '**'}) and - previous.value == ','): - # If we have a function call within an argument list and it won't fit on - # the remaining line, but it will fit on a line by itself, then go ahead - # and split before the call. - opening = _GetOpeningBracket(current) - if (opening and opening.value == '(' and opening.previous_token and - (opening.previous_token.is_name or - opening.previous_token.value in {'*', '**'})): - is_func_call = False - opening = current - while opening: - if opening.value == '(': - is_func_call = True - break - if (not (opening.is_name or opening.value in {'*', '**'}) and - opening.value != '.'): - break - opening = opening.next_token + if not previous: + return False - if is_func_call: - if (not self._FitsOnLine(current, opening.matching_bracket) or - (opening.matching_bracket.next_token and - opening.matching_bracket.next_token.value != ',' and - not opening.matching_bracket.next_token.ClosesScope())): + if style.Get( 'SPLIT_ALL_COMMA_SEPARATED_VALUES' ) and previous.value == ',': return True - pprevious = previous.previous_token - - # A function call with a dictionary as its first argument may result in - # unreadable formatting if the dictionary spans multiple lines. The - # dictionary itself is formatted just fine, but the remaining arguments are - # indented too far: - # - # function_call({ - # KEY_1: 'value one', - # KEY_2: 'value two', - # }, - # default=False) - if (current.value == '{' and previous.value == '(' and pprevious and - pprevious.is_name): - dict_end = current.matching_bracket - next_token = dict_end.next_token - if next_token.value == ',' and not self._FitsOnLine(current, dict_end): - return True - - if (current.is_name and pprevious and pprevious.is_name and - previous.value == '('): - - if (not self._FitsOnLine(previous, previous.matching_bracket) and - _IsFunctionCallWithArguments(current)): - # There is a function call, with more than 1 argument, where the first - # argument is itself a function call with arguments that does not fit - # into the line. In this specific case, if we split after the first - # argument's opening '(', then the formatting will look bad for the - # rest of the arguments. E.g.: - # - # outer_function_call(inner_function_call( - # inner_arg1, inner_arg2), - # outer_arg1, outer_arg2) - # - # Instead, enforce a split before that argument to keep things looking - # good. - if (style.Get('SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN') or - style.Get('SPLIT_BEFORE_FIRST_ARGUMENT')): - return True - - opening = _GetOpeningBracket(current) - if (opening and opening.value == '(' and opening.previous_token and - (opening.previous_token.is_name or - opening.previous_token.value in {'*', '**'})): - is_func_call = False - opening = current - while opening: - if opening.value == '(': - is_func_call = True - break - if (not (opening.is_name or opening.value in {'*', '**'}) and - opening.value != '.'): - break - opening = opening.next_token - - if is_func_call: - if (not self._FitsOnLine(current, opening.matching_bracket) or - (opening.matching_bracket.next_token and - opening.matching_bracket.next_token.value != ',' and - not opening.matching_bracket.next_token.ClosesScope())): - return True - - if (previous.OpensScope() and not current.OpensScope() and - not current.is_comment and - subtypes.SUBSCRIPT_BRACKET not in previous.subtypes): - if pprevious and not pprevious.is_keyword and not pprevious.is_name: - # We want to split if there's a comment in the container. - token = current - while token != previous.matching_bracket: - if token.is_comment: + if ( style.Get( 'SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES' ) and + previous.value == ',' ): + # Avoid breaking in a container that fits in the current line if possible + opening = _GetOpeningBracket( current ) + + # Can't find opening bracket, behave the same way as + # SPLIT_ALL_COMMA_SEPARATED_VALUES. + if not opening: + return True + + if current.is_comment: + # Don't require splitting before a comment, since it may be related to + # the current line. + return False + + # Allow the fallthrough code to handle the closing bracket. + if current != opening.matching_bracket: + # If the container doesn't fit in the current line, must split + return not self._ContainerFitsOnStartLine( opening ) + + if ( self.stack[ -1 ].split_before_closing_bracket and + ( current.value in '}]' and style.Get( 'SPLIT_BEFORE_CLOSING_BRACKET' ) or + current.value in '}])' and style.Get( 'INDENT_CLOSING_BRACKETS' ) ) ): + # Split before the closing bracket if we can. + if subtypes.SUBSCRIPT_BRACKET not in current.subtypes: + return current.node_split_penalty != split_penalty.UNBREAKABLE + + if ( current.value == ')' and previous.value == ',' and + not _IsSingleElementTuple( current.matching_bracket ) ): return True - token = token.next_token - if previous.value == '(': - pptoken = previous.previous_token - if not pptoken or not pptoken.is_name: - # Split after the opening of a tuple if it doesn't fit on the current - # line and it's not a function call. - if self._FitsOnLine(previous, previous.matching_bracket): - return False - elif not self._FitsOnLine(previous, previous.matching_bracket): - if len(previous.container_elements) == 1: + + # Prevent splitting before the first argument in compound statements + # with the exception of function declarations. + if ( style.Get( 'SPLIT_BEFORE_FIRST_ARGUMENT' ) and + _IsCompoundStatement( self.line.first ) and + not _IsFunctionDef( self.line.first ) ): return False - elements = previous.container_elements + [previous.matching_bracket] - i = 1 - while i < len(elements): - if (not elements[i - 1].OpensScope() and - not self._FitsOnLine(elements[i - 1], elements[i])): - return True - i += 1 + ########################################################################### + # List Splitting + if ( style.Get( 'DEDENT_CLOSING_BRACKETS' ) or + style.Get( 'INDENT_CLOSING_BRACKETS' ) or + style.Get( 'SPLIT_BEFORE_FIRST_ARGUMENT' ) ): + bracket = current if current.ClosesScope() else previous + if subtypes.SUBSCRIPT_BRACKET not in bracket.subtypes: + if bracket.OpensScope(): + if style.Get( 'COALESCE_BRACKETS' ): + if current.OpensScope(): + # Prefer to keep all opening brackets together. + return False + + if ( not _IsLastScopeInLine( bracket ) or + logical_line.IsSurroundedByBrackets( bracket ) ): + last_token = bracket.matching_bracket + else: + last_token = _LastTokenInLine( bracket.matching_bracket ) + + if not self._FitsOnLine( bracket, last_token ): + # Split before the first element if the whole list can't fit on a + # single line. + self.stack[ -1 ].split_before_closing_bracket = True + return True + + elif ( style.Get( 'DEDENT_CLOSING_BRACKETS' ) or + style.Get( 'INDENT_CLOSING_BRACKETS' ) + ) and current.ClosesScope(): + # Split before and dedent the closing bracket. + return self.stack[ -1 ].split_before_closing_bracket + + if ( style.Get( 'SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN' ) and + current.is_name ): + # An expression that's surrounded by parens gets split after the opening + # parenthesis. + def SurroundedByParens( token ): + """Check if it's an expression surrounded by parentheses.""" + while token: + if token.value == ',': + return False + if token.value == ')': + return not token.next_token + if token.OpensScope(): + token = token.matching_bracket.next_token + else: + token = token.next_token + return False + + if ( previous.value == '(' and not previous.is_pseudo and + not logical_line.IsSurroundedByBrackets( previous ) ): + pptoken = previous.previous_token + if ( pptoken and not pptoken.is_name and not pptoken.is_keyword and + SurroundedByParens( current ) ): + return True + + if ( current.is_name or current.is_string ) and previous.value == ',': + # If the list has function calls in it and the full list itself cannot + # fit on the line, then we want to split. Otherwise, we'll get something + # like this: + # + # X = [ + # Bar(xxx='some string', + # yyy='another long string', + # zzz='a third long string'), Bar( + # xxx='some string', + # yyy='another long string', + # zzz='a third long string') + # ] + # + # or when a string formatting syntax. + func_call_or_string_format = False + tok = current.next_token + if current.is_name: + while tok and ( tok.is_name or tok.value == '.' ): + tok = tok.next_token + func_call_or_string_format = tok and tok.value == '(' + elif current.is_string: + while tok and tok.is_string: + tok = tok.next_token + func_call_or_string_format = tok and tok.value == '%' + if func_call_or_string_format: + open_bracket = logical_line.IsSurroundedByBrackets( current ) + if open_bracket: + if open_bracket.value in '[{': + if not self._FitsOnLine( open_bracket, + open_bracket.matching_bracket ): + return True + elif tok.value == '(': + if not self._FitsOnLine( current, tok.matching_bracket ): + return True + + if ( current.OpensScope() and previous.value == ',' and + subtypes.DICTIONARY_KEY not in current.next_token.subtypes ): + # If we have a list of tuples, then we can get a similar look as above. If + # the full list cannot fit on the line, then we want a split. + open_bracket = logical_line.IsSurroundedByBrackets( current ) + if ( open_bracket and open_bracket.value in '[{' and + subtypes.SUBSCRIPT_BRACKET not in open_bracket.subtypes ): + if not self._FitsOnLine( current, current.matching_bracket ): + return True + + ########################################################################### + # Dict/Set Splitting + if ( style.Get( 'EACH_DICT_ENTRY_ON_SEPARATE_LINE' ) and + subtypes.DICTIONARY_KEY in current.subtypes and not current.is_comment ): + # Place each dictionary entry onto its own line. + if previous.value == '{' and previous.previous_token: + opening = _GetOpeningBracket( previous.previous_token ) + if ( opening and opening.value == '(' and opening.previous_token and + opening.previous_token.is_name ): + # This is a dictionary that's an argument to a function. + if ( self._FitsOnLine( previous, previous.matching_bracket ) and + previous.matching_bracket.next_token and + ( not opening.matching_bracket.next_token or + opening.matching_bracket.next_token.value != '.' ) and + _ScopeHasNoCommas( previous ) ): + # Don't split before the key if: + # - The dictionary fits on a line, and + # - The function call isn't part of a builder-style call and + # - The dictionary has one entry and no trailing comma + return False + return True - if (self.column_limit - self.column) / float(self.column_limit) < 0.3: - # Try not to squish all of the arguments off to the right. + if ( style.Get( 'SPLIT_BEFORE_DICT_SET_GENERATOR' ) and + subtypes.DICT_SET_GENERATOR in current.subtypes ): + # Split before a dict/set generator. return True - else: - # Split after the opening of a container if it doesn't fit on the - # current line. - if not self._FitsOnLine(previous, previous.matching_bracket): - return True - - ########################################################################### - # Original Formatting Splitting - # These checks rely upon the original formatting. This is in order to - # attempt to keep hand-written code in the same condition as it was before. - # However, this may cause the formatter to fail to be idempotent. - if (style.Get('SPLIT_BEFORE_BITWISE_OPERATOR') and current.value in '&|' and - previous.lineno < current.lineno): - # Retain the split before a bitwise operator. - return True - - if (current.is_comment and - previous.lineno < current.lineno - current.value.count('\n')): - # If a comment comes in the middle of a logical line (like an if - # conditional with comments interspersed), then we want to split if the - # original comments were on a separate line. - return True - return False + if ( subtypes.DICTIONARY_VALUE in current.subtypes or + ( previous.is_pseudo and previous.value == '(' and + not current.is_comment ) ): + # Split before the dictionary value if we can't fit every dictionary + # entry on its own line. + if not current.OpensScope(): + opening = _GetOpeningBracket( current ) + if not self._EachDictEntryFitsOnOneLine( opening ): + return style.Get( 'ALLOW_SPLIT_BEFORE_DICT_VALUE' ) + + if previous.value == '{': + # Split if the dict/set cannot fit on one line and ends in a comma. + closing = previous.matching_bracket + if ( not self._FitsOnLine( previous, closing ) and + closing.previous_token.value == ',' ): + self.stack[ -1 ].split_before_closing_bracket = True + return True + + ########################################################################### + # Argument List Splitting + if ( style.Get( 'SPLIT_BEFORE_NAMED_ASSIGNS' ) and not current.is_comment and + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in current.subtypes ): + if ( previous.value not in { '=', ':', '*', '**' } and + current.value not in ':=,)' and + not _IsFunctionDefinition( previous ) ): + # If we're going to split the lines because of named arguments, then we + # want to split after the opening bracket as well. But not when this is + # part of a function definition. + if previous.value == '(': + # Make sure we don't split after the opening bracket if the + # continuation indent is greater than the opening bracket: + # + # a( + # b=1, + # c=2) + if ( self._FitsOnLine( previous, previous.matching_bracket ) and + logical_line.IsSurroundedByBrackets( previous ) ): + # An argument to a function is a function call with named + # assigns. + return False + + # Don't split if not required + if ( not style.Get( 'SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN' ) + and not style.Get( 'SPLIT_BEFORE_FIRST_ARGUMENT' ) ): + return False + + column = self.column - self.stack[ -1 ].last_space + return column > style.Get( 'CONTINUATION_INDENT_WIDTH' ) + + opening = _GetOpeningBracket( current ) + if opening: + return not self._ContainerFitsOnStartLine( opening ) + + if ( current.value not in '{)' and previous.value == '(' and + self._ArgumentListHasDictionaryEntry( current ) ): + return True - def AddTokenToState(self, newline, dry_run, must_split=False): - """Add a token to the format decision state. + if style.Get( 'SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED' ): + # Split before arguments in a function call or definition if the + # arguments are terminated by a comma. + opening = _GetOpeningBracket( current ) + if opening and opening.previous_token and opening.previous_token.is_name: + if previous.value in '(,': + if opening.matching_bracket.previous_token.value == ',': + return True + + if ( ( current.is_name or current.value in { '*', '**' } ) and + previous.value == ',' ): + # If we have a function call within an argument list and it won't fit on + # the remaining line, but it will fit on a line by itself, then go ahead + # and split before the call. + opening = _GetOpeningBracket( current ) + if ( opening and opening.value == '(' and opening.previous_token and + ( opening.previous_token.is_name or + opening.previous_token.value in { '*', '**' } ) ): + is_func_call = False + opening = current + while opening: + if opening.value == '(': + is_func_call = True + break + if ( not ( opening.is_name or opening.value in { '*', '**' } ) and + opening.value != '.' ): + break + opening = opening.next_token + + if is_func_call: + if ( not self._FitsOnLine( current, opening.matching_bracket ) or + ( opening.matching_bracket.next_token and + opening.matching_bracket.next_token.value != ',' and + not opening.matching_bracket.next_token.ClosesScope() ) ): + return True + + pprevious = previous.previous_token + + # A function call with a dictionary as its first argument may result in + # unreadable formatting if the dictionary spans multiple lines. The + # dictionary itself is formatted just fine, but the remaining arguments are + # indented too far: + # + # function_call({ + # KEY_1: 'value one', + # KEY_2: 'value two', + # }, + # default=False) + if ( current.value == '{' and previous.value == '(' and pprevious and + pprevious.is_name ): + dict_end = current.matching_bracket + next_token = dict_end.next_token + if next_token.value == ',' and not self._FitsOnLine( current, dict_end ): + return True + + if ( current.is_name and pprevious and pprevious.is_name and + previous.value == '(' ): + + if ( not self._FitsOnLine( previous, previous.matching_bracket ) and + _IsFunctionCallWithArguments( current ) ): + # There is a function call, with more than 1 argument, where the first + # argument is itself a function call with arguments that does not fit + # into the line. In this specific case, if we split after the first + # argument's opening '(', then the formatting will look bad for the + # rest of the arguments. E.g.: + # + # outer_function_call(inner_function_call( + # inner_arg1, inner_arg2), + # outer_arg1, outer_arg2) + # + # Instead, enforce a split before that argument to keep things looking + # good. + if ( style.Get( 'SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN' ) or + style.Get( 'SPLIT_BEFORE_FIRST_ARGUMENT' ) ): + return True + + opening = _GetOpeningBracket( current ) + if ( opening and opening.value == '(' and opening.previous_token and + ( opening.previous_token.is_name or + opening.previous_token.value in { '*', '**' } ) ): + is_func_call = False + opening = current + while opening: + if opening.value == '(': + is_func_call = True + break + if ( not ( opening.is_name or opening.value in { '*', '**' } ) + and opening.value != '.' ): + break + opening = opening.next_token + + if is_func_call: + if ( + not self._FitsOnLine( current, + opening.matching_bracket ) or + ( opening.matching_bracket.next_token and + opening.matching_bracket.next_token.value != ',' and + not opening.matching_bracket.next_token.ClosesScope() ) ): + return True + + if ( previous.OpensScope() and not current.OpensScope() and + not current.is_comment and + subtypes.SUBSCRIPT_BRACKET not in previous.subtypes ): + if pprevious and not pprevious.is_keyword and not pprevious.is_name: + # We want to split if there's a comment in the container. + token = current + while token != previous.matching_bracket: + if token.is_comment: + return True + token = token.next_token + if previous.value == '(': + pptoken = previous.previous_token + if not pptoken or not pptoken.is_name: + # Split after the opening of a tuple if it doesn't fit on the current + # line and it's not a function call. + if self._FitsOnLine( previous, previous.matching_bracket ): + return False + elif not self._FitsOnLine( previous, previous.matching_bracket ): + if len( previous.container_elements ) == 1: + return False + + elements = previous.container_elements + [ + previous.matching_bracket + ] + i = 1 + while i < len( elements ): + if ( not elements[ i - 1 ].OpensScope() and + not self._FitsOnLine( elements[ i - 1 ], elements[ i ] ) ): + return True + i += 1 + + if ( self.column_limit - self.column ) / float( + self.column_limit ) < 0.3: + # Try not to squish all of the arguments off to the right. + return True + else: + # Split after the opening of a container if it doesn't fit on the + # current line. + if not self._FitsOnLine( previous, previous.matching_bracket ): + return True + + ########################################################################### + # Original Formatting Splitting + # These checks rely upon the original formatting. This is in order to + # attempt to keep hand-written code in the same condition as it was before. + # However, this may cause the formatter to fail to be idempotent. + if ( style.Get( 'SPLIT_BEFORE_BITWISE_OPERATOR' ) and current.value in '&|' and + previous.lineno < current.lineno ): + # Retain the split before a bitwise operator. + return True + + if ( current.is_comment and + previous.lineno < current.lineno - current.value.count( '\n' ) ): + # If a comment comes in the middle of a logical line (like an if + # conditional with comments interspersed), then we want to split if the + # original comments were on a separate line. + return True + + return False + + def AddTokenToState( self, newline, dry_run, must_split = False ): + """Add a token to the format decision state. Allow the heuristic to try out adding the token with and without a newline. Later on, the algorithm will determine which one has the lowest penalty. @@ -572,21 +581,21 @@ def AddTokenToState(self, newline, dry_run, must_split=False): Returns: The penalty of splitting after the current token. """ - self._PushParameterListState(newline) + self._PushParameterListState( newline ) - penalty = 0 - if newline: - penalty = self._AddTokenOnNewline(dry_run, must_split) - else: - self._AddTokenOnCurrentLine(dry_run) + penalty = 0 + if newline: + penalty = self._AddTokenOnNewline( dry_run, must_split ) + else: + self._AddTokenOnCurrentLine( dry_run ) - penalty += self._CalculateComprehensionState(newline) - penalty += self._CalculateParameterListState(newline) + penalty += self._CalculateComprehensionState( newline ) + penalty += self._CalculateParameterListState( newline ) - return self.MoveStateToNextToken() + penalty + return self.MoveStateToNextToken() + penalty - def _AddTokenOnCurrentLine(self, dry_run): - """Puts the token on the current line. + def _AddTokenOnCurrentLine( self, dry_run ): + """Puts the token on the current line. Appends the next token to the state and updates information necessary for indentation. @@ -594,37 +603,37 @@ def _AddTokenOnCurrentLine(self, dry_run): Arguments: dry_run: (bool) Commit whitespace changes to the FormatToken if True. """ - current = self.next_token - previous = current.previous_token - - spaces = current.spaces_required_before - if isinstance(spaces, list): - # Don't set the value here, as we need to look at the lines near - # this one to determine the actual horizontal alignment value. - spaces = 0 - - if not dry_run: - current.AddWhitespacePrefix(newlines_before=0, spaces=spaces) - - if previous.OpensScope(): - if not current.is_comment: - # Align closing scopes that are on a newline with the opening scope: - # - # foo = [a, - # b, - # ] - self.stack[-1].closing_scope_indent = self.column - 1 - if style.Get('ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'): - self.stack[-1].closing_scope_indent += 1 - self.stack[-1].indent = self.column + spaces - else: - self.stack[-1].closing_scope_indent = ( - self.stack[-1].indent - style.Get('CONTINUATION_INDENT_WIDTH')) - - self.column += spaces - - def _AddTokenOnNewline(self, dry_run, must_split): - """Adds a line break and necessary indentation. + current = self.next_token + previous = current.previous_token + + spaces = current.spaces_required_before + if isinstance( spaces, list ): + # Don't set the value here, as we need to look at the lines near + # this one to determine the actual horizontal alignment value. + spaces = 0 + + if not dry_run: + current.AddWhitespacePrefix( newlines_before = 0, spaces = spaces ) + + if previous.OpensScope(): + if not current.is_comment: + # Align closing scopes that are on a newline with the opening scope: + # + # foo = [a, + # b, + # ] + self.stack[ -1 ].closing_scope_indent = self.column - 1 + if style.Get( 'ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT' ): + self.stack[ -1 ].closing_scope_indent += 1 + self.stack[ -1 ].indent = self.column + spaces + else: + self.stack[ -1 ].closing_scope_indent = ( + self.stack[ -1 ].indent - style.Get( 'CONTINUATION_INDENT_WIDTH' ) ) + + self.column += spaces + + def _AddTokenOnNewline( self, dry_run, must_split ): + """Adds a line break and necessary indentation. Appends the next token to the state and updates information necessary for indentation. @@ -637,63 +646,63 @@ def _AddTokenOnNewline(self, dry_run, must_split): Returns: The split penalty for splitting after the current state. """ - current = self.next_token - previous = current.previous_token - - self.column = self._GetNewlineColumn() - - if not dry_run: - indent_level = self.line.depth - spaces = self.column - if spaces: - spaces -= indent_level * style.Get('INDENT_WIDTH') - current.AddWhitespacePrefix( - newlines_before=1, spaces=spaces, indent_level=indent_level) - - if not current.is_comment: - self.stack[-1].last_space = self.column - self.lowest_level_on_line = self.paren_level - - if (previous.OpensScope() or - (previous.is_comment and previous.previous_token is not None and - previous.previous_token.OpensScope())): - dedent = (style.Get('CONTINUATION_INDENT_WIDTH'), - 0)[style.Get('INDENT_CLOSING_BRACKETS')] - self.stack[-1].closing_scope_indent = ( - max(0, self.stack[-1].indent - dedent)) - self.stack[-1].split_before_closing_bracket = True - - # Calculate the split penalty. - penalty = current.split_penalty - - if must_split: - # Don't penalize for a must split. - return penalty - - if previous.is_pseudo and previous.value == '(': - # Small penalty for splitting after a pseudo paren. - penalty += 50 - - # Add a penalty for each increasing newline we add, but don't penalize for - # splitting before an if-expression or list comprehension. - if current.value not in {'if', 'for'}: - last = self.stack[-1] - last.num_line_splits += 1 - penalty += ( - style.Get('SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT') * - last.num_line_splits) - - if current.OpensScope() and previous.OpensScope(): - # Prefer to keep opening brackets coalesced (unless it's at the beginning - # of a function call). - pprev = previous.previous_token - if not pprev or not pprev.is_name: - penalty += 10 - - return penalty + 10 - - def MoveStateToNextToken(self): - """Calculate format decision state information and move onto the next token. + current = self.next_token + previous = current.previous_token + + self.column = self._GetNewlineColumn() + + if not dry_run: + indent_level = self.line.depth + spaces = self.column + if spaces: + spaces -= indent_level * style.Get( 'INDENT_WIDTH' ) + current.AddWhitespacePrefix( + newlines_before = 1, spaces = spaces, indent_level = indent_level ) + + if not current.is_comment: + self.stack[ -1 ].last_space = self.column + self.lowest_level_on_line = self.paren_level + + if ( previous.OpensScope() or + ( previous.is_comment and previous.previous_token is not None and + previous.previous_token.OpensScope() ) ): + dedent = ( style.Get( 'CONTINUATION_INDENT_WIDTH' ), + 0 )[ style.Get( 'INDENT_CLOSING_BRACKETS' ) ] + self.stack[ -1 ].closing_scope_indent = ( + max( 0, self.stack[ -1 ].indent - dedent ) ) + self.stack[ -1 ].split_before_closing_bracket = True + + # Calculate the split penalty. + penalty = current.split_penalty + + if must_split: + # Don't penalize for a must split. + return penalty + + if previous.is_pseudo and previous.value == '(': + # Small penalty for splitting after a pseudo paren. + penalty += 50 + + # Add a penalty for each increasing newline we add, but don't penalize for + # splitting before an if-expression or list comprehension. + if current.value not in { 'if', 'for' }: + last = self.stack[ -1 ] + last.num_line_splits += 1 + penalty += ( + style.Get( 'SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT' ) * + last.num_line_splits ) + + if current.OpensScope() and previous.OpensScope(): + # Prefer to keep opening brackets coalesced (unless it's at the beginning + # of a function call). + pprev = previous.previous_token + if not pprev or not pprev.is_name: + penalty += 10 + + return penalty + 10 + + def MoveStateToNextToken( self ): + """Calculate format decision state information and move onto the next token. Before moving onto the next token, we first calculate the format decision state given the current token and its formatting decisions. Then the format @@ -702,55 +711,55 @@ def MoveStateToNextToken(self): Returns: The penalty for the number of characters over the column limit. """ - current = self.next_token - if not current.OpensScope() and not current.ClosesScope(): - self.lowest_level_on_line = min(self.lowest_level_on_line, - self.paren_level) - - # If we encounter an opening bracket, we add a level to our stack to prepare - # for the subsequent tokens. - if current.OpensScope(): - last = self.stack[-1] - new_indent = style.Get('CONTINUATION_INDENT_WIDTH') + last.last_space - - self.stack.append(_ParenState(new_indent, self.stack[-1].last_space)) - self.paren_level += 1 - - # If we encounter a closing bracket, we can remove a level from our - # parenthesis stack. - if len(self.stack) > 1 and current.ClosesScope(): - if subtypes.DICTIONARY_KEY_PART in current.subtypes: - self.stack[-2].last_space = self.stack[-2].indent - else: - self.stack[-2].last_space = self.stack[-1].last_space - self.stack.pop() - self.paren_level -= 1 - - is_multiline_string = current.is_string and '\n' in current.value - if is_multiline_string: - # This is a multiline string. Only look at the first line. - self.column += len(current.value.split('\n')[0]) - elif not current.is_pseudo: - self.column += len(current.value) - - self.next_token = self.next_token.next_token - - # Calculate the penalty for overflowing the column limit. - penalty = 0 - if (not current.is_pylint_comment and not current.is_pytype_comment and - not current.is_copybara_comment and self.column > self.column_limit): - excess_characters = self.column - self.column_limit - penalty += style.Get('SPLIT_PENALTY_EXCESS_CHARACTER') * excess_characters - - if is_multiline_string: - # If this is a multiline string, the column is actually the - # end of the last line in the string. - self.column = len(current.value.split('\n')[-1]) - - return penalty - - def _CalculateComprehensionState(self, newline): - """Makes required changes to comprehension state. + current = self.next_token + if not current.OpensScope() and not current.ClosesScope(): + self.lowest_level_on_line = min( + self.lowest_level_on_line, self.paren_level ) + + # If we encounter an opening bracket, we add a level to our stack to prepare + # for the subsequent tokens. + if current.OpensScope(): + last = self.stack[ -1 ] + new_indent = style.Get( 'CONTINUATION_INDENT_WIDTH' ) + last.last_space + + self.stack.append( _ParenState( new_indent, self.stack[ -1 ].last_space ) ) + self.paren_level += 1 + + # If we encounter a closing bracket, we can remove a level from our + # parenthesis stack. + if len( self.stack ) > 1 and current.ClosesScope(): + if subtypes.DICTIONARY_KEY_PART in current.subtypes: + self.stack[ -2 ].last_space = self.stack[ -2 ].indent + else: + self.stack[ -2 ].last_space = self.stack[ -1 ].last_space + self.stack.pop() + self.paren_level -= 1 + + is_multiline_string = current.is_string and '\n' in current.value + if is_multiline_string: + # This is a multiline string. Only look at the first line. + self.column += len( current.value.split( '\n' )[ 0 ] ) + elif not current.is_pseudo: + self.column += len( current.value ) + + self.next_token = self.next_token.next_token + + # Calculate the penalty for overflowing the column limit. + penalty = 0 + if ( not current.is_pylint_comment and not current.is_pytype_comment and + not current.is_copybara_comment and self.column > self.column_limit ): + excess_characters = self.column - self.column_limit + penalty += style.Get( 'SPLIT_PENALTY_EXCESS_CHARACTER' ) * excess_characters + + if is_multiline_string: + # If this is a multiline string, the column is actually the + # end of the last line in the string. + self.column = len( current.value.split( '\n' )[ -1 ] ) + + return penalty + + def _CalculateComprehensionState( self, newline ): + """Makes required changes to comprehension state. Args: newline: Whether the current token is to be added on a newline. @@ -759,81 +768,82 @@ def _CalculateComprehensionState(self, newline): The penalty for the token-newline combination given the current comprehension state. """ - current = self.next_token - previous = current.previous_token - top_of_stack = self.comp_stack[-1] if self.comp_stack else None - penalty = 0 - - if top_of_stack is not None: - # Check if the token terminates the current comprehension. - if current == top_of_stack.closing_bracket: - last = self.comp_stack.pop() - # Lightly penalize comprehensions that are split across multiple lines. - if last.has_interior_split: - penalty += style.Get('SPLIT_PENALTY_COMPREHENSION') + current = self.next_token + previous = current.previous_token + top_of_stack = self.comp_stack[ -1 ] if self.comp_stack else None + penalty = 0 + + if top_of_stack is not None: + # Check if the token terminates the current comprehension. + if current == top_of_stack.closing_bracket: + last = self.comp_stack.pop() + # Lightly penalize comprehensions that are split across multiple lines. + if last.has_interior_split: + penalty += style.Get( 'SPLIT_PENALTY_COMPREHENSION' ) + + return penalty + + if newline: + top_of_stack.has_interior_split = True + + if ( subtypes.COMP_EXPR in current.subtypes and + subtypes.COMP_EXPR not in previous.subtypes ): + self.comp_stack.append( object_state.ComprehensionState( current ) ) + return penalty + + if current.value == 'for' and subtypes.COMP_FOR in current.subtypes: + if top_of_stack.for_token is not None: + # Treat nested comprehensions like normal comp_if expressions. + # Example: + # my_comp = [ + # a.qux + b.qux + # for a in foo + # --> for b in bar <-- + # if a.zut + b.zut + # ] + if ( style.Get( 'SPLIT_COMPLEX_COMPREHENSION' ) and + top_of_stack.has_split_at_for != newline and + ( top_of_stack.has_split_at_for or + not top_of_stack.HasTrivialExpr() ) ): + penalty += split_penalty.UNBREAKABLE + else: + top_of_stack.for_token = current + top_of_stack.has_split_at_for = newline + + # Try to keep trivial expressions on the same line as the comp_for. + if ( style.Get( 'SPLIT_COMPLEX_COMPREHENSION' ) and newline and + top_of_stack.HasTrivialExpr() ): + penalty += split_penalty.CONNECTED + + if ( subtypes.COMP_IF in current.subtypes and + subtypes.COMP_IF not in previous.subtypes ): + # Penalize breaking at comp_if when it doesn't match the newline structure + # in the rest of the comprehension. + if ( style.Get( 'SPLIT_COMPLEX_COMPREHENSION' ) and + top_of_stack.has_split_at_for != newline and + ( top_of_stack.has_split_at_for or + not top_of_stack.HasTrivialExpr() ) ): + penalty += split_penalty.UNBREAKABLE return penalty - if newline: - top_of_stack.has_interior_split = True - - if (subtypes.COMP_EXPR in current.subtypes and - subtypes.COMP_EXPR not in previous.subtypes): - self.comp_stack.append(object_state.ComprehensionState(current)) - return penalty - - if current.value == 'for' and subtypes.COMP_FOR in current.subtypes: - if top_of_stack.for_token is not None: - # Treat nested comprehensions like normal comp_if expressions. - # Example: - # my_comp = [ - # a.qux + b.qux - # for a in foo - # --> for b in bar <-- - # if a.zut + b.zut - # ] - if (style.Get('SPLIT_COMPLEX_COMPREHENSION') and - top_of_stack.has_split_at_for != newline and - (top_of_stack.has_split_at_for or - not top_of_stack.HasTrivialExpr())): - penalty += split_penalty.UNBREAKABLE - else: - top_of_stack.for_token = current - top_of_stack.has_split_at_for = newline - - # Try to keep trivial expressions on the same line as the comp_for. - if (style.Get('SPLIT_COMPLEX_COMPREHENSION') and newline and - top_of_stack.HasTrivialExpr()): - penalty += split_penalty.CONNECTED - - if (subtypes.COMP_IF in current.subtypes and - subtypes.COMP_IF not in previous.subtypes): - # Penalize breaking at comp_if when it doesn't match the newline structure - # in the rest of the comprehension. - if (style.Get('SPLIT_COMPLEX_COMPREHENSION') and - top_of_stack.has_split_at_for != newline and - (top_of_stack.has_split_at_for or not top_of_stack.HasTrivialExpr())): - penalty += split_penalty.UNBREAKABLE - - return penalty - - def _PushParameterListState(self, newline): - """Push a new parameter list state for a function definition. + def _PushParameterListState( self, newline ): + """Push a new parameter list state for a function definition. Args: newline: Whether the current token is to be added on a newline. """ - current = self.next_token - previous = current.previous_token + current = self.next_token + previous = current.previous_token - if _IsFunctionDefinition(previous): - first_param_column = previous.total_length + self.stack[-2].indent - self.param_list_stack.append( - object_state.ParameterListState(previous, newline, - first_param_column)) + if _IsFunctionDefinition( previous ): + first_param_column = previous.total_length + self.stack[ -2 ].indent + self.param_list_stack.append( + object_state.ParameterListState( + previous, newline, first_param_column ) ) - def _CalculateParameterListState(self, newline): - """Makes required changes to parameter list state. + def _CalculateParameterListState( self, newline ): + """Makes required changes to parameter list state. Args: newline: Whether the current token is to be added on a newline. @@ -842,353 +852,355 @@ def _CalculateParameterListState(self, newline): The penalty for the token-newline combination given the current parameter state. """ - current = self.next_token - previous = current.previous_token - penalty = 0 - - if _IsFunctionDefinition(previous): - first_param_column = previous.total_length + self.stack[-2].indent - if not newline: - param_list = self.param_list_stack[-1] - if param_list.parameters and param_list.has_typed_return: - last_param = param_list.parameters[-1].first_token - last_token = _LastTokenInLine(previous.matching_bracket) - total_length = last_token.total_length - total_length -= last_param.total_length - len(last_param.value) - if total_length + self.column > self.column_limit: - # If we need to split before the trailing code of a function - # definition with return types, then also split before the opening - # parameter so that the trailing bit isn't indented on a line by - # itself: - # - # def rrrrrrrrrrrrrrrrrrrrrr(ccccccccccccccccccccccc: Tuple[Text] - # ) -> List[Tuple[Text, Text]]: - # pass - penalty += split_penalty.VERY_STRONGLY_CONNECTED + current = self.next_token + previous = current.previous_token + penalty = 0 + + if _IsFunctionDefinition( previous ): + first_param_column = previous.total_length + self.stack[ -2 ].indent + if not newline: + param_list = self.param_list_stack[ -1 ] + if param_list.parameters and param_list.has_typed_return: + last_param = param_list.parameters[ -1 ].first_token + last_token = _LastTokenInLine( previous.matching_bracket ) + total_length = last_token.total_length + total_length -= last_param.total_length - len( last_param.value ) + if total_length + self.column > self.column_limit: + # If we need to split before the trailing code of a function + # definition with return types, then also split before the opening + # parameter so that the trailing bit isn't indented on a line by + # itself: + # + # def rrrrrrrrrrrrrrrrrrrrrr(ccccccccccccccccccccccc: Tuple[Text] + # ) -> List[Tuple[Text, Text]]: + # pass + penalty += split_penalty.VERY_STRONGLY_CONNECTED + return penalty + + if first_param_column <= self.column: + # Make sure we don't split after the opening bracket if the + # continuation indent is greater than the opening bracket: + # + # a( + # b=1, + # c=2) + penalty += split_penalty.VERY_STRONGLY_CONNECTED + return penalty + + if not self.param_list_stack: + return penalty + + param_list = self.param_list_stack[ -1 ] + if current == self.param_list_stack[ -1 ].closing_bracket: + self.param_list_stack.pop() # We're done with this state. + if newline and param_list.has_typed_return: + if param_list.split_before_closing_bracket: + penalty -= split_penalty.STRONGLY_CONNECTED + elif param_list.LastParamFitsOnLine( self.column ): + penalty += split_penalty.STRONGLY_CONNECTED + + if ( not newline and param_list.has_typed_return and + param_list.has_split_before_first_param ): + # Prefer splitting before the closing bracket if there's a return type + # and we've already split before the first parameter. + penalty += split_penalty.STRONGLY_CONNECTED + + return penalty + + if not param_list.parameters: + return penalty + + if newline: + if self._FitsOnLine( param_list.parameters[ 0 ].first_token, + _LastTokenInLine( param_list.closing_bracket ) ): + penalty += split_penalty.STRONGLY_CONNECTED + + if ( not newline and style.Get( 'SPLIT_BEFORE_NAMED_ASSIGNS' ) and + param_list.has_default_values and + current != param_list.parameters[ 0 ].first_token and + current != param_list.closing_bracket and + subtypes.PARAMETER_START in current.subtypes ): + # If we want to split before parameters when there are named assigns, + # then add a penalty for not splitting. + penalty += split_penalty.STRONGLY_CONNECTED + return penalty - if first_param_column <= self.column: - # Make sure we don't split after the opening bracket if the - # continuation indent is greater than the opening bracket: - # - # a( - # b=1, - # c=2) - penalty += split_penalty.VERY_STRONGLY_CONNECTED - return penalty - - if not self.param_list_stack: - return penalty - - param_list = self.param_list_stack[-1] - if current == self.param_list_stack[-1].closing_bracket: - self.param_list_stack.pop() # We're done with this state. - if newline and param_list.has_typed_return: - if param_list.split_before_closing_bracket: - penalty -= split_penalty.STRONGLY_CONNECTED - elif param_list.LastParamFitsOnLine(self.column): - penalty += split_penalty.STRONGLY_CONNECTED - - if (not newline and param_list.has_typed_return and - param_list.has_split_before_first_param): - # Prefer splitting before the closing bracket if there's a return type - # and we've already split before the first parameter. - penalty += split_penalty.STRONGLY_CONNECTED - - return penalty - - if not param_list.parameters: - return penalty - - if newline: - if self._FitsOnLine(param_list.parameters[0].first_token, - _LastTokenInLine(param_list.closing_bracket)): - penalty += split_penalty.STRONGLY_CONNECTED - - if (not newline and style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and - param_list.has_default_values and - current != param_list.parameters[0].first_token and - current != param_list.closing_bracket and - subtypes.PARAMETER_START in current.subtypes): - # If we want to split before parameters when there are named assigns, - # then add a penalty for not splitting. - penalty += split_penalty.STRONGLY_CONNECTED - - return penalty - - def _IndentWithContinuationAlignStyle(self, column): - if column == 0: - return column - align_style = style.Get('CONTINUATION_ALIGN_STYLE') - if align_style == 'FIXED': - return ((self.line.depth * style.Get('INDENT_WIDTH')) + - style.Get('CONTINUATION_INDENT_WIDTH')) - if align_style == 'VALIGN-RIGHT': - indent_width = style.Get('INDENT_WIDTH') - return indent_width * int((column + indent_width - 1) / indent_width) - return column - - def _GetNewlineColumn(self): - """Return the new column on the newline.""" - current = self.next_token - previous = current.previous_token - top_of_stack = self.stack[-1] - - if isinstance(current.spaces_required_before, list): - # Don't set the value here, as we need to look at the lines near - # this one to determine the actual horizontal alignment value. - return 0 - elif current.spaces_required_before > 2 or self.line.disable: - return current.spaces_required_before - - cont_aligned_indent = self._IndentWithContinuationAlignStyle( - top_of_stack.indent) - - if current.OpensScope(): - return cont_aligned_indent if self.paren_level else self.first_indent - - if current.ClosesScope(): - if (previous.OpensScope() or - (previous.is_comment and previous.previous_token is not None and - previous.previous_token.OpensScope())): - return max(0, - top_of_stack.indent - style.Get('CONTINUATION_INDENT_WIDTH')) - return top_of_stack.closing_scope_indent - - if (previous and previous.is_string and current.is_string and - subtypes.DICTIONARY_VALUE in current.subtypes): - return previous.column - - if style.Get('INDENT_DICTIONARY_VALUE'): - if previous and (previous.value == ':' or previous.is_pseudo): - if subtypes.DICTIONARY_VALUE in current.subtypes: - return top_of_stack.indent - - if (not self.param_list_stack and _IsCompoundStatement(self.line.first) and - (not (style.Get('DEDENT_CLOSING_BRACKETS') or - style.Get('INDENT_CLOSING_BRACKETS')) or - style.Get('SPLIT_BEFORE_FIRST_ARGUMENT'))): - token_indent = ( - len(self.line.first.whitespace_prefix.split('\n')[-1]) + - style.Get('INDENT_WIDTH')) - if token_indent == top_of_stack.indent: - return token_indent + style.Get('CONTINUATION_INDENT_WIDTH') - - if (self.param_list_stack and - not self.param_list_stack[-1].SplitBeforeClosingBracket( - top_of_stack.indent) and top_of_stack.indent - == ((self.line.depth + 1) * style.Get('INDENT_WIDTH'))): - # NOTE: comment inside argument list is not excluded in subtype assigner - if (subtypes.PARAMETER_START in current.subtypes or - (previous.is_comment and - subtypes.PARAMETER_START in previous.subtypes)): - return top_of_stack.indent + style.Get('CONTINUATION_INDENT_WIDTH') - - return cont_aligned_indent - - def _FitsOnLine(self, start, end): - """Determines if line between start and end can fit on the current line.""" - length = end.total_length - start.total_length - if not start.is_pseudo: - length += len(start.value) - return length + self.column <= self.column_limit - - def _EachDictEntryFitsOnOneLine(self, opening): - """Determine if each dict elems can fit on one line.""" - - def PreviousNonCommentToken(tok): - tok = tok.previous_token - while tok.is_comment: - tok = tok.previous_token - return tok - - def ImplicitStringConcatenation(tok): - num_strings = 0 - if tok.is_pseudo: - tok = tok.next_token - while tok.is_string: - num_strings += 1 - tok = tok.next_token - return num_strings > 1 - - def DictValueIsContainer(opening, closing): - """Return true if the dictionary value is a container.""" - if not opening or not closing: - return False - colon = opening.previous_token - while colon: - if not colon.is_pseudo: - break - colon = colon.previous_token - if not colon or colon.value != ':': - return False - key = colon.previous_token - if not key: - return False - return subtypes.DICTIONARY_KEY_PART in key.subtypes - - closing = opening.matching_bracket - entry_start = opening.next_token - current = opening.next_token.next_token - - while current and current != closing: - if subtypes.DICTIONARY_KEY in current.subtypes: - prev = PreviousNonCommentToken(current) - if prev.value == ',': - prev = PreviousNonCommentToken(prev.previous_token) - if not DictValueIsContainer(prev.matching_bracket, prev): - length = prev.total_length - entry_start.total_length - length += len(entry_start.value) - if length + self.stack[-2].indent >= self.column_limit: - return False - entry_start = current - if current.OpensScope(): - if ((current.value == '{' or - (current.is_pseudo and current.next_token.value == '{') and - subtypes.DICTIONARY_VALUE in current.subtypes) or - ImplicitStringConcatenation(current)): - # A dictionary entry that cannot fit on a single line shouldn't matter - # to this calculation. If it can't fit on a single line, then the - # opening should be on the same line as the key and the rest on - # newlines after it. But the other entries should be on single lines - # if possible. - if current.matching_bracket: - current = current.matching_bracket - while current: - if current == closing: - return True + def _IndentWithContinuationAlignStyle( self, column ): + if column == 0: + return column + align_style = style.Get( 'CONTINUATION_ALIGN_STYLE' ) + if align_style == 'FIXED': + return ( + ( self.line.depth * style.Get( 'INDENT_WIDTH' ) ) + + style.Get( 'CONTINUATION_INDENT_WIDTH' ) ) + if align_style == 'VALIGN-RIGHT': + indent_width = style.Get( 'INDENT_WIDTH' ) + return indent_width * int( ( column + indent_width - 1 ) / indent_width ) + return column + + def _GetNewlineColumn( self ): + """Return the new column on the newline.""" + current = self.next_token + previous = current.previous_token + top_of_stack = self.stack[ -1 ] + + if isinstance( current.spaces_required_before, list ): + # Don't set the value here, as we need to look at the lines near + # this one to determine the actual horizontal alignment value. + return 0 + elif current.spaces_required_before > 2 or self.line.disable: + return current.spaces_required_before + + cont_aligned_indent = self._IndentWithContinuationAlignStyle( + top_of_stack.indent ) + + if current.OpensScope(): + return cont_aligned_indent if self.paren_level else self.first_indent + + if current.ClosesScope(): + if ( previous.OpensScope() or + ( previous.is_comment and previous.previous_token is not None and + previous.previous_token.OpensScope() ) ): + return max( + 0, top_of_stack.indent - style.Get( 'CONTINUATION_INDENT_WIDTH' ) ) + return top_of_stack.closing_scope_indent + + if ( previous and previous.is_string and current.is_string and + subtypes.DICTIONARY_VALUE in current.subtypes ): + return previous.column + + if style.Get( 'INDENT_DICTIONARY_VALUE' ): + if previous and ( previous.value == ':' or previous.is_pseudo ): + if subtypes.DICTIONARY_VALUE in current.subtypes: + return top_of_stack.indent + + if ( not self.param_list_stack and _IsCompoundStatement( self.line.first ) and + ( not ( style.Get( 'DEDENT_CLOSING_BRACKETS' ) or + style.Get( 'INDENT_CLOSING_BRACKETS' ) ) or + style.Get( 'SPLIT_BEFORE_FIRST_ARGUMENT' ) ) ): + token_indent = ( + len( self.line.first.whitespace_prefix.split( '\n' )[ -1 ] ) + + style.Get( 'INDENT_WIDTH' ) ) + if token_indent == top_of_stack.indent: + return token_indent + style.Get( 'CONTINUATION_INDENT_WIDTH' ) + + if ( self.param_list_stack and + not self.param_list_stack[ -1 ].SplitBeforeClosingBracket( + top_of_stack.indent ) and top_of_stack.indent + == ( ( self.line.depth + 1 ) * style.Get( 'INDENT_WIDTH' ) ) ): + # NOTE: comment inside argument list is not excluded in subtype assigner + if ( subtypes.PARAMETER_START in current.subtypes or + ( previous.is_comment and + subtypes.PARAMETER_START in previous.subtypes ) ): + return top_of_stack.indent + style.Get( 'CONTINUATION_INDENT_WIDTH' ) + + return cont_aligned_indent + + def _FitsOnLine( self, start, end ): + """Determines if line between start and end can fit on the current line.""" + length = end.total_length - start.total_length + if not start.is_pseudo: + length += len( start.value ) + return length + self.column <= self.column_limit + + def _EachDictEntryFitsOnOneLine( self, opening ): + """Determine if each dict elems can fit on one line.""" + + def PreviousNonCommentToken( tok ): + tok = tok.previous_token + while tok.is_comment: + tok = tok.previous_token + return tok + + def ImplicitStringConcatenation( tok ): + num_strings = 0 + if tok.is_pseudo: + tok = tok.next_token + while tok.is_string: + num_strings += 1 + tok = tok.next_token + return num_strings > 1 + + def DictValueIsContainer( opening, closing ): + """Return true if the dictionary value is a container.""" + if not opening or not closing: + return False + colon = opening.previous_token + while colon: + if not colon.is_pseudo: + break + colon = colon.previous_token + if not colon or colon.value != ':': + return False + key = colon.previous_token + if not key: + return False + return subtypes.DICTIONARY_KEY_PART in key.subtypes + + closing = opening.matching_bracket + entry_start = opening.next_token + current = opening.next_token.next_token + + while current and current != closing: if subtypes.DICTIONARY_KEY in current.subtypes: - entry_start = current - break - current = current.next_token - else: - current = current.matching_bracket - else: - current = current.next_token - - # At this point, current is the closing bracket. Go back one to get the end - # of the dictionary entry. - current = PreviousNonCommentToken(current) - length = current.total_length - entry_start.total_length - length += len(entry_start.value) - return length + self.stack[-2].indent <= self.column_limit - - def _ArgumentListHasDictionaryEntry(self, token): - """Check if the function argument list has a dictionary as an arg.""" - if _IsArgumentToFunction(token): - while token: - if token.value == '{': - length = token.matching_bracket.total_length - token.total_length - return length + self.stack[-2].indent > self.column_limit - if token.ClosesScope(): - break - if token.OpensScope(): - token = token.matching_bracket - token = token.next_token - return False + prev = PreviousNonCommentToken( current ) + if prev.value == ',': + prev = PreviousNonCommentToken( prev.previous_token ) + if not DictValueIsContainer( prev.matching_bracket, prev ): + length = prev.total_length - entry_start.total_length + length += len( entry_start.value ) + if length + self.stack[ -2 ].indent >= self.column_limit: + return False + entry_start = current + if current.OpensScope(): + if ( ( current.value == '{' or + ( current.is_pseudo and current.next_token.value == '{' ) and + subtypes.DICTIONARY_VALUE in current.subtypes ) or + ImplicitStringConcatenation( current ) ): + # A dictionary entry that cannot fit on a single line shouldn't matter + # to this calculation. If it can't fit on a single line, then the + # opening should be on the same line as the key and the rest on + # newlines after it. But the other entries should be on single lines + # if possible. + if current.matching_bracket: + current = current.matching_bracket + while current: + if current == closing: + return True + if subtypes.DICTIONARY_KEY in current.subtypes: + entry_start = current + break + current = current.next_token + else: + current = current.matching_bracket + else: + current = current.next_token + + # At this point, current is the closing bracket. Go back one to get the end + # of the dictionary entry. + current = PreviousNonCommentToken( current ) + length = current.total_length - entry_start.total_length + length += len( entry_start.value ) + return length + self.stack[ -2 ].indent <= self.column_limit + + def _ArgumentListHasDictionaryEntry( self, token ): + """Check if the function argument list has a dictionary as an arg.""" + if _IsArgumentToFunction( token ): + while token: + if token.value == '{': + length = token.matching_bracket.total_length - token.total_length + return length + self.stack[ -2 ].indent > self.column_limit + if token.ClosesScope(): + break + if token.OpensScope(): + token = token.matching_bracket + token = token.next_token + return False - def _ContainerFitsOnStartLine(self, opening): - """Check if the container can fit on its starting line.""" - return (opening.matching_bracket.total_length - opening.total_length + - self.stack[-1].indent) <= self.column_limit + def _ContainerFitsOnStartLine( self, opening ): + """Check if the container can fit on its starting line.""" + return ( + opening.matching_bracket.total_length - opening.total_length + + self.stack[ -1 ].indent ) <= self.column_limit _COMPOUND_STMTS = frozenset( - {'for', 'while', 'if', 'elif', 'with', 'except', 'def', 'class'}) + { 'for', 'while', 'if', 'elif', 'with', 'except', 'def', 'class' } ) -def _IsCompoundStatement(token): - if token.value == 'async': - token = token.next_token - return token.value in _COMPOUND_STMTS +def _IsCompoundStatement( token ): + if token.value == 'async': + token = token.next_token + return token.value in _COMPOUND_STMTS -def _IsFunctionDef(token): - if token.value == 'async': - token = token.next_token - return token.value == 'def' +def _IsFunctionDef( token ): + if token.value == 'async': + token = token.next_token + return token.value == 'def' -def _IsFunctionCallWithArguments(token): - while token: - if token.value == '(': - token = token.next_token - return token and token.value != ')' - elif token.name not in {'NAME', 'DOT', 'EQUAL'}: - break - token = token.next_token - return False +def _IsFunctionCallWithArguments( token ): + while token: + if token.value == '(': + token = token.next_token + return token and token.value != ')' + elif token.name not in { 'NAME', 'DOT', 'EQUAL' }: + break + token = token.next_token + return False -def _IsArgumentToFunction(token): - bracket = logical_line.IsSurroundedByBrackets(token) - if not bracket or bracket.value != '(': - return False - previous = bracket.previous_token - return previous and previous.is_name +def _IsArgumentToFunction( token ): + bracket = logical_line.IsSurroundedByBrackets( token ) + if not bracket or bracket.value != '(': + return False + previous = bracket.previous_token + return previous and previous.is_name -def _GetOpeningBracket(current): - """Get the opening bracket containing the current token.""" - if current.matching_bracket and not current.is_pseudo: - return current if current.OpensScope() else current.matching_bracket +def _GetOpeningBracket( current ): + """Get the opening bracket containing the current token.""" + if current.matching_bracket and not current.is_pseudo: + return current if current.OpensScope() else current.matching_bracket - while current: - if current.ClosesScope(): - current = current.matching_bracket - elif current.is_pseudo: - current = current.previous_token - elif current.OpensScope(): - return current - current = current.previous_token - return None + while current: + if current.ClosesScope(): + current = current.matching_bracket + elif current.is_pseudo: + current = current.previous_token + elif current.OpensScope(): + return current + current = current.previous_token + return None -def _LastTokenInLine(current): - while not current.is_comment and current.next_token: - current = current.next_token - return current +def _LastTokenInLine( current ): + while not current.is_comment and current.next_token: + current = current.next_token + return current -def _IsFunctionDefinition(current): - prev = current.previous_token - return current.value == '(' and prev and subtypes.FUNC_DEF in prev.subtypes +def _IsFunctionDefinition( current ): + prev = current.previous_token + return current.value == '(' and prev and subtypes.FUNC_DEF in prev.subtypes -def _IsLastScopeInLine(current): - current = current.matching_bracket - while current: - current = current.next_token - if current and current.OpensScope(): - return False - return True +def _IsLastScopeInLine( current ): + current = current.matching_bracket + while current: + current = current.next_token + if current and current.OpensScope(): + return False + return True -def _IsSingleElementTuple(token): - """Check if it's a single-element tuple.""" - close = token.matching_bracket - token = token.next_token - num_commas = 0 - while token != close: - if token.value == ',': - num_commas += 1 - token = token.matching_bracket if token.OpensScope() else token.next_token - return num_commas == 1 +def _IsSingleElementTuple( token ): + """Check if it's a single-element tuple.""" + close = token.matching_bracket + token = token.next_token + num_commas = 0 + while token != close: + if token.value == ',': + num_commas += 1 + token = token.matching_bracket if token.OpensScope() else token.next_token + return num_commas == 1 -def _ScopeHasNoCommas(token): - """Check if the scope has no commas.""" - close = token.matching_bracket - token = token.next_token - while token != close: - if token.value == ',': - return False - token = token.matching_bracket if token.OpensScope() else token.next_token - return True +def _ScopeHasNoCommas( token ): + """Check if the scope has no commas.""" + close = token.matching_bracket + token = token.next_token + while token != close: + if token.value == ',': + return False + token = token.matching_bracket if token.OpensScope() else token.next_token + return True -class _ParenState(object): - """Maintains the state of the bracket enclosures. +class _ParenState( object ): + """Maintains the state of the bracket enclosures. A stack of _ParenState objects are kept so that we know how to indent relative to the brackets. @@ -1205,32 +1217,34 @@ class _ParenState(object): Each subsequent line split gets an increasing penalty. """ - # TODO(morbo): This doesn't track "bin packing." - - def __init__(self, indent, last_space): - self.indent = indent - self.last_space = last_space - self.closing_scope_indent = 0 - self.split_before_closing_bracket = False - self.num_line_splits = 0 - - def Clone(self): - state = _ParenState(self.indent, self.last_space) - state.closing_scope_indent = self.closing_scope_indent - state.split_before_closing_bracket = self.split_before_closing_bracket - state.num_line_splits = self.num_line_splits - return state - - def __repr__(self): - return '[indent::%d, last_space::%d, closing_scope_indent::%d]' % ( - self.indent, self.last_space, self.closing_scope_indent) - - def __eq__(self, other): - return hash(self) == hash(other) - - def __ne__(self, other): - return not self == other - - def __hash__(self, *args, **kwargs): - return hash((self.indent, self.last_space, self.closing_scope_indent, - self.split_before_closing_bracket, self.num_line_splits)) + # TODO(morbo): This doesn't track "bin packing." + + def __init__( self, indent, last_space ): + self.indent = indent + self.last_space = last_space + self.closing_scope_indent = 0 + self.split_before_closing_bracket = False + self.num_line_splits = 0 + + def Clone( self ): + state = _ParenState( self.indent, self.last_space ) + state.closing_scope_indent = self.closing_scope_indent + state.split_before_closing_bracket = self.split_before_closing_bracket + state.num_line_splits = self.num_line_splits + return state + + def __repr__( self ): + return '[indent::%d, last_space::%d, closing_scope_indent::%d]' % ( + self.indent, self.last_space, self.closing_scope_indent ) + + def __eq__( self, other ): + return hash( self ) == hash( other ) + + def __ne__( self, other ): + return not self == other + + def __hash__( self, *args, **kwargs ): + return hash( + ( + self.indent, self.last_space, self.closing_scope_indent, + self.split_before_closing_bracket, self.num_line_splits ) ) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 070987851..3dd570ef4 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -25,12 +25,12 @@ CONTINUATION = token.N_TOKENS -_OPENING_BRACKETS = frozenset({'(', '[', '{'}) -_CLOSING_BRACKETS = frozenset({')', ']', '}'}) +_OPENING_BRACKETS = frozenset( { '(', '[', '{' } ) +_CLOSING_BRACKETS = frozenset( { ')', ']', '}' } ) -def _TabbedContinuationAlignPadding(spaces, align_style, tab_width): - """Build padding string for continuation alignment in tabbed indentation. +def _TabbedContinuationAlignPadding( spaces, align_style, tab_width ): + """Build padding string for continuation alignment in tabbed indentation. Arguments: spaces: (int) The number of spaces to place before the token for alignment. @@ -40,15 +40,15 @@ def _TabbedContinuationAlignPadding(spaces, align_style, tab_width): Returns: A padding string for alignment with style specified by align_style option. """ - if align_style in ('FIXED', 'VALIGN-RIGHT'): - if spaces > 0: - return '\t' * int((spaces + tab_width - 1) / tab_width) - return '' - return ' ' * spaces + if align_style in ( 'FIXED', 'VALIGN-RIGHT' ): + if spaces > 0: + return '\t' * int( ( spaces + tab_width - 1 ) / tab_width ) + return '' + return ' ' * spaces -class FormatToken(object): - """Enhanced token information for formatting. +class FormatToken( object ): + """Enhanced token information for formatting. This represents the token plus additional information useful for reformatting the code. @@ -83,58 +83,57 @@ class FormatToken(object): newlines: The number of newlines needed before this token. """ - def __init__(self, node, name): - """Constructor. + def __init__( self, node, name ): + """Constructor. Arguments: node: (pytree.Leaf) The node that's being wrapped. name: (string) The name of the node. """ - self.node = node - self.name = name - self.type = node.type - self.column = node.column - self.lineno = node.lineno - self.value = node.value - - if self.is_continuation: - self.value = node.value.rstrip() - - self.next_token = None - self.previous_token = None - self.matching_bracket = None - self.parameters = [] - self.container_opening = None - self.container_elements = [] - self.whitespace_prefix = '' - self.total_length = 0 - self.split_penalty = 0 - self.can_break_before = False - self.must_break_before = pytree_utils.GetNodeAnnotation( - node, pytree_utils.Annotation.MUST_SPLIT, default=False) - self.newlines = pytree_utils.GetNodeAnnotation( - node, pytree_utils.Annotation.NEWLINES) - self.spaces_required_before = 0 - - if self.is_comment: - self.spaces_required_before = style.Get('SPACES_BEFORE_COMMENT') - - stypes = pytree_utils.GetNodeAnnotation(node, - pytree_utils.Annotation.SUBTYPE) - self.subtypes = {subtypes.NONE} if not stypes else stypes - self.is_pseudo = hasattr(node, 'is_pseudo') and node.is_pseudo - - @property - def formatted_whitespace_prefix(self): - if style.Get('INDENT_BLANK_LINES'): - without_newlines = self.whitespace_prefix.lstrip('\n') - height = len(self.whitespace_prefix) - len(without_newlines) - if height: - return ('\n' + without_newlines) * height - return self.whitespace_prefix - - def AddWhitespacePrefix(self, newlines_before, spaces=0, indent_level=0): - """Register a token's whitespace prefix. + self.node = node + self.name = name + self.type = node.type + self.column = node.column + self.lineno = node.lineno + self.value = node.value + + if self.is_continuation: + self.value = node.value.rstrip() + + self.next_token = None + self.previous_token = None + self.matching_bracket = None + self.parameters = [] + self.container_opening = None + self.container_elements = [] + self.whitespace_prefix = '' + self.total_length = 0 + self.split_penalty = 0 + self.can_break_before = False + self.must_break_before = pytree_utils.GetNodeAnnotation( + node, pytree_utils.Annotation.MUST_SPLIT, default = False ) + self.newlines = pytree_utils.GetNodeAnnotation( + node, pytree_utils.Annotation.NEWLINES ) + self.spaces_required_before = 0 + + if self.is_comment: + self.spaces_required_before = style.Get( 'SPACES_BEFORE_COMMENT' ) + + stypes = pytree_utils.GetNodeAnnotation( node, pytree_utils.Annotation.SUBTYPE ) + self.subtypes = { subtypes.NONE } if not stypes else stypes + self.is_pseudo = hasattr( node, 'is_pseudo' ) and node.is_pseudo + + @property + def formatted_whitespace_prefix( self ): + if style.Get( 'INDENT_BLANK_LINES' ): + without_newlines = self.whitespace_prefix.lstrip( '\n' ) + height = len( self.whitespace_prefix ) - len( without_newlines ) + if height: + return ( '\n' + without_newlines ) * height + return self.whitespace_prefix + + def AddWhitespacePrefix( self, newlines_before, spaces = 0, indent_level = 0 ): + """Register a token's whitespace prefix. This is the whitespace that will be output before a token's string. @@ -143,261 +142,196 @@ def AddWhitespacePrefix(self, newlines_before, spaces=0, indent_level=0): spaces: (int) The number of spaces to place before the token. indent_level: (int) The indentation level. """ - if style.Get('USE_TABS'): - if newlines_before > 0: - indent_before = '\t' * indent_level + _TabbedContinuationAlignPadding( - spaces, style.Get('CONTINUATION_ALIGN_STYLE'), - style.Get('INDENT_WIDTH')) - else: - indent_before = '\t' * indent_level + ' ' * spaces - else: - indent_before = (' ' * indent_level * style.Get('INDENT_WIDTH') + - ' ' * spaces) - - if self.is_comment: - comment_lines = [s.lstrip() for s in self.value.splitlines()] - self.value = ('\n' + indent_before).join(comment_lines) - - # Update our own value since we are changing node value - self.value = self.value - - if not self.whitespace_prefix: - self.whitespace_prefix = ('\n' * (self.newlines or newlines_before) + - indent_before) - else: - self.whitespace_prefix += indent_before - - def AdjustNewlinesBefore(self, newlines_before): - """Change the number of newlines before this token.""" - self.whitespace_prefix = ('\n' * newlines_before + - self.whitespace_prefix.lstrip('\n')) - - def RetainHorizontalSpacing(self, first_column, depth): - """Retains a token's horizontal spacing.""" - previous = self.previous_token - if not previous: - return - - if previous.is_pseudo: - previous = previous.previous_token - if not previous: - return - - cur_lineno = self.lineno - prev_lineno = previous.lineno - if previous.is_multiline_string: - prev_lineno += previous.value.count('\n') - - if (cur_lineno != prev_lineno or - (previous.is_pseudo and previous.value != ')' and - cur_lineno != previous.previous_token.lineno)): - self.spaces_required_before = ( - self.column - first_column + depth * style.Get('INDENT_WIDTH')) - return - - cur_column = self.column - prev_column = previous.column - prev_len = len(previous.value) - - if previous.is_pseudo and previous.value == ')': - prev_column -= 1 - prev_len = 0 - - if previous.is_multiline_string: - prev_len = len(previous.value.split('\n')[-1]) - if '\n' in previous.value: - prev_column = 0 # Last line starts in column 0. - - self.spaces_required_before = cur_column - (prev_column + prev_len) - - def OpensScope(self): - return self.value in _OPENING_BRACKETS - - def ClosesScope(self): - return self.value in _CLOSING_BRACKETS - - def AddSubtype(self, subtype): - self.subtypes.add(subtype) - - def __repr__(self): - msg = ('FormatToken(name={0}, value={1}, column={2}, lineno={3}, ' - 'splitpenalty={4}'.format( - 'DOCSTRING' if self.is_docstring else self.name, self.value, - self.column, self.lineno, self.split_penalty)) - msg += ', pseudo)' if self.is_pseudo else ')' - return msg - - @property - def node_split_penalty(self): - """Split penalty attached to the pytree node of this token.""" - return pytree_utils.GetNodeAnnotation( - self.node, pytree_utils.Annotation.SPLIT_PENALTY, default=0) - - @property - def is_binary_op(self): - """Token is a binary operator.""" - return subtypes.BINARY_OPERATOR in self.subtypes - - @property - @py3compat.lru_cache() - def is_arithmetic_op(self): - """Token is an arithmetic operator.""" - return self.value in frozenset({ - '+', # Add - '-', # Subtract - '*', # Multiply - '@', # Matrix Multiply - '/', # Divide - '//', # Floor Divide - '%', # Modulo - '<<', # Left Shift - '>>', # Right Shift - '|', # Bitwise Or - '&', # Bitwise Add - '^', # Bitwise Xor - '**', # Power - }) - - @property - def is_simple_expr(self): - """Token is an operator in a simple expression.""" - return subtypes.SIMPLE_EXPRESSION in self.subtypes - - @property - def is_subscript_colon(self): - """Token is a subscript colon.""" - return subtypes.SUBSCRIPT_COLON in self.subtypes - - @property - def is_comment(self): - return self.type == token.COMMENT - - @property - def is_continuation(self): - return self.type == CONTINUATION - - @property - @py3compat.lru_cache() - def is_keyword(self): - return keyword.iskeyword(self.value) - - @property - def is_name(self): - return self.type == token.NAME and not self.is_keyword - - @property - def is_number(self): - return self.type == token.NUMBER - - @property - def is_string(self): - return self.type == token.STRING - - @property - def is_multiline_string(self): - """Test if this string is a multiline string. + if style.Get( 'USE_TABS' ): + if newlines_before > 0: + indent_before = '\t' * indent_level + _TabbedContinuationAlignPadding( + spaces, style.Get( 'CONTINUATION_ALIGN_STYLE' ), + style.Get( 'INDENT_WIDTH' ) ) + else: + indent_before = '\t' * indent_level + ' ' * spaces + else: + indent_before = ( + ' ' * indent_level * style.Get( 'INDENT_WIDTH' ) + ' ' * spaces ) + + if self.is_comment: + comment_lines = [ s.lstrip() for s in self.value.splitlines() ] + self.value = ( '\n' + indent_before ).join( comment_lines ) + + # Update our own value since we are changing node value + self.value = self.value + + if not self.whitespace_prefix: + self.whitespace_prefix = ( + '\n' * ( self.newlines or newlines_before ) + indent_before ) + else: + self.whitespace_prefix += indent_before + + def AdjustNewlinesBefore( self, newlines_before ): + """Change the number of newlines before this token.""" + self.whitespace_prefix = ( + '\n' * newlines_before + self.whitespace_prefix.lstrip( '\n' ) ) + + def RetainHorizontalSpacing( self, first_column, depth ): + """Retains a token's horizontal spacing.""" + previous = self.previous_token + if not previous: + return + + if previous.is_pseudo: + previous = previous.previous_token + if not previous: + return + + cur_lineno = self.lineno + prev_lineno = previous.lineno + if previous.is_multiline_string: + prev_lineno += previous.value.count( '\n' ) + + if ( cur_lineno != prev_lineno or + ( previous.is_pseudo and previous.value != ')' and + cur_lineno != previous.previous_token.lineno ) ): + self.spaces_required_before = ( + self.column - first_column + depth * style.Get( 'INDENT_WIDTH' ) ) + return + + cur_column = self.column + prev_column = previous.column + prev_len = len( previous.value ) + + if previous.is_pseudo and previous.value == ')': + prev_column -= 1 + prev_len = 0 + + if previous.is_multiline_string: + prev_len = len( previous.value.split( '\n' )[ -1 ] ) + if '\n' in previous.value: + prev_column = 0 # Last line starts in column 0. + + self.spaces_required_before = cur_column - ( prev_column + prev_len ) + + def OpensScope( self ): + return self.value in _OPENING_BRACKETS + + def ClosesScope( self ): + return self.value in _CLOSING_BRACKETS + + def AddSubtype( self, subtype ): + self.subtypes.add( subtype ) + + def __repr__( self ): + msg = ( + 'FormatToken(name={0}, value={1}, column={2}, lineno={3}, ' + 'splitpenalty={4}'.format( + 'DOCSTRING' if self.is_docstring else self.name, self.value, + self.column, self.lineno, self.split_penalty ) ) + msg += ', pseudo)' if self.is_pseudo else ')' + return msg + + @property + def node_split_penalty( self ): + """Split penalty attached to the pytree node of this token.""" + return pytree_utils.GetNodeAnnotation( + self.node, pytree_utils.Annotation.SPLIT_PENALTY, default = 0 ) + + @property + def is_binary_op( self ): + """Token is a binary operator.""" + return subtypes.BINARY_OPERATOR in self.subtypes + + @property + @py3compat.lru_cache() + def is_arithmetic_op( self ): + """Token is an arithmetic operator.""" + return self.value in frozenset( + { + '+', # Add + '-', # Subtract + '*', # Multiply + '@', # Matrix Multiply + '/', # Divide + '//', # Floor Divide + '%', # Modulo + '<<', # Left Shift + '>>', # Right Shift + '|', # Bitwise Or + '&', # Bitwise Add + '^', # Bitwise Xor + '**', # Power + } ) + + @property + def is_simple_expr( self ): + """Token is an operator in a simple expression.""" + return subtypes.SIMPLE_EXPRESSION in self.subtypes + + @property + def is_subscript_colon( self ): + """Token is a subscript colon.""" + return subtypes.SUBSCRIPT_COLON in self.subtypes + + @property + def is_comment( self ): + return self.type == token.COMMENT + + @property + def is_continuation( self ): + return self.type == CONTINUATION + + @property + @py3compat.lru_cache() + def is_keyword( self ): + return keyword.iskeyword( self.value ) + + @property + def is_name( self ): + return self.type == token.NAME and not self.is_keyword + + @property + def is_number( self ): + return self.type == token.NUMBER + + @property + def is_string( self ): + return self.type == token.STRING + + @property + def is_multiline_string( self ): + """Test if this string is a multiline string. Returns: A multiline string always ends with triple quotes, so if it is a string token, inspect the last 3 characters and return True if it is a triple double or triple single quote mark. """ - return self.is_string and self.value.endswith(('"""', "'''")) - - @property - def is_docstring(self): - return self.is_string and self.previous_token is None - - @property - def is_pylint_comment(self): - return self.is_comment and re.match(r'#.*\bpylint:\s*(disable|enable)=', - self.value) - - @property - def is_pytype_comment(self): - return self.is_comment and re.match(r'#.*\bpytype:\s*(disable|enable)=', - self.value) - - @property - def is_copybara_comment(self): - return self.is_comment and re.match( - r'#.*\bcopybara:\s*(strip|insert|replace)', self.value) - - @property - def is_assign(self): - return subtypes.ASSIGN_OPERATOR in self.subtypes - - @property - def is_dict_colon(self): - # if the token is dictionary colon and - # the dictionary has no comp_for - return self.value == ':' and self.previous_token.is_dict_key - - @property - def is_dict_key(self): - # if the token is dictionary key which is not preceded by doubel stars and - # the dictionary has no comp_for - return subtypes.DICTIONARY_KEY_PART in self.subtypes - - @property - def is_dict_key_start(self): - # if the token is dictionary key start - return subtypes.DICTIONARY_KEY in self.subtypes - - @property - def is_dict_value(self): - return subtypes.DICTIONARY_VALUE in self.subtypes - - @property - def is_augassign(self): - augassigns = {'+=', '-=' , '*=' , '@=' , '/=' , '%=' , '&=' , '|=' , '^=' , - '<<=' , '>>=' , '**=' , '//='} - return self.value in augassigns - - @property - def is_argassign(self): - return (subtypes.DEFAULT_OR_NAMED_ASSIGN in self.subtypes - or subtypes.VARARGS_LIST in self.subtypes) - - @property - def is_argname(self): - # it's the argument part before argument assignment operator, - # including tnames and data type - # not the assign operator, - # not the value after the assign operator - - # argument without assignment is also included - # the token is arg part before '=' but not after '=' - if self.is_argname_start: - return True - - # exclude comment inside argument list - if not self.is_comment: - # the token is any element in typed arglist - if subtypes.TYPED_NAME_ARG_LIST in self.subtypes: - return True - - return False - - @property - def is_argname_start(self): - # return true if it's the start of every argument entry - previous_subtypes = {0} - if self.previous_token: - previous_subtypes = self.previous_token.subtypes - - return ( - (not self.is_comment - and subtypes.DEFAULT_OR_NAMED_ASSIGN not in self.subtypes - and subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in self.subtypes - and subtypes.DEFAULT_OR_NAMED_ASSIGN not in previous_subtypes - and (not subtypes.PARAMETER_STOP in self.subtypes - or subtypes.PARAMETER_START in self.subtypes) - ) - or # if there is comment, the arg after it is the argname start - (not self.is_comment and self.previous_token and self.previous_token.is_comment - and - (subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in previous_subtypes - or subtypes.TYPED_NAME_ARG_LIST in self.subtypes - or subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in self.subtypes)) - ) + return self.is_string and self.value.endswith( ( '"""', "'''" ) ) + + @property + def is_docstring( self ): + return self.is_string and self.previous_token is None + + @property + def is_pylint_comment( self ): + return self.is_comment and re.match( + r'#.*\bpylint:\s*(disable|enable)=', self.value ) + + @property + def is_pytype_comment( self ): + return self.is_comment and re.match( + r'#.*\bpytype:\s*(disable|enable)=', self.value ) + + @property + def is_copybara_comment( self ): + return self.is_comment and re.match( + r'#.*\bcopybara:\s*(strip|insert|replace)', self.value ) + + @property + def is_assign( self ): + return subtypes.ASSIGN_OPERATOR in self.subtypes + + @property + def is_augassign( self ): + augassigns = { + '+=', '-=', '*=', '@=', '/=', '%=', '&=', '|=', '^=', '<<=', '>>=', '**=', + '//=' + } + return self.value in augassigns diff --git a/yapf/yapflib/identify_container.py b/yapf/yapflib/identify_container.py index d027cc5d4..049694a77 100644 --- a/yapf/yapflib/identify_container.py +++ b/yapf/yapflib/identify_container.py @@ -25,45 +25,45 @@ from yapf.pytree import pytree_visitor -def IdentifyContainers(tree): - """Run the identify containers visitor over the tree, modifying it in place. +def IdentifyContainers( tree ): + """Run the identify containers visitor over the tree, modifying it in place. Arguments: tree: the top-level pytree node to annotate with subtypes. """ - identify_containers = _IdentifyContainers() - identify_containers.Visit(tree) + identify_containers = _IdentifyContainers() + identify_containers.Visit( tree ) -class _IdentifyContainers(pytree_visitor.PyTreeVisitor): - """_IdentifyContainers - see file-level docstring for detailed description.""" +class _IdentifyContainers( pytree_visitor.PyTreeVisitor ): + """_IdentifyContainers - see file-level docstring for detailed description.""" - def Visit_trailer(self, node): # pylint: disable=invalid-name - for child in node.children: - self.Visit(child) + def Visit_trailer( self, node ): # pylint: disable=invalid-name + for child in node.children: + self.Visit( child ) - if len(node.children) != 3: - return - if node.children[0].type != grammar_token.LPAR: - return + if len( node.children ) != 3: + return + if node.children[ 0 ].type != grammar_token.LPAR: + return - if pytree_utils.NodeName(node.children[1]) == 'arglist': - for child in node.children[1].children: - pytree_utils.SetOpeningBracket( - pytree_utils.FirstLeafNode(child), node.children[0]) - else: - pytree_utils.SetOpeningBracket( - pytree_utils.FirstLeafNode(node.children[1]), node.children[0]) + if pytree_utils.NodeName( node.children[ 1 ] ) == 'arglist': + for child in node.children[ 1 ].children: + pytree_utils.SetOpeningBracket( + pytree_utils.FirstLeafNode( child ), node.children[ 0 ] ) + else: + pytree_utils.SetOpeningBracket( + pytree_utils.FirstLeafNode( node.children[ 1 ] ), node.children[ 0 ] ) - def Visit_atom(self, node): # pylint: disable=invalid-name - for child in node.children: - self.Visit(child) + def Visit_atom( self, node ): # pylint: disable=invalid-name + for child in node.children: + self.Visit( child ) - if len(node.children) != 3: - return - if node.children[0].type != grammar_token.LPAR: - return + if len( node.children ) != 3: + return + if node.children[ 0 ].type != grammar_token.LPAR: + return - for child in node.children[1].children: - pytree_utils.SetOpeningBracket( - pytree_utils.FirstLeafNode(child), node.children[0]) + for child in node.children[ 1 ].children: + pytree_utils.SetOpeningBracket( + pytree_utils.FirstLeafNode( child ), node.children[ 0 ] ) diff --git a/yapf/yapflib/line_joiner.py b/yapf/yapflib/line_joiner.py index f0acd2f37..8a2911397 100644 --- a/yapf/yapflib/line_joiner.py +++ b/yapf/yapflib/line_joiner.py @@ -36,11 +36,11 @@ from yapf.yapflib import style -_CLASS_OR_FUNC = frozenset({'def', 'class'}) +_CLASS_OR_FUNC = frozenset( { 'def', 'class' } ) -def CanMergeMultipleLines(lines, last_was_merged=False): - """Determine if multiple lines can be joined into one. +def CanMergeMultipleLines( lines, last_was_merged = False ): + """Determine if multiple lines can be joined into one. Arguments: lines: (list of LogicalLine) This is a splice of LogicalLines from the full @@ -51,39 +51,39 @@ def CanMergeMultipleLines(lines, last_was_merged=False): True if two consecutive lines can be joined together. In reality, this will only happen if two consecutive lines can be joined, due to the style guide. """ - # The indentation amount for the starting line (number of spaces). - indent_amt = lines[0].depth * style.Get('INDENT_WIDTH') - if len(lines) == 1 or indent_amt > style.Get('COLUMN_LIMIT'): - return False - - if (len(lines) >= 3 and lines[2].depth >= lines[1].depth and - lines[0].depth != lines[2].depth): - # If lines[2]'s depth is greater than or equal to line[1]'s depth, we're not - # looking at a single statement (e.g., if-then, while, etc.). A following - # line with the same depth as the first line isn't part of the lines we - # would want to combine. - return False # Don't merge more than two lines together. + # The indentation amount for the starting line (number of spaces). + indent_amt = lines[ 0 ].depth * style.Get( 'INDENT_WIDTH' ) + if len( lines ) == 1 or indent_amt > style.Get( 'COLUMN_LIMIT' ): + return False + + if ( len( lines ) >= 3 and lines[ 2 ].depth >= lines[ 1 ].depth and + lines[ 0 ].depth != lines[ 2 ].depth ): + # If lines[2]'s depth is greater than or equal to line[1]'s depth, we're not + # looking at a single statement (e.g., if-then, while, etc.). A following + # line with the same depth as the first line isn't part of the lines we + # would want to combine. + return False # Don't merge more than two lines together. + + if lines[ 0 ].first.value in _CLASS_OR_FUNC: + # Don't join lines onto the starting line of a class or function. + return False + + limit = style.Get( 'COLUMN_LIMIT' ) - indent_amt + if lines[ 0 ].last.total_length < limit: + limit -= lines[ 0 ].last.total_length + + if lines[ 0 ].first.value == 'if': + return _CanMergeLineIntoIfStatement( lines, limit ) + if last_was_merged and lines[ 0 ].first.value in { 'elif', 'else' }: + return _CanMergeLineIntoIfStatement( lines, limit ) + + # TODO(morbo): Other control statements? - if lines[0].first.value in _CLASS_OR_FUNC: - # Don't join lines onto the starting line of a class or function. return False - limit = style.Get('COLUMN_LIMIT') - indent_amt - if lines[0].last.total_length < limit: - limit -= lines[0].last.total_length - - if lines[0].first.value == 'if': - return _CanMergeLineIntoIfStatement(lines, limit) - if last_was_merged and lines[0].first.value in {'elif', 'else'}: - return _CanMergeLineIntoIfStatement(lines, limit) - - # TODO(morbo): Other control statements? - return False - - -def _CanMergeLineIntoIfStatement(lines, limit): - """Determine if we can merge a short if-then statement into one line. +def _CanMergeLineIntoIfStatement( lines, limit ): + """Determine if we can merge a short if-then statement into one line. Two lines of an if-then statement can be merged if they were that way in the original source, fit on the line without going over the column limit, and are @@ -97,13 +97,13 @@ def _CanMergeLineIntoIfStatement(lines, limit): Returns: True if the lines can be merged, False otherwise. """ - if len(lines[1].tokens) == 1 and lines[1].last.is_multiline_string: - # This might be part of a multiline shebang. - return True - if lines[0].lineno != lines[1].lineno: - # Don't merge lines if the original lines weren't merged. - return False - if lines[1].last.total_length >= limit: - # Don't merge lines if the result goes over the column limit. - return False - return style.Get('JOIN_MULTIPLE_LINES') + if len( lines[ 1 ].tokens ) == 1 and lines[ 1 ].last.is_multiline_string: + # This might be part of a multiline shebang. + return True + if lines[ 0 ].lineno != lines[ 1 ].lineno: + # Don't merge lines if the original lines weren't merged. + return False + if lines[ 1 ].last.total_length >= limit: + # Don't merge lines if the result goes over the column limit. + return False + return style.Get( 'JOIN_MULTIPLE_LINES' ) diff --git a/yapf/yapflib/logical_line.py b/yapf/yapflib/logical_line.py index 8c84b7ba8..b02e3588b 100644 --- a/yapf/yapflib/logical_line.py +++ b/yapf/yapflib/logical_line.py @@ -29,8 +29,8 @@ from lib2to3.fixer_util import syms as python_symbols -class LogicalLine(object): - """Represents a single logical line in the output. +class LogicalLine( object ): + """Represents a single logical line in the output. Attributes: depth: indentation depth of this line. This is just a numeric value used to @@ -38,8 +38,8 @@ class LogicalLine(object): actual amount of spaces, which is style-dependent. """ - def __init__(self, depth, tokens=None): - """Constructor. + def __init__( self, depth, tokens = None ): + """Constructor. Creates a new logical line with the given depth an initial list of tokens. Constructs the doubly-linked lists for format tokens using their built-in @@ -49,108 +49,108 @@ def __init__(self, depth, tokens=None): depth: indentation depth of this line tokens: initial list of tokens """ - self.depth = depth - self._tokens = tokens or [] - self.disable = False - - if self._tokens: - # Set up a doubly linked list. - for index, tok in enumerate(self._tokens[1:]): - # Note, 'index' is the index to the previous token. - tok.previous_token = self._tokens[index] - self._tokens[index].next_token = tok - - def CalculateFormattingInformation(self): - """Calculate the split penalty and total length for the tokens.""" - # Say that the first token in the line should have a space before it. This - # means only that if this logical line is joined with a predecessor line, - # then there will be a space between them. - self.first.spaces_required_before = 1 - self.first.total_length = len(self.first.value) - - prev_token = self.first - prev_length = self.first.total_length - for token in self._tokens[1:]: - if (token.spaces_required_before == 0 and - _SpaceRequiredBetween(prev_token, token, self.disable)): - token.spaces_required_before = 1 - - tok_len = len(token.value) if not token.is_pseudo else 0 - - spaces_required_before = token.spaces_required_before - if isinstance(spaces_required_before, list): - assert token.is_comment, token - - # If here, we are looking at a comment token that appears on a line - # with other tokens (but because it is a comment, it is always the last - # token). Rather than specifying the actual number of spaces here, - # hard code a value of 0 and then set it later. This logic only works - # because this comment token is guaranteed to be the last token in the - # list. - spaces_required_before = 0 - - token.total_length = prev_length + tok_len + spaces_required_before - - # The split penalty has to be computed before {must|can}_break_before, - # because these may use it for their decision. - token.split_penalty += _SplitPenalty(prev_token, token) - token.must_break_before = _MustBreakBefore(prev_token, token) - token.can_break_before = ( - token.must_break_before or _CanBreakBefore(prev_token, token)) - - prev_length = token.total_length - prev_token = token - - def Split(self): - """Split the line at semicolons.""" - if not self.has_semicolon or self.disable: - return [self] - - llines = [] - lline = LogicalLine(self.depth) - for tok in self._tokens: - if tok.value == ';': - llines.append(lline) - lline = LogicalLine(self.depth) - else: - lline.AppendToken(tok) - - if lline.tokens: - llines.append(lline) - - for lline in llines: - lline.first.previous_token = None - lline.last.next_token = None - - return llines - - ############################################################################ - # Token Access and Manipulation Methods # - ############################################################################ - - def AppendToken(self, token): - """Append a new FormatToken to the tokens contained in this line.""" - if self._tokens: - token.previous_token = self.last - self.last.next_token = token - self._tokens.append(token) - - @property - def first(self): - """Returns the first non-whitespace token.""" - return self._tokens[0] - - @property - def last(self): - """Returns the last non-whitespace token.""" - return self._tokens[-1] - - ############################################################################ - # Token -> String Methods # - ############################################################################ - - def AsCode(self, indent_per_depth=2): - """Return a "code" representation of this line. + self.depth = depth + self._tokens = tokens or [] + self.disable = False + + if self._tokens: + # Set up a doubly linked list. + for index, tok in enumerate( self._tokens[ 1 : ] ): + # Note, 'index' is the index to the previous token. + tok.previous_token = self._tokens[ index ] + self._tokens[ index ].next_token = tok + + def CalculateFormattingInformation( self ): + """Calculate the split penalty and total length for the tokens.""" + # Say that the first token in the line should have a space before it. This + # means only that if this logical line is joined with a predecessor line, + # then there will be a space between them. + self.first.spaces_required_before = 1 + self.first.total_length = len( self.first.value ) + + prev_token = self.first + prev_length = self.first.total_length + for token in self._tokens[ 1 : ]: + if ( token.spaces_required_before == 0 and + _SpaceRequiredBetween( prev_token, token, self.disable ) ): + token.spaces_required_before = 1 + + tok_len = len( token.value ) if not token.is_pseudo else 0 + + spaces_required_before = token.spaces_required_before + if isinstance( spaces_required_before, list ): + assert token.is_comment, token + + # If here, we are looking at a comment token that appears on a line + # with other tokens (but because it is a comment, it is always the last + # token). Rather than specifying the actual number of spaces here, + # hard code a value of 0 and then set it later. This logic only works + # because this comment token is guaranteed to be the last token in the + # list. + spaces_required_before = 0 + + token.total_length = prev_length + tok_len + spaces_required_before + + # The split penalty has to be computed before {must|can}_break_before, + # because these may use it for their decision. + token.split_penalty += _SplitPenalty( prev_token, token ) + token.must_break_before = _MustBreakBefore( prev_token, token ) + token.can_break_before = ( + token.must_break_before or _CanBreakBefore( prev_token, token ) ) + + prev_length = token.total_length + prev_token = token + + def Split( self ): + """Split the line at semicolons.""" + if not self.has_semicolon or self.disable: + return [ self ] + + llines = [] + lline = LogicalLine( self.depth ) + for tok in self._tokens: + if tok.value == ';': + llines.append( lline ) + lline = LogicalLine( self.depth ) + else: + lline.AppendToken( tok ) + + if lline.tokens: + llines.append( lline ) + + for lline in llines: + lline.first.previous_token = None + lline.last.next_token = None + + return llines + + ############################################################################ + # Token Access and Manipulation Methods # + ############################################################################ + + def AppendToken( self, token ): + """Append a new FormatToken to the tokens contained in this line.""" + if self._tokens: + token.previous_token = self.last + self.last.next_token = token + self._tokens.append( token ) + + @property + def first( self ): + """Returns the first non-whitespace token.""" + return self._tokens[ 0 ] + + @property + def last( self ): + """Returns the last non-whitespace token.""" + return self._tokens[ -1 ] + + ############################################################################ + # Token -> String Methods # + ############################################################################ + + def AsCode( self, indent_per_depth = 2 ): + """Return a "code" representation of this line. The code representation shows how the line would be printed out as code. @@ -164,516 +164,518 @@ def AsCode(self, indent_per_depth=2): Returns: A string representing the line as code. """ - indent = ' ' * indent_per_depth * self.depth - tokens_str = ' '.join(tok.value for tok in self._tokens) - return indent + tokens_str + indent = ' ' * indent_per_depth * self.depth + tokens_str = ' '.join( tok.value for tok in self._tokens ) + return indent + tokens_str - def __str__(self): # pragma: no cover - return self.AsCode() + def __str__( self ): # pragma: no cover + return self.AsCode() - def __repr__(self): # pragma: no cover - tokens_repr = ','.join( - '{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens) - return 'LogicalLine(depth={0}, tokens=[{1}])'.format( - self.depth, tokens_repr) + def __repr__( self ): # pragma: no cover + tokens_repr = ','.join( + '{0}({1!r})'.format( tok.name, tok.value ) for tok in self._tokens ) + return 'LogicalLine(depth={0}, tokens=[{1}])'.format( self.depth, tokens_repr ) - ############################################################################ - # Properties # - ############################################################################ + ############################################################################ + # Properties # + ############################################################################ - @property - def tokens(self): - """Access the tokens contained within this line. + @property + def tokens( self ): + """Access the tokens contained within this line. The caller must not modify the tokens list returned by this method. Returns: List of tokens in this line. """ - return self._tokens + return self._tokens - @property - def lineno(self): - """Return the line number of this logical line. + @property + def lineno( self ): + """Return the line number of this logical line. Returns: The line number of the first token in this logical line. """ - return self.first.lineno + return self.first.lineno - @property - def start(self): - """The start of the logical line. + @property + def start( self ): + """The start of the logical line. Returns: A tuple of the starting line number and column. """ - return (self.first.lineno, self.first.column) + return ( self.first.lineno, self.first.column ) - @property - def end(self): - """The end of the logical line. + @property + def end( self ): + """The end of the logical line. Returns: A tuple of the ending line number and column. """ - return (self.last.lineno, self.last.column + len(self.last.value)) + return ( self.last.lineno, self.last.column + len( self.last.value ) ) - @property - def is_comment(self): - return self.first.is_comment + @property + def is_comment( self ): + return self.first.is_comment - @property - def has_semicolon(self): - return any(tok.value == ';' for tok in self._tokens) + @property + def has_semicolon( self ): + return any( tok.value == ';' for tok in self._tokens ) -def _IsIdNumberStringToken(tok): - return tok.is_keyword or tok.is_name or tok.is_number or tok.is_string +def _IsIdNumberStringToken( tok ): + return tok.is_keyword or tok.is_name or tok.is_number or tok.is_string -def _IsUnaryOperator(tok): - return subtypes.UNARY_OPERATOR in tok.subtypes +def _IsUnaryOperator( tok ): + return subtypes.UNARY_OPERATOR in tok.subtypes -def _HasPrecedence(tok): - """Whether a binary operation has precedence within its context.""" - node = tok.node +def _HasPrecedence( tok ): + """Whether a binary operation has precedence within its context.""" + node = tok.node - # We let ancestor be the statement surrounding the operation that tok is the - # operator in. - ancestor = node.parent.parent + # We let ancestor be the statement surrounding the operation that tok is the + # operator in. + ancestor = node.parent.parent - while ancestor is not None: - # Search through the ancestor nodes in the parse tree for operators with - # lower precedence. - predecessor_type = pytree_utils.NodeName(ancestor) - if predecessor_type in ['arith_expr', 'term']: - # An ancestor "arith_expr" or "term" means we have found an operator - # with lower precedence than our tok. - return True - if predecessor_type != 'atom': - # We understand the context to look for precedence within as an - # arbitrary nesting of "arith_expr", "term", and "atom" nodes. If we - # leave this context we have not found a lower precedence operator. - return False - # Under normal usage we expect a complete parse tree to be available and - # we will return before we get an AttributeError from the root. - ancestor = ancestor.parent + while ancestor is not None: + # Search through the ancestor nodes in the parse tree for operators with + # lower precedence. + predecessor_type = pytree_utils.NodeName( ancestor ) + if predecessor_type in [ 'arith_expr', 'term' ]: + # An ancestor "arith_expr" or "term" means we have found an operator + # with lower precedence than our tok. + return True + if predecessor_type != 'atom': + # We understand the context to look for precedence within as an + # arbitrary nesting of "arith_expr", "term", and "atom" nodes. If we + # leave this context we have not found a lower precedence operator. + return False + # Under normal usage we expect a complete parse tree to be available and + # we will return before we get an AttributeError from the root. + ancestor = ancestor.parent -def _PriorityIndicatingNoSpace(tok): - """Whether to remove spaces around an operator due to precedence.""" - if not tok.is_arithmetic_op or not tok.is_simple_expr: - # Limit space removal to highest priority arithmetic operators - return False - return _HasPrecedence(tok) +def _PriorityIndicatingNoSpace( tok ): + """Whether to remove spaces around an operator due to precedence.""" + if not tok.is_arithmetic_op or not tok.is_simple_expr: + # Limit space removal to highest priority arithmetic operators + return False + return _HasPrecedence( tok ) -def _IsSubscriptColonAndValuePair(token1, token2): - return (token1.is_number or token1.is_name) and token2.is_subscript_colon +def _IsSubscriptColonAndValuePair( token1, token2 ): + return ( token1.is_number or token1.is_name ) and token2.is_subscript_colon -def _SpaceRequiredBetween(left, right, is_line_disabled): - """Return True if a space is required between the left and right token.""" - lval = left.value - rval = right.value - if (left.is_pseudo and _IsIdNumberStringToken(right) and - left.previous_token and _IsIdNumberStringToken(left.previous_token)): - # Space between keyword... tokens and pseudo parens. - return True - if left.is_pseudo or right.is_pseudo: - # There should be a space after the ':' in a dictionary. - if left.OpensScope(): - return True - # The closing pseudo-paren shouldn't affect spacing. - return False - if left.is_continuation or right.is_continuation: - # The continuation node's value has all of the spaces it needs. - return False - if right.name in pytree_utils.NONSEMANTIC_TOKENS: - # No space before a non-semantic token. - return False - if _IsIdNumberStringToken(left) and _IsIdNumberStringToken(right): - # Spaces between keyword, string, number, and identifier tokens. - return True - if lval == ',' and rval == ':': - # We do want a space between a comma and colon. - return True - if style.Get('SPACE_INSIDE_BRACKETS'): - # Supersede the "no space before a colon or comma" check. - if left.OpensScope() and rval == ':': - return True - if right.ClosesScope() and lval == ':': - return True - if (style.Get('SPACES_AROUND_SUBSCRIPT_COLON') and - (_IsSubscriptColonAndValuePair(left, right) or - _IsSubscriptColonAndValuePair(right, left))): - # Supersede the "never want a space before a colon or comma" check. - return True - if rval in ':,': - # Otherwise, we never want a space before a colon or comma. - return False - if lval == ',' and rval in ']})': - # Add a space between ending ',' and closing bracket if requested. - return style.Get('SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET') - if lval == ',': - # We want a space after a comma. - return True - if lval == 'from' and rval == '.': - # Space before the '.' in an import statement. - return True - if lval == '.' and rval == 'import': - # Space after the '.' in an import statement. - return True - if (lval == '=' and rval in {'.', ',,,'} and - subtypes.DEFAULT_OR_NAMED_ASSIGN not in left.subtypes): - # Space between equal and '.' as in "X = ...". - return True - if lval == ':' and rval in {'.', '...'}: - # Space between : and ... - return True - if ((right.is_keyword or right.is_name) and - (left.is_keyword or left.is_name)): - # Don't merge two keywords/identifiers. - return True - if (subtypes.SUBSCRIPT_COLON in left.subtypes or - subtypes.SUBSCRIPT_COLON in right.subtypes): - # A subscript shouldn't have spaces separating its colons. - return False - if (subtypes.TYPED_NAME in left.subtypes or - subtypes.TYPED_NAME in right.subtypes): - # A typed argument should have a space after the colon. - return True - if left.is_string: - if (rval == '=' and - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in right.subtypes): - # If there is a type hint, then we don't want to add a space between the - # equal sign and the hint. - return False - if rval not in '[)]}.' and not right.is_binary_op: - # A string followed by something other than a subscript, closing bracket, - # dot, or a binary op should have a space after it. - return True +def _SpaceRequiredBetween( left, right, is_line_disabled ): + """Return True if a space is required between the left and right token.""" + lval = left.value + rval = right.value + if ( left.is_pseudo and _IsIdNumberStringToken( right ) and left.previous_token and + _IsIdNumberStringToken( left.previous_token ) ): + # Space between keyword... tokens and pseudo parens. + return True + if left.is_pseudo or right.is_pseudo: + # There should be a space after the ':' in a dictionary. + if left.OpensScope(): + return True + # The closing pseudo-paren shouldn't affect spacing. + return False + if left.is_continuation or right.is_continuation: + # The continuation node's value has all of the spaces it needs. + return False + if right.name in pytree_utils.NONSEMANTIC_TOKENS: + # No space before a non-semantic token. + return False + if _IsIdNumberStringToken( left ) and _IsIdNumberStringToken( right ): + # Spaces between keyword, string, number, and identifier tokens. + return True + if lval == ',' and rval == ':': + # We do want a space between a comma and colon. + return True + if style.Get( 'SPACE_INSIDE_BRACKETS' ): + # Supersede the "no space before a colon or comma" check. + if left.OpensScope() and rval == ':': + return True + if right.ClosesScope() and lval == ':': + return True + if ( style.Get( 'SPACES_AROUND_SUBSCRIPT_COLON' ) and + ( _IsSubscriptColonAndValuePair( left, right ) or + _IsSubscriptColonAndValuePair( right, left ) ) ): + # Supersede the "never want a space before a colon or comma" check. + return True + if rval in ':,': + # Otherwise, we never want a space before a colon or comma. + return False + if lval == ',' and rval in ']})': + # Add a space between ending ',' and closing bracket if requested. + return style.Get( 'SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET' ) + if lval == ',': + # We want a space after a comma. + return True + if lval == 'from' and rval == '.': + # Space before the '.' in an import statement. + return True + if lval == '.' and rval == 'import': + # Space after the '.' in an import statement. + return True + if ( lval == '=' and rval in { '.', ',,,' } and + subtypes.DEFAULT_OR_NAMED_ASSIGN not in left.subtypes ): + # Space between equal and '.' as in "X = ...". + return True + if lval == ':' and rval in { '.', '...' }: + # Space between : and ... + return True + if ( ( right.is_keyword or right.is_name ) and + ( left.is_keyword or left.is_name ) ): + # Don't merge two keywords/identifiers. + return True + if ( subtypes.SUBSCRIPT_COLON in left.subtypes or + subtypes.SUBSCRIPT_COLON in right.subtypes ): + # A subscript shouldn't have spaces separating its colons. + return False + if ( subtypes.TYPED_NAME in left.subtypes or + subtypes.TYPED_NAME in right.subtypes ): + # A typed argument should have a space after the colon. + return True + if left.is_string: + if ( rval == '=' and + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in right.subtypes ): + # If there is a type hint, then we don't want to add a space between the + # equal sign and the hint. + return False + if rval not in '[)]}.' and not right.is_binary_op: + # A string followed by something other than a subscript, closing bracket, + # dot, or a binary op should have a space after it. + return True + if right.ClosesScope(): + # A string followed by closing brackets should have a space after it + # depending on SPACE_INSIDE_BRACKETS. A string followed by opening + # brackets, however, should not. + return style.Get( 'SPACE_INSIDE_BRACKETS' ) + if subtypes.SUBSCRIPT_BRACKET in right.subtypes: + # It's legal to do this in Python: 'hello'[a] + return False + if left.is_binary_op and lval != '**' and _IsUnaryOperator( right ): + # Space between the binary operator and the unary operator. + return True + if left.is_keyword and _IsUnaryOperator( right ): + # Handle things like "not -3 < x". + return True + if _IsUnaryOperator( left ) and _IsUnaryOperator( right ): + # No space between two unary operators. + return False + if left.is_binary_op or right.is_binary_op: + if lval == '**' or rval == '**': + # Space around the "power" operator. + return style.Get( 'SPACES_AROUND_POWER_OPERATOR' ) + # Enforce spaces around binary operators except the blocked ones. + block_list = style.Get( 'NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS' ) + if lval in block_list or rval in block_list: + return False + if style.Get( 'ARITHMETIC_PRECEDENCE_INDICATION' ): + if _PriorityIndicatingNoSpace( left ) or _PriorityIndicatingNoSpace( + right ): + return False + else: + return True + else: + return True + if ( _IsUnaryOperator( left ) and lval != 'not' and + ( right.is_name or right.is_number or rval == '(' ) ): + # The previous token was a unary op. No space is desired between it and + # the current token. + return False + if ( subtypes.DEFAULT_OR_NAMED_ASSIGN in left.subtypes and + subtypes.TYPED_NAME not in right.subtypes ): + # A named argument or default parameter shouldn't have spaces around it. + return style.Get( 'SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN' ) + if ( subtypes.DEFAULT_OR_NAMED_ASSIGN in right.subtypes and + subtypes.TYPED_NAME not in left.subtypes ): + # A named argument or default parameter shouldn't have spaces around it. + return style.Get( 'SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN' ) + if ( subtypes.VARARGS_LIST in left.subtypes or + subtypes.VARARGS_LIST in right.subtypes ): + return False + if ( subtypes.VARARGS_STAR in left.subtypes or + subtypes.KWARGS_STAR_STAR in left.subtypes ): + # Don't add a space after a vararg's star or a keyword's star-star. + return False + if lval == '@' and subtypes.DECORATOR in left.subtypes: + # Decorators shouldn't be separated from the 'at' sign. + return False + if left.is_keyword and rval == '.': + # Add space between keywords and dots. + return lval not in { 'None', 'print' } + if lval == '.' and right.is_keyword: + # Add space between keywords and dots. + return rval not in { 'None', 'print' } + if lval == '.' or rval == '.': + # Don't place spaces between dots. + return False + if ( ( lval == '(' and rval == ')' ) or ( lval == '[' and rval == ']' ) or + ( lval == '{' and rval == '}' ) ): + # Empty objects shouldn't be separated by spaces. + return False + if not is_line_disabled and ( left.OpensScope() or right.ClosesScope() ): + if ( style.GetOrDefault( 'SPACES_AROUND_DICT_DELIMITERS', False ) and + ( ( lval == '{' and + _IsDictListTupleDelimiterTok( left, is_opening = True ) ) or + ( rval == '}' and + _IsDictListTupleDelimiterTok( right, is_opening = False ) ) ) ): + return True + if ( style.GetOrDefault( 'SPACES_AROUND_LIST_DELIMITERS', False ) and + ( ( lval == '[' and + _IsDictListTupleDelimiterTok( left, is_opening = True ) ) or + ( rval == ']' and + _IsDictListTupleDelimiterTok( right, is_opening = False ) ) ) ): + return True + if ( style.GetOrDefault( 'SPACES_AROUND_TUPLE_DELIMITERS', False ) and + ( ( lval == '(' and + _IsDictListTupleDelimiterTok( left, is_opening = True ) ) or + ( rval == ')' and + _IsDictListTupleDelimiterTok( right, is_opening = False ) ) ) ): + return True + if left.OpensScope() and right.OpensScope(): + # Nested objects' opening brackets shouldn't be separated, unless enabled + # by SPACE_INSIDE_BRACKETS. + return style.Get( 'SPACE_INSIDE_BRACKETS' ) + if left.ClosesScope() and right.ClosesScope(): + # Nested objects' closing brackets shouldn't be separated, unless enabled + # by SPACE_INSIDE_BRACKETS. + return style.Get( 'SPACE_INSIDE_BRACKETS' ) + if left.ClosesScope() and rval in '([': + # A call, set, dictionary, or subscript that has a call or subscript after + # it shouldn't have a space between them. + return False + if left.OpensScope() and _IsIdNumberStringToken( right ): + # Don't separate the opening bracket from the first item, unless enabled + # by SPACE_INSIDE_BRACKETS. + return style.Get( 'SPACE_INSIDE_BRACKETS' ) + if left.is_name and rval in '([': + # Don't separate a call or array access from the name. + return False if right.ClosesScope(): - # A string followed by closing brackets should have a space after it - # depending on SPACE_INSIDE_BRACKETS. A string followed by opening - # brackets, however, should not. - return style.Get('SPACE_INSIDE_BRACKETS') - if subtypes.SUBSCRIPT_BRACKET in right.subtypes: - # It's legal to do this in Python: 'hello'[a] - return False - if left.is_binary_op and lval != '**' and _IsUnaryOperator(right): - # Space between the binary operator and the unary operator. + # Don't separate the closing bracket from the last item, unless enabled + # by SPACE_INSIDE_BRACKETS. + # FIXME(morbo): This might be too permissive. + return style.Get( 'SPACE_INSIDE_BRACKETS' ) + if lval == 'print' and rval == '(': + # Special support for the 'print' function. + return False + if left.OpensScope() and _IsUnaryOperator( right ): + # Don't separate a unary operator from the opening bracket, unless enabled + # by SPACE_INSIDE_BRACKETS. + return style.Get( 'SPACE_INSIDE_BRACKETS' ) + if ( left.OpensScope() and ( subtypes.VARARGS_STAR in right.subtypes or + subtypes.KWARGS_STAR_STAR in right.subtypes ) ): + # Don't separate a '*' or '**' from the opening bracket, unless enabled + # by SPACE_INSIDE_BRACKETS. + return style.Get( 'SPACE_INSIDE_BRACKETS' ) + if rval == ';': + # Avoid spaces before a semicolon. (Why is there a semicolon?!) + return False + if lval == '(' and rval == 'await': + # Special support for the 'await' keyword. Don't separate the 'await' + # keyword from an opening paren, unless enabled by SPACE_INSIDE_BRACKETS. + return style.Get( 'SPACE_INSIDE_BRACKETS' ) return True - if left.is_keyword and _IsUnaryOperator(right): - # Handle things like "not -3 < x". + + +def _MustBreakBefore( prev_token, cur_token ): + """Return True if a line break is required before the current token.""" + if prev_token.is_comment or ( prev_token.previous_token and prev_token.is_pseudo and + prev_token.previous_token.is_comment ): + # Must break if the previous token was a comment. + return True + if ( cur_token.is_string and prev_token.is_string and + IsSurroundedByBrackets( cur_token ) ): + # We want consecutive strings to be on separate lines. This is a + # reasonable assumption, because otherwise they should have written them + # all on the same line, or with a '+'. + return True + return cur_token.must_break_before + + +def _CanBreakBefore( prev_token, cur_token ): + """Return True if a line break may occur before the current token.""" + pval = prev_token.value + cval = cur_token.value + if py3compat.PY3: + if pval == 'yield' and cval == 'from': + # Don't break before a yield argument. + return False + if pval in { 'async', 'await' } and cval in { 'def', 'with', 'for' }: + # Don't break after sync keywords. + return False + if cur_token.split_penalty >= split_penalty.UNBREAKABLE: + return False + if pval == '@': + # Don't break right after the beginning of a decorator. + return False + if cval == ':': + # Don't break before the start of a block of code. + return False + if cval == ',': + # Don't break before a comma. + return False + if prev_token.is_name and cval == '(': + # Don't break in the middle of a function definition or call. + return False + if prev_token.is_name and cval == '[': + # Don't break in the middle of an array dereference. + return False + if cur_token.is_comment and prev_token.lineno == cur_token.lineno: + # Don't break a comment at the end of the line. + return False + if subtypes.UNARY_OPERATOR in prev_token.subtypes: + # Don't break after a unary token. + return False + if not style.Get( 'ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS' ): + if ( subtypes.DEFAULT_OR_NAMED_ASSIGN in cur_token.subtypes or + subtypes.DEFAULT_OR_NAMED_ASSIGN in prev_token.subtypes ): + return False return True - if _IsUnaryOperator(left) and _IsUnaryOperator(right): - # No space between two unary operators. - return False - if left.is_binary_op or right.is_binary_op: - if lval == '**' or rval == '**': - # Space around the "power" operator. - return style.Get('SPACES_AROUND_POWER_OPERATOR') - # Enforce spaces around binary operators except the blocked ones. - block_list = style.Get('NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS') - if lval in block_list or rval in block_list: - return False - if style.Get('ARITHMETIC_PRECEDENCE_INDICATION'): - if _PriorityIndicatingNoSpace(left) or _PriorityIndicatingNoSpace(right): + + +def IsSurroundedByBrackets( tok ): + """Return True if the token is surrounded by brackets.""" + paren_count = 0 + brace_count = 0 + sq_bracket_count = 0 + previous_token = tok.previous_token + while previous_token: + if previous_token.value == ')': + paren_count -= 1 + elif previous_token.value == '}': + brace_count -= 1 + elif previous_token.value == ']': + sq_bracket_count -= 1 + + if previous_token.value == '(': + if paren_count == 0: + return previous_token + paren_count += 1 + elif previous_token.value == '{': + if brace_count == 0: + return previous_token + brace_count += 1 + elif previous_token.value == '[': + if sq_bracket_count == 0: + return previous_token + sq_bracket_count += 1 + + previous_token = previous_token.previous_token + return None + + +def _IsDictListTupleDelimiterTok( tok, is_opening ): + assert tok + + if tok.matching_bracket is None: return False - else: - return True + + if is_opening: + open_tok = tok + close_tok = tok.matching_bracket else: - return True - if (_IsUnaryOperator(left) and lval != 'not' and - (right.is_name or right.is_number or rval == '(')): - # The previous token was a unary op. No space is desired between it and - # the current token. - return False - if (subtypes.DEFAULT_OR_NAMED_ASSIGN in left.subtypes and - subtypes.TYPED_NAME not in right.subtypes): - # A named argument or default parameter shouldn't have spaces around it. - return style.Get('SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN') - if (subtypes.DEFAULT_OR_NAMED_ASSIGN in right.subtypes and - subtypes.TYPED_NAME not in left.subtypes): - # A named argument or default parameter shouldn't have spaces around it. - return style.Get('SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN') - if (subtypes.VARARGS_LIST in left.subtypes or - subtypes.VARARGS_LIST in right.subtypes): - return False - if (subtypes.VARARGS_STAR in left.subtypes or - subtypes.KWARGS_STAR_STAR in left.subtypes): - # Don't add a space after a vararg's star or a keyword's star-star. - return False - if lval == '@' and subtypes.DECORATOR in left.subtypes: - # Decorators shouldn't be separated from the 'at' sign. - return False - if left.is_keyword and rval == '.': - # Add space between keywords and dots. - return lval not in {'None', 'print'} - if lval == '.' and right.is_keyword: - # Add space between keywords and dots. - return rval not in {'None', 'print'} - if lval == '.' or rval == '.': - # Don't place spaces between dots. - return False - if ((lval == '(' and rval == ')') or (lval == '[' and rval == ']') or - (lval == '{' and rval == '}')): - # Empty objects shouldn't be separated by spaces. - return False - if not is_line_disabled and (left.OpensScope() or right.ClosesScope()): - if (style.GetOrDefault('SPACES_AROUND_DICT_DELIMITERS', False) and ( - (lval == '{' and _IsDictListTupleDelimiterTok(left, is_opening=True)) or - (rval == '}' and - _IsDictListTupleDelimiterTok(right, is_opening=False)))): - return True - if (style.GetOrDefault('SPACES_AROUND_LIST_DELIMITERS', False) and ( - (lval == '[' and _IsDictListTupleDelimiterTok(left, is_opening=True)) or - (rval == ']' and - _IsDictListTupleDelimiterTok(right, is_opening=False)))): - return True - if (style.GetOrDefault('SPACES_AROUND_TUPLE_DELIMITERS', False) and ( - (lval == '(' and _IsDictListTupleDelimiterTok(left, is_opening=True)) or - (rval == ')' and - _IsDictListTupleDelimiterTok(right, is_opening=False)))): - return True - if left.OpensScope() and right.OpensScope(): - # Nested objects' opening brackets shouldn't be separated, unless enabled - # by SPACE_INSIDE_BRACKETS. - return style.Get('SPACE_INSIDE_BRACKETS') - if left.ClosesScope() and right.ClosesScope(): - # Nested objects' closing brackets shouldn't be separated, unless enabled - # by SPACE_INSIDE_BRACKETS. - return style.Get('SPACE_INSIDE_BRACKETS') - if left.ClosesScope() and rval in '([': - # A call, set, dictionary, or subscript that has a call or subscript after - # it shouldn't have a space between them. - return False - if left.OpensScope() and _IsIdNumberStringToken(right): - # Don't separate the opening bracket from the first item, unless enabled - # by SPACE_INSIDE_BRACKETS. - return style.Get('SPACE_INSIDE_BRACKETS') - if left.is_name and rval in '([': - # Don't separate a call or array access from the name. - return False - if right.ClosesScope(): - # Don't separate the closing bracket from the last item, unless enabled - # by SPACE_INSIDE_BRACKETS. - # FIXME(morbo): This might be too permissive. - return style.Get('SPACE_INSIDE_BRACKETS') - if lval == 'print' and rval == '(': - # Special support for the 'print' function. - return False - if left.OpensScope() and _IsUnaryOperator(right): - # Don't separate a unary operator from the opening bracket, unless enabled - # by SPACE_INSIDE_BRACKETS. - return style.Get('SPACE_INSIDE_BRACKETS') - if (left.OpensScope() and (subtypes.VARARGS_STAR in right.subtypes or - subtypes.KWARGS_STAR_STAR in right.subtypes)): - # Don't separate a '*' or '**' from the opening bracket, unless enabled - # by SPACE_INSIDE_BRACKETS. - return style.Get('SPACE_INSIDE_BRACKETS') - if rval == ';': - # Avoid spaces before a semicolon. (Why is there a semicolon?!) - return False - if lval == '(' and rval == 'await': - # Special support for the 'await' keyword. Don't separate the 'await' - # keyword from an opening paren, unless enabled by SPACE_INSIDE_BRACKETS. - return style.Get('SPACE_INSIDE_BRACKETS') - return True - - -def _MustBreakBefore(prev_token, cur_token): - """Return True if a line break is required before the current token.""" - if prev_token.is_comment or (prev_token.previous_token and - prev_token.is_pseudo and - prev_token.previous_token.is_comment): - # Must break if the previous token was a comment. - return True - if (cur_token.is_string and prev_token.is_string and - IsSurroundedByBrackets(cur_token)): - # We want consecutive strings to be on separate lines. This is a - # reasonable assumption, because otherwise they should have written them - # all on the same line, or with a '+'. - return True - return cur_token.must_break_before - - -def _CanBreakBefore(prev_token, cur_token): - """Return True if a line break may occur before the current token.""" - pval = prev_token.value - cval = cur_token.value - if py3compat.PY3: - if pval == 'yield' and cval == 'from': - # Don't break before a yield argument. - return False - if pval in {'async', 'await'} and cval in {'def', 'with', 'for'}: - # Don't break after sync keywords. - return False - if cur_token.split_penalty >= split_penalty.UNBREAKABLE: - return False - if pval == '@': - # Don't break right after the beginning of a decorator. - return False - if cval == ':': - # Don't break before the start of a block of code. - return False - if cval == ',': - # Don't break before a comma. - return False - if prev_token.is_name and cval == '(': - # Don't break in the middle of a function definition or call. - return False - if prev_token.is_name and cval == '[': - # Don't break in the middle of an array dereference. - return False - if cur_token.is_comment and prev_token.lineno == cur_token.lineno: - # Don't break a comment at the end of the line. - return False - if subtypes.UNARY_OPERATOR in prev_token.subtypes: - # Don't break after a unary token. - return False - if not style.Get('ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS'): - if (subtypes.DEFAULT_OR_NAMED_ASSIGN in cur_token.subtypes or - subtypes.DEFAULT_OR_NAMED_ASSIGN in prev_token.subtypes): - return False - return True - - -def IsSurroundedByBrackets(tok): - """Return True if the token is surrounded by brackets.""" - paren_count = 0 - brace_count = 0 - sq_bracket_count = 0 - previous_token = tok.previous_token - while previous_token: - if previous_token.value == ')': - paren_count -= 1 - elif previous_token.value == '}': - brace_count -= 1 - elif previous_token.value == ']': - sq_bracket_count -= 1 - - if previous_token.value == '(': - if paren_count == 0: - return previous_token - paren_count += 1 - elif previous_token.value == '{': - if brace_count == 0: - return previous_token - brace_count += 1 - elif previous_token.value == '[': - if sq_bracket_count == 0: - return previous_token - sq_bracket_count += 1 - - previous_token = previous_token.previous_token - return None - - -def _IsDictListTupleDelimiterTok(tok, is_opening): - assert tok - - if tok.matching_bracket is None: - return False - - if is_opening: - open_tok = tok - close_tok = tok.matching_bracket - else: - open_tok = tok.matching_bracket - close_tok = tok - - # There must be something in between the tokens - if open_tok.next_token == close_tok: - return False - - assert open_tok.next_token.node - assert open_tok.next_token.node.parent - - return open_tok.next_token.node.parent.type in [ - python_symbols.dictsetmaker, - python_symbols.listmaker, - python_symbols.testlist_gexp, - ] - - -_LOGICAL_OPERATORS = frozenset({'and', 'or'}) -_BITWISE_OPERATORS = frozenset({'&', '|', '^'}) -_ARITHMETIC_OPERATORS = frozenset({'+', '-', '*', '/', '%', '//', '@'}) - - -def _SplitPenalty(prev_token, cur_token): - """Return the penalty for breaking the line before the current token.""" - pval = prev_token.value - cval = cur_token.value - if pval == 'not': - return split_penalty.UNBREAKABLE - - if cur_token.node_split_penalty > 0: - return cur_token.node_split_penalty - - if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'): - # Prefer to split before 'and' and 'or'. - if pval in _LOGICAL_OPERATORS: - return style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR') - if cval in _LOGICAL_OPERATORS: - return 0 - else: - # Prefer to split after 'and' and 'or'. - if pval in _LOGICAL_OPERATORS: - return 0 - if cval in _LOGICAL_OPERATORS: - return style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR') - - if style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'): - # Prefer to split before '&', '|', and '^'. - if pval in _BITWISE_OPERATORS: - return style.Get('SPLIT_PENALTY_BITWISE_OPERATOR') - if cval in _BITWISE_OPERATORS: - return 0 - else: - # Prefer to split after '&', '|', and '^'. - if pval in _BITWISE_OPERATORS: - return 0 - if cval in _BITWISE_OPERATORS: - return style.Get('SPLIT_PENALTY_BITWISE_OPERATOR') - - if (subtypes.COMP_FOR in cur_token.subtypes or - subtypes.COMP_IF in cur_token.subtypes): - # We don't mind breaking before the 'for' or 'if' of a list comprehension. - return 0 - if subtypes.UNARY_OPERATOR in prev_token.subtypes: - # Try not to break after a unary operator. - return style.Get('SPLIT_PENALTY_AFTER_UNARY_OPERATOR') - if pval == ',': - # Breaking after a comma is fine, if need be. + open_tok = tok.matching_bracket + close_tok = tok + + # There must be something in between the tokens + if open_tok.next_token == close_tok: + return False + + assert open_tok.next_token.node + assert open_tok.next_token.node.parent + + return open_tok.next_token.node.parent.type in [ + python_symbols.dictsetmaker, + python_symbols.listmaker, + python_symbols.testlist_gexp, + ] + + +_LOGICAL_OPERATORS = frozenset( { 'and', 'or' } ) +_BITWISE_OPERATORS = frozenset( { '&', '|', '^' } ) +_ARITHMETIC_OPERATORS = frozenset( { '+', '-', '*', '/', '%', '//', '@' } ) + + +def _SplitPenalty( prev_token, cur_token ): + """Return the penalty for breaking the line before the current token.""" + pval = prev_token.value + cval = cur_token.value + if pval == 'not': + return split_penalty.UNBREAKABLE + + if cur_token.node_split_penalty > 0: + return cur_token.node_split_penalty + + if style.Get( 'SPLIT_BEFORE_LOGICAL_OPERATOR' ): + # Prefer to split before 'and' and 'or'. + if pval in _LOGICAL_OPERATORS: + return style.Get( 'SPLIT_PENALTY_LOGICAL_OPERATOR' ) + if cval in _LOGICAL_OPERATORS: + return 0 + else: + # Prefer to split after 'and' and 'or'. + if pval in _LOGICAL_OPERATORS: + return 0 + if cval in _LOGICAL_OPERATORS: + return style.Get( 'SPLIT_PENALTY_LOGICAL_OPERATOR' ) + + if style.Get( 'SPLIT_BEFORE_BITWISE_OPERATOR' ): + # Prefer to split before '&', '|', and '^'. + if pval in _BITWISE_OPERATORS: + return style.Get( 'SPLIT_PENALTY_BITWISE_OPERATOR' ) + if cval in _BITWISE_OPERATORS: + return 0 + else: + # Prefer to split after '&', '|', and '^'. + if pval in _BITWISE_OPERATORS: + return 0 + if cval in _BITWISE_OPERATORS: + return style.Get( 'SPLIT_PENALTY_BITWISE_OPERATOR' ) + + if ( subtypes.COMP_FOR in cur_token.subtypes or + subtypes.COMP_IF in cur_token.subtypes ): + # We don't mind breaking before the 'for' or 'if' of a list comprehension. + return 0 + if subtypes.UNARY_OPERATOR in prev_token.subtypes: + # Try not to break after a unary operator. + return style.Get( 'SPLIT_PENALTY_AFTER_UNARY_OPERATOR' ) + if pval == ',': + # Breaking after a comma is fine, if need be. + return 0 + if pval == '**' or cval == '**': + return split_penalty.STRONGLY_CONNECTED + if ( subtypes.VARARGS_STAR in prev_token.subtypes or + subtypes.KWARGS_STAR_STAR in prev_token.subtypes ): + # Don't split after a varargs * or kwargs **. + return split_penalty.UNBREAKABLE + if prev_token.OpensScope() and cval != '(': + # Slightly prefer + return style.Get( 'SPLIT_PENALTY_AFTER_OPENING_BRACKET' ) + if cval == ':': + # Don't split before a colon. + return split_penalty.UNBREAKABLE + if cval == '=': + # Don't split before an assignment. + return split_penalty.UNBREAKABLE + if ( subtypes.DEFAULT_OR_NAMED_ASSIGN in prev_token.subtypes or + subtypes.DEFAULT_OR_NAMED_ASSIGN in cur_token.subtypes ): + # Don't break before or after an default or named assignment. + return split_penalty.UNBREAKABLE + if cval == '==': + # We would rather not split before an equality operator. + return split_penalty.STRONGLY_CONNECTED + if cur_token.ClosesScope(): + # Give a slight penalty for splitting before the closing scope. + return 100 return 0 - if pval == '**' or cval == '**': - return split_penalty.STRONGLY_CONNECTED - if (subtypes.VARARGS_STAR in prev_token.subtypes or - subtypes.KWARGS_STAR_STAR in prev_token.subtypes): - # Don't split after a varargs * or kwargs **. - return split_penalty.UNBREAKABLE - if prev_token.OpensScope() and cval != '(': - # Slightly prefer - return style.Get('SPLIT_PENALTY_AFTER_OPENING_BRACKET') - if cval == ':': - # Don't split before a colon. - return split_penalty.UNBREAKABLE - if cval == '=': - # Don't split before an assignment. - return split_penalty.UNBREAKABLE - if (subtypes.DEFAULT_OR_NAMED_ASSIGN in prev_token.subtypes or - subtypes.DEFAULT_OR_NAMED_ASSIGN in cur_token.subtypes): - # Don't break before or after an default or named assignment. - return split_penalty.UNBREAKABLE - if cval == '==': - # We would rather not split before an equality operator. - return split_penalty.STRONGLY_CONNECTED - if cur_token.ClosesScope(): - # Give a slight penalty for splitting before the closing scope. - return 100 - return 0 diff --git a/yapf/yapflib/object_state.py b/yapf/yapflib/object_state.py index ec259e682..58dd6fe18 100644 --- a/yapf/yapflib/object_state.py +++ b/yapf/yapflib/object_state.py @@ -27,8 +27,8 @@ from yapf.yapflib import subtypes -class ComprehensionState(object): - """Maintains the state of list comprehension formatting decisions. +class ComprehensionState( object ): + """Maintains the state of list comprehension formatting decisions. A stack of ComprehensionState objects are kept to ensure that list comprehensions are wrapped with well-defined rules. @@ -44,50 +44,53 @@ class ComprehensionState(object): That is, a split somewhere after expr_token or before closing_bracket. """ - def __init__(self, expr_token): - self.expr_token = expr_token - self.for_token = None - self.has_split_at_for = False - self.has_interior_split = False + def __init__( self, expr_token ): + self.expr_token = expr_token + self.for_token = None + self.has_split_at_for = False + self.has_interior_split = False - def HasTrivialExpr(self): - """Returns whether the comp_expr is "trivial" i.e. is a single token.""" - return self.expr_token.next_token.value == 'for' + def HasTrivialExpr( self ): + """Returns whether the comp_expr is "trivial" i.e. is a single token.""" + return self.expr_token.next_token.value == 'for' - @property - def opening_bracket(self): - return self.expr_token.previous_token + @property + def opening_bracket( self ): + return self.expr_token.previous_token - @property - def closing_bracket(self): - return self.opening_bracket.matching_bracket + @property + def closing_bracket( self ): + return self.opening_bracket.matching_bracket - def Clone(self): - clone = ComprehensionState(self.expr_token) - clone.for_token = self.for_token - clone.has_split_at_for = self.has_split_at_for - clone.has_interior_split = self.has_interior_split - return clone + def Clone( self ): + clone = ComprehensionState( self.expr_token ) + clone.for_token = self.for_token + clone.has_split_at_for = self.has_split_at_for + clone.has_interior_split = self.has_interior_split + return clone - def __repr__(self): - return ('[opening_bracket::%s, for_token::%s, has_split_at_for::%s,' - ' has_interior_split::%s, has_trivial_expr::%s]' % - (self.opening_bracket, self.for_token, self.has_split_at_for, - self.has_interior_split, self.HasTrivialExpr())) + def __repr__( self ): + return ( + '[opening_bracket::%s, for_token::%s, has_split_at_for::%s,' + ' has_interior_split::%s, has_trivial_expr::%s]' % ( + self.opening_bracket, self.for_token, self.has_split_at_for, + self.has_interior_split, self.HasTrivialExpr() ) ) - def __eq__(self, other): - return hash(self) == hash(other) + def __eq__( self, other ): + return hash( self ) == hash( other ) - def __ne__(self, other): - return not self == other + def __ne__( self, other ): + return not self == other - def __hash__(self, *args, **kwargs): - return hash((self.expr_token, self.for_token, self.has_split_at_for, - self.has_interior_split)) + def __hash__( self, *args, **kwargs ): + return hash( + ( + self.expr_token, self.for_token, self.has_split_at_for, + self.has_interior_split ) ) -class ParameterListState(object): - """Maintains the state of function parameter list formatting decisions. +class ParameterListState( object ): + """Maintains the state of function parameter list formatting decisions. Attributes: opening_bracket: The opening bracket of the parameter list. @@ -104,95 +107,97 @@ class ParameterListState(object): needed if the indentation would collide. """ - def __init__(self, opening_bracket, newline, opening_column): - self.opening_bracket = opening_bracket - self.has_split_before_first_param = newline - self.opening_column = opening_column - self.parameters = opening_bracket.parameters - self.split_before_closing_bracket = False - - @property - def closing_bracket(self): - return self.opening_bracket.matching_bracket - - @property - def has_typed_return(self): - return self.closing_bracket.next_token.value == '->' - - @property - @py3compat.lru_cache() - def has_default_values(self): - return any(param.has_default_value for param in self.parameters) - - @property - @py3compat.lru_cache() - def ends_in_comma(self): - if not self.parameters: - return False - return self.parameters[-1].last_token.next_token.value == ',' - - @property - @py3compat.lru_cache() - def last_token(self): - token = self.opening_bracket.matching_bracket - while not token.is_comment and token.next_token: - token = token.next_token - return token - - @py3compat.lru_cache() - def LastParamFitsOnLine(self, indent): - """Return true if the last parameter fits on a single line.""" - if not self.has_typed_return: - return False - if not self.parameters: - return True - total_length = self.last_token.total_length - last_param = self.parameters[-1].first_token - total_length -= last_param.total_length - len(last_param.value) - return total_length + indent <= style.Get('COLUMN_LIMIT') - - @py3compat.lru_cache() - def SplitBeforeClosingBracket(self, indent): - """Return true if there's a split before the closing bracket.""" - if style.Get('DEDENT_CLOSING_BRACKETS'): - return True - if self.ends_in_comma: - return True - if not self.parameters: - return False - total_length = self.last_token.total_length - last_param = self.parameters[-1].first_token - total_length -= last_param.total_length - len(last_param.value) - return total_length + indent > style.Get('COLUMN_LIMIT') - - def Clone(self): - clone = ParameterListState(self.opening_bracket, - self.has_split_before_first_param, - self.opening_column) - clone.split_before_closing_bracket = self.split_before_closing_bracket - clone.parameters = [param.Clone() for param in self.parameters] - return clone - - def __repr__(self): - return ('[opening_bracket::%s, has_split_before_first_param::%s, ' - 'opening_column::%d]' % - (self.opening_bracket, self.has_split_before_first_param, - self.opening_column)) - - def __eq__(self, other): - return hash(self) == hash(other) - - def __ne__(self, other): - return not self == other - - def __hash__(self, *args, **kwargs): - return hash( - (self.opening_bracket, self.has_split_before_first_param, - self.opening_column, (hash(param) for param in self.parameters))) - - -class Parameter(object): - """A parameter in a parameter list. + def __init__( self, opening_bracket, newline, opening_column ): + self.opening_bracket = opening_bracket + self.has_split_before_first_param = newline + self.opening_column = opening_column + self.parameters = opening_bracket.parameters + self.split_before_closing_bracket = False + + @property + def closing_bracket( self ): + return self.opening_bracket.matching_bracket + + @property + def has_typed_return( self ): + return self.closing_bracket.next_token.value == '->' + + @property + @py3compat.lru_cache() + def has_default_values( self ): + return any( param.has_default_value for param in self.parameters ) + + @property + @py3compat.lru_cache() + def ends_in_comma( self ): + if not self.parameters: + return False + return self.parameters[ -1 ].last_token.next_token.value == ',' + + @property + @py3compat.lru_cache() + def last_token( self ): + token = self.opening_bracket.matching_bracket + while not token.is_comment and token.next_token: + token = token.next_token + return token + + @py3compat.lru_cache() + def LastParamFitsOnLine( self, indent ): + """Return true if the last parameter fits on a single line.""" + if not self.has_typed_return: + return False + if not self.parameters: + return True + total_length = self.last_token.total_length + last_param = self.parameters[ -1 ].first_token + total_length -= last_param.total_length - len( last_param.value ) + return total_length + indent <= style.Get( 'COLUMN_LIMIT' ) + + @py3compat.lru_cache() + def SplitBeforeClosingBracket( self, indent ): + """Return true if there's a split before the closing bracket.""" + if style.Get( 'DEDENT_CLOSING_BRACKETS' ): + return True + if self.ends_in_comma: + return True + if not self.parameters: + return False + total_length = self.last_token.total_length + last_param = self.parameters[ -1 ].first_token + total_length -= last_param.total_length - len( last_param.value ) + return total_length + indent > style.Get( 'COLUMN_LIMIT' ) + + def Clone( self ): + clone = ParameterListState( + self.opening_bracket, self.has_split_before_first_param, + self.opening_column ) + clone.split_before_closing_bracket = self.split_before_closing_bracket + clone.parameters = [ param.Clone() for param in self.parameters ] + return clone + + def __repr__( self ): + return ( + '[opening_bracket::%s, has_split_before_first_param::%s, ' + 'opening_column::%d]' % ( + self.opening_bracket, self.has_split_before_first_param, + self.opening_column ) ) + + def __eq__( self, other ): + return hash( self ) == hash( other ) + + def __ne__( self, other ): + return not self == other + + def __hash__( self, *args, **kwargs ): + return hash( + ( + self.opening_bracket, self.has_split_before_first_param, + self.opening_column, ( hash( param ) for param in self.parameters ) ) ) + + +class Parameter( object ): + """A parameter in a parameter list. Attributes: first_token: (format_token.FormatToken) First token of parameter. @@ -200,33 +205,33 @@ class Parameter(object): has_default_value: (boolean) True if the parameter has a default value """ - def __init__(self, first_token, last_token): - self.first_token = first_token - self.last_token = last_token + def __init__( self, first_token, last_token ): + self.first_token = first_token + self.last_token = last_token - @property - @py3compat.lru_cache() - def has_default_value(self): - """Returns true if the parameter has a default value.""" - tok = self.first_token - while tok != self.last_token: - if subtypes.DEFAULT_OR_NAMED_ASSIGN in tok.subtypes: - return True - tok = tok.matching_bracket if tok.OpensScope() else tok.next_token - return False + @property + @py3compat.lru_cache() + def has_default_value( self ): + """Returns true if the parameter has a default value.""" + tok = self.first_token + while tok != self.last_token: + if subtypes.DEFAULT_OR_NAMED_ASSIGN in tok.subtypes: + return True + tok = tok.matching_bracket if tok.OpensScope() else tok.next_token + return False - def Clone(self): - return Parameter(self.first_token, self.last_token) + def Clone( self ): + return Parameter( self.first_token, self.last_token ) - def __repr__(self): - return '[first_token::%s, last_token:%s]' % (self.first_token, - self.last_token) + def __repr__( self ): + return '[first_token::%s, last_token:%s]' % ( + self.first_token, self.last_token ) - def __eq__(self, other): - return hash(self) == hash(other) + def __eq__( self, other ): + return hash( self ) == hash( other ) - def __ne__(self, other): - return not self == other + def __ne__( self, other ): + return not self == other - def __hash__(self, *args, **kwargs): - return hash((self.first_token, self.last_token)) + def __hash__( self, *args, **kwargs ): + return hash( ( self.first_token, self.last_token ) ) diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py index e4cb9788f..143a13c3e 100644 --- a/yapf/yapflib/py3compat.py +++ b/yapf/yapflib/py3compat.py @@ -18,75 +18,75 @@ import os import sys -PY3 = sys.version_info[0] >= 3 -PY36 = sys.version_info[0] >= 3 and sys.version_info[1] >= 6 -PY37 = sys.version_info[0] >= 3 and sys.version_info[1] >= 7 -PY38 = sys.version_info[0] >= 3 and sys.version_info[1] >= 8 +PY3 = sys.version_info[ 0 ] >= 3 +PY36 = sys.version_info[ 0 ] >= 3 and sys.version_info[ 1 ] >= 6 +PY37 = sys.version_info[ 0 ] >= 3 and sys.version_info[ 1 ] >= 7 +PY38 = sys.version_info[ 0 ] >= 3 and sys.version_info[ 1 ] >= 8 if PY3: - StringIO = io.StringIO - BytesIO = io.BytesIO + StringIO = io.StringIO + BytesIO = io.BytesIO - import codecs # noqa: F811 + import codecs # noqa: F811 - def open_with_encoding(filename, mode, encoding, newline=''): # pylint: disable=unused-argument # noqa - return codecs.open(filename, mode=mode, encoding=encoding) + def open_with_encoding( filename, mode, encoding, newline = '' ): # pylint: disable=unused-argument # noqa + return codecs.open( filename, mode = mode, encoding = encoding ) - import functools - lru_cache = functools.lru_cache + import functools + lru_cache = functools.lru_cache - range = range - ifilter = filter + range = range + ifilter = filter - def raw_input(): - wrapper = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8') - return wrapper.buffer.raw.readall().decode('utf-8') + def raw_input(): + wrapper = io.TextIOWrapper( sys.stdin.buffer, encoding = 'utf-8' ) + return wrapper.buffer.raw.readall().decode( 'utf-8' ) - import configparser + import configparser - # Mappings from strings to booleans (such as '1' to True, 'false' to False, - # etc.) - CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser.BOOLEAN_STATES + # Mappings from strings to booleans (such as '1' to True, 'false' to False, + # etc.) + CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser.BOOLEAN_STATES - import tokenize - detect_encoding = tokenize.detect_encoding - TokenInfo = tokenize.TokenInfo + import tokenize + detect_encoding = tokenize.detect_encoding + TokenInfo = tokenize.TokenInfo else: - import __builtin__ - import cStringIO - from itertools import ifilter + import __builtin__ + import cStringIO + from itertools import ifilter - StringIO = BytesIO = cStringIO.StringIO + StringIO = BytesIO = cStringIO.StringIO - open_with_encoding = io.open + open_with_encoding = io.open - # Python 2.7 doesn't have a native LRU cache, so do nothing. - def lru_cache(maxsize=128, typed=False): + # Python 2.7 doesn't have a native LRU cache, so do nothing. + def lru_cache( maxsize = 128, typed = False ): - def fake_wrapper(user_function): - return user_function + def fake_wrapper( user_function ): + return user_function - return fake_wrapper + return fake_wrapper - range = xrange # noqa: F821 + range = xrange # noqa: F821 - raw_input = raw_input + raw_input = raw_input - import ConfigParser as configparser - CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser._boolean_states # pylint: disable=protected-access # noqa + import ConfigParser as configparser + CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser._boolean_states # pylint: disable=protected-access # noqa - from lib2to3.pgen2 import tokenize - detect_encoding = tokenize.detect_encoding + from lib2to3.pgen2 import tokenize + detect_encoding = tokenize.detect_encoding - import collections + import collections - class TokenInfo( - collections.namedtuple('TokenInfo', 'type string start end line')): - pass + class TokenInfo( collections.namedtuple( 'TokenInfo', + 'type string start end line' ) ): + pass -def EncodeAndWriteToStdout(s, encoding='utf-8'): - """Encode the given string and emit to stdout. +def EncodeAndWriteToStdout( s, encoding = 'utf-8' ): + """Encode the given string and emit to stdout. The string may contain non-ascii characters. This is a problem when stdout is redirected, because then Python doesn't know the encoding and we may get a @@ -96,50 +96,50 @@ def EncodeAndWriteToStdout(s, encoding='utf-8'): s: (string) The string to encode. encoding: (string) The encoding of the string. """ - if PY3: - sys.stdout.buffer.write(s.encode(encoding)) - elif sys.platform == 'win32': - # On python 2 and Windows universal newline transformation will be in - # effect on stdout. Python 2 will not let us avoid the easily because - # it happens based on whether the file handle is opened in O_BINARY or - # O_TEXT state. However we can tell Windows itself to change the current - # mode, and python 2 will follow suit. However we must take care to change - # the mode on the actual external stdout not just the current sys.stdout - # which may have been monkey-patched inside the python environment. - import msvcrt # pylint: disable=g-import-not-at-top - if sys.__stdout__ is sys.stdout: - msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) - sys.stdout.write(s.encode(encoding)) - else: - sys.stdout.write(s.encode(encoding)) + if PY3: + sys.stdout.buffer.write( s.encode( encoding ) ) + elif sys.platform == 'win32': + # On python 2 and Windows universal newline transformation will be in + # effect on stdout. Python 2 will not let us avoid the easily because + # it happens based on whether the file handle is opened in O_BINARY or + # O_TEXT state. However we can tell Windows itself to change the current + # mode, and python 2 will follow suit. However we must take care to change + # the mode on the actual external stdout not just the current sys.stdout + # which may have been monkey-patched inside the python environment. + import msvcrt # pylint: disable=g-import-not-at-top + if sys.__stdout__ is sys.stdout: + msvcrt.setmode( sys.stdout.fileno(), os.O_BINARY ) + sys.stdout.write( s.encode( encoding ) ) + else: + sys.stdout.write( s.encode( encoding ) ) if PY3: - basestring = str - unicode = str # pylint: disable=redefined-builtin,invalid-name + basestring = str + unicode = str # pylint: disable=redefined-builtin,invalid-name else: - basestring = basestring + basestring = basestring - def unicode(s): # pylint: disable=invalid-name - """Force conversion of s to unicode.""" - return __builtin__.unicode(s, 'utf-8') + def unicode( s ): # pylint: disable=invalid-name + """Force conversion of s to unicode.""" + return __builtin__.unicode( s, 'utf-8' ) # In Python 3.2+, readfp is deprecated in favor of read_file, which doesn't # exist in Python 2 yet. To avoid deprecation warnings, subclass ConfigParser to # fix this - now read_file works across all Python versions we care about. -class ConfigParser(configparser.ConfigParser): - if not PY3: +class ConfigParser( configparser.ConfigParser ): + if not PY3: - def read_file(self, fp, source=None): - self.readfp(fp, filename=source) + def read_file( self, fp, source = None ): + self.readfp( fp, filename = source ) -def removeBOM(source): - """Remove any Byte-order-Mark bytes from the beginning of a file.""" - bom = codecs.BOM_UTF8 - if PY3: - bom = bom.decode('utf-8') - if source.startswith(bom): - return source[len(bom):] - return source +def removeBOM( source ): + """Remove any Byte-order-Mark bytes from the beginning of a file.""" + bom = codecs.BOM_UTF8 + if PY3: + bom = bom.decode( 'utf-8' ) + if source.startswith( bom ): + return source[ len( bom ): ] + return source diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 8f8a103f8..7e0fdf344 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -37,8 +37,8 @@ from yapf.yapflib import verifier -def Reformat(llines, verify=False, lines=None): - """Reformat the logical lines. +def Reformat( llines, verify = False, lines = None ): + """Reformat the logical lines. Arguments: llines: (list of logical_line.LogicalLine) Lines we want to format. @@ -49,144 +49,138 @@ def Reformat(llines, verify=False, lines=None): Returns: A string representing the reformatted code. """ - final_lines = [] - prev_line = None # The previous line. - indent_width = style.Get('INDENT_WIDTH') - - for lline in _SingleOrMergedLines(llines): - first_token = lline.first - _FormatFirstToken(first_token, lline.depth, prev_line, final_lines) - - indent_amt = indent_width * lline.depth - state = format_decision_state.FormatDecisionState(lline, indent_amt) - state.MoveStateToNextToken() - - if not lline.disable: - if lline.first.is_comment: - lline.first.value = lline.first.value.rstrip() - elif lline.last.is_comment: - lline.last.value = lline.last.value.rstrip() - if prev_line and prev_line.disable: - # Keep the vertical spacing between a disabled and enabled formatting - # region. - _RetainRequiredVerticalSpacingBetweenTokens(lline.first, prev_line.last, - lines) - if any(tok.is_comment for tok in lline.tokens): - _RetainVerticalSpacingBeforeComments(lline) - - if lline.disable or _LineHasContinuationMarkers(lline): - _RetainHorizontalSpacing(lline) - _RetainRequiredVerticalSpacing(lline, prev_line, lines) - _EmitLineUnformatted(state) - - elif (_LineContainsPylintDisableLineTooLong(lline) or - _LineContainsI18n(lline)): - # Don't modify vertical spacing, but fix any horizontal spacing issues. - _RetainRequiredVerticalSpacing(lline, prev_line, lines) - _EmitLineUnformatted(state) - - elif _CanPlaceOnSingleLine(lline) and not any(tok.must_break_before - for tok in lline.tokens): - # The logical line fits on one line. - while state.next_token: - state.AddTokenToState(newline=False, dry_run=False) - - elif not _AnalyzeSolutionSpace(state): - # Failsafe mode. If there isn't a solution to the line, then just emit - # it as is. - state = format_decision_state.FormatDecisionState(lline, indent_amt) - state.MoveStateToNextToken() - _RetainHorizontalSpacing(lline) - _RetainRequiredVerticalSpacing(lline, prev_line, None) - _EmitLineUnformatted(state) - - final_lines.append(lline) - prev_line = lline - - if style.Get('ALIGN_ASSIGNMENT'): - _AlignAssignment(final_lines) - if (style.Get('EACH_DICT_ENTRY_ON_SEPARATE_LINE') - and style.Get('ALIGN_DICT_COLON')): - _AlignDictColon(final_lines) - if style.Get('ALIGN_ARGUMENT_ASSIGNMENT'): - _AlignArgAssign(final_lines) - - _AlignTrailingComments(final_lines) - return _FormatFinalLines(final_lines, verify) - - -def _RetainHorizontalSpacing(line): - """Retain all horizontal spacing between tokens.""" - for tok in line.tokens: - tok.RetainHorizontalSpacing(line.first.column, line.depth) - - -def _RetainRequiredVerticalSpacing(cur_line, prev_line, lines): - """Retain all vertical spacing between lines.""" - prev_tok = None - if prev_line is not None: - prev_tok = prev_line.last - - if cur_line.disable: - # After the first token we are acting on a single line. So if it is - # disabled we must not reformat. - lines = set() - - for cur_tok in cur_line.tokens: - _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines) - prev_tok = cur_tok - - -def _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines): - """Retain vertical spacing between two tokens if not in editable range.""" - if prev_tok is None: - return - - if prev_tok.is_string: - prev_lineno = prev_tok.lineno + prev_tok.value.count('\n') - elif prev_tok.is_pseudo: - if not prev_tok.previous_token.is_multiline_string: - prev_lineno = prev_tok.previous_token.lineno + final_lines = [] + prev_line = None # The previous line. + indent_width = style.Get( 'INDENT_WIDTH' ) + + for lline in _SingleOrMergedLines( llines ): + first_token = lline.first + _FormatFirstToken( first_token, lline.depth, prev_line, final_lines ) + + indent_amt = indent_width * lline.depth + state = format_decision_state.FormatDecisionState( lline, indent_amt ) + state.MoveStateToNextToken() + + if not lline.disable: + if lline.first.is_comment: + lline.first.value = lline.first.value.rstrip() + elif lline.last.is_comment: + lline.last.value = lline.last.value.rstrip() + if prev_line and prev_line.disable: + # Keep the vertical spacing between a disabled and enabled formatting + # region. + _RetainRequiredVerticalSpacingBetweenTokens( + lline.first, prev_line.last, lines ) + if any( tok.is_comment for tok in lline.tokens ): + _RetainVerticalSpacingBeforeComments( lline ) + + if lline.disable or _LineHasContinuationMarkers( lline ): + _RetainHorizontalSpacing( lline ) + _RetainRequiredVerticalSpacing( lline, prev_line, lines ) + _EmitLineUnformatted( state ) + + elif ( _LineContainsPylintDisableLineTooLong( lline ) or + _LineContainsI18n( lline ) ): + # Don't modify vertical spacing, but fix any horizontal spacing issues. + _RetainRequiredVerticalSpacing( lline, prev_line, lines ) + _EmitLineUnformatted( state ) + + elif _CanPlaceOnSingleLine( lline ) and not any( tok.must_break_before + for tok in lline.tokens ): + # The logical line fits on one line. + while state.next_token: + state.AddTokenToState( newline = False, dry_run = False ) + + elif not _AnalyzeSolutionSpace( state ): + # Failsafe mode. If there isn't a solution to the line, then just emit + # it as is. + state = format_decision_state.FormatDecisionState( lline, indent_amt ) + state.MoveStateToNextToken() + _RetainHorizontalSpacing( lline ) + _RetainRequiredVerticalSpacing( lline, prev_line, None ) + _EmitLineUnformatted( state ) + + final_lines.append( lline ) + prev_line = lline + + if style.Get( 'ALIGN_ASSIGNMENT' ): + _AlignAssignment( final_lines ) + + _AlignTrailingComments( final_lines ) + return _FormatFinalLines( final_lines, verify ) + + +def _RetainHorizontalSpacing( line ): + """Retain all horizontal spacing between tokens.""" + for tok in line.tokens: + tok.RetainHorizontalSpacing( line.first.column, line.depth ) + + +def _RetainRequiredVerticalSpacing( cur_line, prev_line, lines ): + """Retain all vertical spacing between lines.""" + prev_tok = None + if prev_line is not None: + prev_tok = prev_line.last + + if cur_line.disable: + # After the first token we are acting on a single line. So if it is + # disabled we must not reformat. + lines = set() + + for cur_tok in cur_line.tokens: + _RetainRequiredVerticalSpacingBetweenTokens( cur_tok, prev_tok, lines ) + prev_tok = cur_tok + + +def _RetainRequiredVerticalSpacingBetweenTokens( cur_tok, prev_tok, lines ): + """Retain vertical spacing between two tokens if not in editable range.""" + if prev_tok is None: + return + + if prev_tok.is_string: + prev_lineno = prev_tok.lineno + prev_tok.value.count( '\n' ) + elif prev_tok.is_pseudo: + if not prev_tok.previous_token.is_multiline_string: + prev_lineno = prev_tok.previous_token.lineno + else: + prev_lineno = prev_tok.lineno else: - prev_lineno = prev_tok.lineno - else: - prev_lineno = prev_tok.lineno + prev_lineno = prev_tok.lineno - if cur_tok.is_comment: - cur_lineno = cur_tok.lineno - cur_tok.value.count('\n') - else: - cur_lineno = cur_tok.lineno + if cur_tok.is_comment: + cur_lineno = cur_tok.lineno - cur_tok.value.count( '\n' ) + else: + cur_lineno = cur_tok.lineno - if not prev_tok.is_comment and prev_tok.value.endswith('\\'): - prev_lineno += prev_tok.value.count('\n') + if not prev_tok.is_comment and prev_tok.value.endswith( '\\' ): + prev_lineno += prev_tok.value.count( '\n' ) - required_newlines = cur_lineno - prev_lineno - if cur_tok.is_comment and not prev_tok.is_comment: - # Don't adjust between a comment and non-comment. - pass - elif lines and lines.intersection(range(prev_lineno, cur_lineno + 1)): - desired_newlines = cur_tok.whitespace_prefix.count('\n') - whitespace_lines = range(prev_lineno + 1, cur_lineno) - deletable_lines = len(lines.intersection(whitespace_lines)) - required_newlines = max(required_newlines - deletable_lines, - desired_newlines) + required_newlines = cur_lineno - prev_lineno + if cur_tok.is_comment and not prev_tok.is_comment: + # Don't adjust between a comment and non-comment. + pass + elif lines and lines.intersection( range( prev_lineno, cur_lineno + 1 ) ): + desired_newlines = cur_tok.whitespace_prefix.count( '\n' ) + whitespace_lines = range( prev_lineno + 1, cur_lineno ) + deletable_lines = len( lines.intersection( whitespace_lines ) ) + required_newlines = max( required_newlines - deletable_lines, desired_newlines ) - cur_tok.AdjustNewlinesBefore(required_newlines) + cur_tok.AdjustNewlinesBefore( required_newlines ) -def _RetainVerticalSpacingBeforeComments(line): - """Retain vertical spacing before comments.""" - prev_token = None - for tok in line.tokens: - if tok.is_comment and prev_token: - if tok.lineno - tok.value.count('\n') - prev_token.lineno > 1: - tok.AdjustNewlinesBefore(ONE_BLANK_LINE) +def _RetainVerticalSpacingBeforeComments( line ): + """Retain vertical spacing before comments.""" + prev_token = None + for tok in line.tokens: + if tok.is_comment and prev_token: + if tok.lineno - tok.value.count( '\n' ) - prev_token.lineno > 1: + tok.AdjustNewlinesBefore( ONE_BLANK_LINE ) - prev_token = tok + prev_token = tok -def _EmitLineUnformatted(state): - """Emit the line without formatting. +def _EmitLineUnformatted( state ): + """Emit the line without formatting. The line contains code that if reformatted would break a non-syntactic convention. E.g., i18n comments and function calls are tightly bound by @@ -197,23 +191,23 @@ def _EmitLineUnformatted(state): state: (format_decision_state.FormatDecisionState) The format decision state. """ - while state.next_token: - previous_token = state.next_token.previous_token - previous_lineno = previous_token.lineno + while state.next_token: + previous_token = state.next_token.previous_token + previous_lineno = previous_token.lineno - if previous_token.is_multiline_string or previous_token.is_string: - previous_lineno += previous_token.value.count('\n') + if previous_token.is_multiline_string or previous_token.is_string: + previous_lineno += previous_token.value.count( '\n' ) - if previous_token.is_continuation: - newline = False - else: - newline = state.next_token.lineno > previous_lineno + if previous_token.is_continuation: + newline = False + else: + newline = state.next_token.lineno > previous_lineno - state.AddTokenToState(newline=newline, dry_run=False) + state.AddTokenToState( newline = newline, dry_run = False ) -def _LineContainsI18n(line): - """Return true if there are i18n comments or function calls in the line. +def _LineContainsI18n( line ): + """Return true if there are i18n comments or function calls in the line. I18n comments and pseudo-function calls are closely related. They cannot be moved apart without breaking i18n. @@ -224,33 +218,33 @@ def _LineContainsI18n(line): Returns: True if the line contains i18n comments or function calls. False otherwise. """ - if style.Get('I18N_COMMENT'): - for tok in line.tokens: - if tok.is_comment and re.match(style.Get('I18N_COMMENT'), tok.value): - # Contains an i18n comment. - return True - - if style.Get('I18N_FUNCTION_CALL'): - length = len(line.tokens) - for index in range(length - 1): - if (line.tokens[index + 1].value == '(' and - line.tokens[index].value in style.Get('I18N_FUNCTION_CALL')): - return True - return False + if style.Get( 'I18N_COMMENT' ): + for tok in line.tokens: + if tok.is_comment and re.match( style.Get( 'I18N_COMMENT' ), tok.value ): + # Contains an i18n comment. + return True + + if style.Get( 'I18N_FUNCTION_CALL' ): + length = len( line.tokens ) + for index in range( length - 1 ): + if ( line.tokens[ index + 1 ].value == '(' and + line.tokens[ index ].value in style.Get( 'I18N_FUNCTION_CALL' ) ): + return True + return False -def _LineContainsPylintDisableLineTooLong(line): - """Return true if there is a "pylint: disable=line-too-long" comment.""" - return re.search(r'\bpylint:\s+disable=line-too-long\b', line.last.value) +def _LineContainsPylintDisableLineTooLong( line ): + """Return true if there is a "pylint: disable=line-too-long" comment.""" + return re.search( r'\bpylint:\s+disable=line-too-long\b', line.last.value ) -def _LineHasContinuationMarkers(line): - """Return true if the line has continuation markers in it.""" - return any(tok.is_continuation for tok in line.tokens) +def _LineHasContinuationMarkers( line ): + """Return true if the line has continuation markers in it.""" + return any( tok.is_continuation for tok in line.tokens ) -def _CanPlaceOnSingleLine(line): - """Determine if the logical line can go on a single line. +def _CanPlaceOnSingleLine( line ): + """Determine if the logical line can go on a single line. Arguments: line: (logical_line.LogicalLine) The line currently being formatted. @@ -258,673 +252,359 @@ def _CanPlaceOnSingleLine(line): Returns: True if the line can or should be added to a single line. False otherwise. """ - token_names = [x.name for x in line.tokens] - if (style.Get('FORCE_MULTILINE_DICT') and 'LBRACE' in token_names): - return False - indent_amt = style.Get('INDENT_WIDTH') * line.depth - last = line.last - last_index = -1 - if (last.is_pylint_comment or last.is_pytype_comment or - last.is_copybara_comment): - last = last.previous_token - last_index = -2 - if last is None: - return True - return (last.total_length + indent_amt <= style.Get('COLUMN_LIMIT') and - not any(tok.is_comment for tok in line.tokens[:last_index])) - - -def _AlignTrailingComments(final_lines): - """Align trailing comments to the same column.""" - final_lines_index = 0 - while final_lines_index < len(final_lines): - line = final_lines[final_lines_index] - assert line.tokens - - processed_content = False - - for tok in line.tokens: - if (tok.is_comment and isinstance(tok.spaces_required_before, list) and - tok.value.startswith('#')): - # All trailing comments and comments that appear on a line by themselves - # in this block should be indented at the same level. The block is - # terminated by an empty line or EOF. Enumerate through each line in - # the block and calculate the max line length. Once complete, use the - # first col value greater than that value and create the necessary for - # each line accordingly. - all_pc_line_lengths = [] # All pre-comment line lengths - max_line_length = 0 - - while True: - # EOF - if final_lines_index + len(all_pc_line_lengths) == len(final_lines): - break - - this_line = final_lines[final_lines_index + len(all_pc_line_lengths)] - - # Blank line - note that content is preformatted so we don't need to - # worry about spaces/tabs; a blank line will always be '\n\n'. - assert this_line.tokens - if (all_pc_line_lengths and - this_line.tokens[0].formatted_whitespace_prefix.startswith('\n\n') - ): - break - - if this_line.disable: - all_pc_line_lengths.append([]) - continue - - # Calculate the length of each line in this logical line. - line_content = '' - pc_line_lengths = [] - - for line_tok in this_line.tokens: - whitespace_prefix = line_tok.formatted_whitespace_prefix - - newline_index = whitespace_prefix.rfind('\n') - if newline_index != -1: - max_line_length = max(max_line_length, len(line_content)) - line_content = '' - - whitespace_prefix = whitespace_prefix[newline_index + 1:] - - if line_tok.is_comment: - pc_line_lengths.append(len(line_content)) - else: - line_content += '{}{}'.format(whitespace_prefix, line_tok.value) - - if pc_line_lengths: - max_line_length = max(max_line_length, max(pc_line_lengths)) - - all_pc_line_lengths.append(pc_line_lengths) - - # Calculate the aligned column value - max_line_length += 2 - - aligned_col = None - for potential_col in tok.spaces_required_before: - if potential_col > max_line_length: - aligned_col = potential_col - break - - if aligned_col is None: - aligned_col = max_line_length - - # Update the comment token values based on the aligned values - for all_pc_line_lengths_index, pc_line_lengths in enumerate( - all_pc_line_lengths): - if not pc_line_lengths: - continue + token_names = [ x.name for x in line.tokens ] + if ( style.Get( 'FORCE_MULTILINE_DICT' ) and 'LBRACE' in token_names ): + return False + indent_amt = style.Get( 'INDENT_WIDTH' ) * line.depth + last = line.last + last_index = -1 + if ( last.is_pylint_comment or last.is_pytype_comment or last.is_copybara_comment ): + last = last.previous_token + last_index = -2 + if last is None: + return True + return ( + last.total_length + indent_amt <= style.Get( 'COLUMN_LIMIT' ) and + not any( tok.is_comment for tok in line.tokens[ : last_index ] ) ) + + +def _AlignTrailingComments( final_lines ): + """Align trailing comments to the same column.""" + final_lines_index = 0 + while final_lines_index < len( final_lines ): + line = final_lines[ final_lines_index ] + assert line.tokens + + processed_content = False + + for tok in line.tokens: + if ( tok.is_comment and isinstance( tok.spaces_required_before, list ) and + tok.value.startswith( '#' ) ): + # All trailing comments and comments that appear on a line by themselves + # in this block should be indented at the same level. The block is + # terminated by an empty line or EOF. Enumerate through each line in + # the block and calculate the max line length. Once complete, use the + # first col value greater than that value and create the necessary for + # each line accordingly. + all_pc_line_lengths = [] # All pre-comment line lengths + max_line_length = 0 + + while True: + # EOF + if final_lines_index + len( all_pc_line_lengths ) == len( + final_lines ): + break + + this_line = final_lines[ final_lines_index + + len( all_pc_line_lengths ) ] + + # Blank line - note that content is preformatted so we don't need to + # worry about spaces/tabs; a blank line will always be '\n\n'. + assert this_line.tokens + if ( all_pc_line_lengths and + this_line.tokens[ 0 ].formatted_whitespace_prefix.startswith( + '\n\n' ) ): + break + + if this_line.disable: + all_pc_line_lengths.append( [] ) + continue - this_line = final_lines[final_lines_index + all_pc_line_lengths_index] + # Calculate the length of each line in this logical line. + line_content = '' + pc_line_lengths = [] - pc_line_length_index = 0 - for line_tok in this_line.tokens: - if line_tok.is_comment: - assert pc_line_length_index < len(pc_line_lengths) - assert pc_line_lengths[pc_line_length_index] < aligned_col + for line_tok in this_line.tokens: + whitespace_prefix = line_tok.formatted_whitespace_prefix - # Note that there may be newlines embedded in the comments, so - # we need to apply a whitespace prefix to each line. - whitespace = ' ' * ( - aligned_col - pc_line_lengths[pc_line_length_index] - 1) - pc_line_length_index += 1 + newline_index = whitespace_prefix.rfind( '\n' ) + if newline_index != -1: + max_line_length = max( + max_line_length, len( line_content ) ) + line_content = '' - line_content = [] + whitespace_prefix = whitespace_prefix[ newline_index + 1 : ] - for comment_line_index, comment_line in enumerate( - line_tok.value.split('\n')): - line_content.append('{}{}'.format(whitespace, - comment_line.strip())) + if line_tok.is_comment: + pc_line_lengths.append( len( line_content ) ) + else: + line_content += '{}{}'.format( + whitespace_prefix, line_tok.value ) - if comment_line_index == 0: - whitespace = ' ' * (aligned_col - 1) + if pc_line_lengths: + max_line_length = max( max_line_length, max( pc_line_lengths ) ) - line_content = '\n'.join(line_content) + all_pc_line_lengths.append( pc_line_lengths ) - # Account for initial whitespace already slated for the - # beginning of the line. - existing_whitespace_prefix = \ - line_tok.formatted_whitespace_prefix.lstrip('\n') + # Calculate the aligned column value + max_line_length += 2 - if line_content.startswith(existing_whitespace_prefix): - line_content = line_content[len(existing_whitespace_prefix):] + aligned_col = None + for potential_col in tok.spaces_required_before: + if potential_col > max_line_length: + aligned_col = potential_col + break - line_tok.value = line_content + if aligned_col is None: + aligned_col = max_line_length - assert pc_line_length_index == len(pc_line_lengths) + # Update the comment token values based on the aligned values + for all_pc_line_lengths_index, pc_line_lengths in enumerate( + all_pc_line_lengths ): + if not pc_line_lengths: + continue - final_lines_index += len(all_pc_line_lengths) + this_line = final_lines[ final_lines_index + + all_pc_line_lengths_index ] - processed_content = True - break + pc_line_length_index = 0 + for line_tok in this_line.tokens: + if line_tok.is_comment: + assert pc_line_length_index < len( pc_line_lengths ) + assert pc_line_lengths[ pc_line_length_index ] < aligned_col - if not processed_content: - final_lines_index += 1 + # Note that there may be newlines embedded in the comments, so + # we need to apply a whitespace prefix to each line. + whitespace = ' ' * ( + aligned_col - pc_line_lengths[ pc_line_length_index ] - + 1 ) + pc_line_length_index += 1 + line_content = [] -def _AlignAssignment(final_lines): - """Align assignment operators and augmented assignment operators to the same column""" + for comment_line_index, comment_line in enumerate( + line_tok.value.split( '\n' ) ): + line_content.append( + '{}{}'.format( whitespace, comment_line.strip() ) ) - final_lines_index = 0 - while final_lines_index < len(final_lines): - line = final_lines[final_lines_index] + if comment_line_index == 0: + whitespace = ' ' * ( aligned_col - 1 ) - assert line.tokens - process_content = False + line_content = '\n'.join( line_content ) - for tok in line.tokens: - if tok.is_assign or tok.is_augassign: - # all pre assignment variable lengths in one block of lines - all_pa_variables_lengths = [] - max_variables_length = 0 - - while True: - # EOF - if final_lines_index + len(all_pa_variables_lengths) == len(final_lines): - break + # Account for initial whitespace already slated for the + # beginning of the line. + existing_whitespace_prefix = \ + line_tok.formatted_whitespace_prefix.lstrip('\n') - this_line_index = final_lines_index + len(all_pa_variables_lengths) - this_line = final_lines[this_line_index] + if line_content.startswith( existing_whitespace_prefix ): + line_content = line_content[ + len( existing_whitespace_prefix ): ] - next_line = None - if this_line_index < len(final_lines) - 1: - next_line = final_lines[final_lines_index + len(all_pa_variables_lengths) + 1 ] + line_tok.value = line_content - assert this_line.tokens, next_line.tokens + assert pc_line_length_index == len( pc_line_lengths ) - # align them differently when there is a blank line in between - if (all_pa_variables_lengths and - this_line.tokens[0].formatted_whitespace_prefix.startswith('\n\n') - ): - break + final_lines_index += len( all_pc_line_lengths ) - # if there is a standalone comment or keyword statement line - # or other lines without assignment in between, break - elif (all_pa_variables_lengths and - True not in [tok.is_assign or tok.is_augassign for tok in this_line.tokens]): - if this_line.tokens[0].is_comment: - if style.Get('NEW_ALIGNMENT_AFTER_COMMENTLINE'): + processed_content = True break - else: break - - if this_line.disable: - all_pa_variables_lengths.append([]) - continue - - variables_content = '' - pa_variables_lengths = [] - contain_object = False - line_tokens = this_line.tokens - # only one assignment expression is on each line - for index in range(len(line_tokens)): - line_tok = line_tokens[index] - - prefix = line_tok.formatted_whitespace_prefix - newline_index = prefix.rfind('\n') - if newline_index != -1: - variables_content = '' - prefix = prefix[newline_index + 1:] - - if line_tok.is_assign or line_tok.is_augassign: - next_toks = [line_tokens[i] for i in range(index+1, len(line_tokens))] - # if there is object(list/tuple/dict) with newline entries, break, - # update the alignment so far and start to calulate new alignment - for tok in next_toks: - if tok.value in ['(', '[', '{'] and tok.next_token: - if (tok.next_token.formatted_whitespace_prefix.startswith('\n') - or (tok.next_token.is_comment and tok.next_token.next_token.formatted_whitespace_prefix.startswith('\n'))): - pa_variables_lengths.append(len(variables_content)) - contain_object = True - break - if not contain_object: - if line_tok.is_assign: - pa_variables_lengths.append(len(variables_content)) - # if augassign, add the extra augmented part to the max length caculation - elif line_tok.is_augassign: - pa_variables_lengths.append(len(variables_content) + len(line_tok.value) - 1 ) - # don't add the tokens - # after the assignment operator - break - else: - variables_content += '{}{}'.format(prefix, line_tok.value) - - if pa_variables_lengths: - max_variables_length = max(max_variables_length, max(pa_variables_lengths)) - - all_pa_variables_lengths.append(pa_variables_lengths) - - # after saving this line's max variable length, - # we check if next line has the same depth as this line, - # if not, we don't want to calculate their max variable length together - # so we break the while loop, update alignment so far, and - # then go to next line that has '=' - if next_line: - if this_line.depth != next_line.depth: - break - # if this line contains objects with newline entries, - # start new block alignment - if contain_object: - break - - # if no update of max_length, just go to the next block - if max_variables_length == 0: continue - - max_variables_length += 2 - # Update the assignment token values based on the max variable length - for all_pa_variables_lengths_index, pa_variables_lengths in enumerate( - all_pa_variables_lengths): - if not pa_variables_lengths: - continue - this_line = final_lines[final_lines_index + all_pa_variables_lengths_index] - - # only the first assignment operator on each line - pa_variables_lengths_index = 0 - for line_tok in this_line.tokens: - if line_tok.is_assign or line_tok.is_augassign: - assert pa_variables_lengths[0] < max_variables_length - - if pa_variables_lengths_index < len(pa_variables_lengths): - whitespace = ' ' * ( - max_variables_length - pa_variables_lengths[0] - 1) - - assign_content = '{}{}'.format(whitespace, line_tok.value.strip()) - - existing_whitespace_prefix = \ - line_tok.formatted_whitespace_prefix.lstrip('\n') - - # in case the existing spaces are larger than padded spaces - if (len(whitespace) == 1 or len(whitespace) > 1 and - len(existing_whitespace_prefix)>len(whitespace)): - line_tok.whitespace_prefix = '' - elif assign_content.startswith(existing_whitespace_prefix): - assign_content = assign_content[len(existing_whitespace_prefix):] - - # update the assignment operator value - line_tok.value = assign_content - - pa_variables_lengths_index += 1 - - final_lines_index += len(all_pa_variables_lengths) - - process_content = True - break - - if not process_content: - final_lines_index += 1 - - -def _AlignArgAssign(final_lines): - """Align the assign operators in a argument list to the same column""" - """NOTE One argument list of one function is on one logical line! - But funtion calls/argument lists can be in argument list. - """ - final_lines_index = 0 - while final_lines_index < len(final_lines): - line = final_lines[final_lines_index] - if line.disable: - final_lines_index += 1 - continue - - assert line.tokens - process_content = False - - for tok in line.tokens: - if tok.is_argassign: + if not processed_content: + final_lines_index += 1 - this_line = line - line_tokens = this_line.tokens - for open_index in range(len(line_tokens)): - line_tok = line_tokens[open_index] +def _AlignAssignment( final_lines ): + """Align assignment operators and augmented assignment operators to the same column""" + + final_lines_index = 0 + while final_lines_index < len( final_lines ): + line = final_lines[ final_lines_index ] + + assert line.tokens + process_content = False + + for tok in line.tokens: + if tok.is_assign or tok.is_augassign: + # all pre assignment variable lengths in one block of lines + all_pa_variables_lengths = [] + max_variables_length = 0 + + while True: + # EOF + if final_lines_index + len( all_pa_variables_lengths ) == len( + final_lines ): + break + + this_line_index = final_lines_index + len( + all_pa_variables_lengths ) + this_line = final_lines[ this_line_index ] + + next_line = None + if this_line_index < len( final_lines ) - 1: + next_line = final_lines[ final_lines_index + + len( all_pa_variables_lengths ) + 1 ] + + assert this_line.tokens, next_line.tokens + + # align them differently when there is a blank line in between + if ( all_pa_variables_lengths and + this_line.tokens[ 0 ].formatted_whitespace_prefix.startswith( + '\n\n' ) ): + break + + # if there is a standalone comment or keyword statement line + # or other lines without assignment in between, break + elif ( all_pa_variables_lengths and + True not in [ tok.is_assign or tok.is_augassign + for tok in this_line.tokens ] ): + if this_line.tokens[ 0 ].is_comment: + if style.Get( 'NEW_ALIGNMENT_AFTER_COMMENTLINE' ): + break + else: + break + + if this_line.disable: + all_pa_variables_lengths.append( [] ) + continue - if (line_tok.value == '(' and not line_tok.is_pseudo - and line_tok.next_token.formatted_whitespace_prefix.startswith('\n')): - index = open_index - # skip the comments in the beginning - index += 1 - line_tok = line_tokens[index] - while not line_tok.is_argname_start and index < len(line_tokens)-1: - index += 1 - line_tok = line_tokens[index] - - # check if the argstart is on newline - if line_tok.is_argname_start and line_tok.formatted_whitespace_prefix.startswith('\n'): - first_arg_index = index - first_arg_column = len(line_tok.formatted_whitespace_prefix.lstrip('\n')) - - closing = False - all_arg_name_lengths = [] - arg_name_lengths = [] - name_content = '' - arg_column = first_arg_column - - # start with the first argument - # that has nextline prefix - while not closing: - # if there is a comment in between, save, reset and continue to calulate new alignment - if (style.Get('NEW_ALIGNMENT_AFTER_COMMENTLINE') - and arg_name_lengths and line_tok.is_comment - and line_tok.formatted_whitespace_prefix.startswith('\n')): - all_arg_name_lengths.append(arg_name_lengths) - arg_name_lengths = [] - index += 1 - line_tok = line_tokens[index] - continue - - prefix = line_tok.formatted_whitespace_prefix - newline_index = prefix.rfind('\n') - - if newline_index != -1: - if line_tok.is_argname_start: - name_content = '' - prefix = prefix[newline_index + 1:] - arg_column = len(prefix) - # if a typed arg name is so long - # that there are newlines inside - # only calulate the last line arg_name that has the assignment - elif line_tok.is_argname: - name_content = '' - prefix = prefix[newline_index + 1:] - # if any argument not on newline - elif line_tok.is_argname_start: - name_content = '' - arg_column = line_tok.column - # in case they are formatted into one line in final_line - # but are put in separated lines in original codes - if arg_column == first_arg_column: - arg_column = line_tok.formatted_whitespace_prefix - # on the same argument level - if (line_tok.is_argname_start and arg_name_lengths - and arg_column==first_arg_column): - argname_end = line_tok - while argname_end.is_argname: - argname_end = argname_end.next_token - # argument without assignment in between - if not argname_end.is_argassign: - all_arg_name_lengths.append(arg_name_lengths) - arg_name_lengths = [] - index += 1 - line_tok = line_tokens[index] + variables_content = '' + pa_variables_lengths = [] + contain_object = False + line_tokens = this_line.tokens + # only one assignment expression is on each line + for index in range( len( line_tokens ) ): + line_tok = line_tokens[ index ] + + prefix = line_tok.formatted_whitespace_prefix + newline_index = prefix.rfind( '\n' ) + if newline_index != -1: + variables_content = '' + prefix = prefix[ newline_index + 1 : ] + + if line_tok.is_assign or line_tok.is_augassign: + next_toks = [ + line_tokens[ i ] + for i in range( index + 1, len( line_tokens ) ) + ] + # if there is object(list/tuple/dict) with newline entries, break, + # update the alignment so far and start to calulate new alignment + for tok in next_toks: + if tok.value in [ '(', '[', '{' ] and tok.next_token: + if ( + tok.next_token.formatted_whitespace_prefix + .startswith( '\n' ) or + ( tok.next_token.is_comment and + tok.next_token.next_token. + formatted_whitespace_prefix.startswith( '\n' ) + ) ): + pa_variables_lengths.append( + len( variables_content ) ) + contain_object = True + break + if not contain_object: + if line_tok.is_assign: + pa_variables_lengths.append( + len( variables_content ) ) + # if augassign, add the extra augmented part to the max length caculation + elif line_tok.is_augassign: + pa_variables_lengths.append( + len( variables_content ) + + len( line_tok.value ) - 1 ) + # don't add the tokens + # after the assignment operator + break + else: + variables_content += '{}{}'.format( prefix, line_tok.value ) + + if pa_variables_lengths: + max_variables_length = max( + max_variables_length, max( pa_variables_lengths ) ) + + all_pa_variables_lengths.append( pa_variables_lengths ) + + # after saving this line's max variable length, + # we check if next line has the same depth as this line, + # if not, we don't want to calculate their max variable length together + # so we break the while loop, update alignment so far, and + # then go to next line that has '=' + if next_line: + if this_line.depth != next_line.depth: + break + # if this line contains objects with newline entries, + # start new block alignment + if contain_object: + break + + # if no update of max_length, just go to the next block + if max_variables_length == 0: continue - if line_tok.is_argassign and arg_column == first_arg_column: - arg_name_lengths.append(len(name_content)) - elif line_tok.is_argname and arg_column == first_arg_column: - name_content += '{}{}'.format(prefix, line_tok.value) - # add up all token values before the arg assign operator + max_variables_length += 2 - index += 1 - if index < len(line_tokens): - line_tok = line_tokens[index] - # when the matching closing bracket is never found - # due to edge cases where the closing bracket - # is not indented or dedented - else: - all_arg_name_lengths.append(arg_name_lengths) - break - - # if there is a new object(list/tuple/dict) with its entries on newlines, - # save, reset and continue to calulate new alignment - if (line_tok.value in ['(', '[','{'] and line_tok.next_token - and line_tok.next_token.formatted_whitespace_prefix.startswith('\n')): - if arg_name_lengths: - all_arg_name_lengths.append(arg_name_lengths) - arg_name_lengths = [] - index += 1 - line_tok = line_tokens[index] - continue - - if line_tok.value == ')'and not line_tok.is_pseudo: - if line_tok.formatted_whitespace_prefix.startswith('\n'): - close_column = len(line_tok.formatted_whitespace_prefix.lstrip('\n')) - else: close_column = line_tok.column - if close_column < first_arg_column: - if arg_name_lengths: - all_arg_name_lengths.append(arg_name_lengths) - closing = True - - # update the alignment once one full arg list is processed - if all_arg_name_lengths: - # if argument list with only the first argument on newline - if len(all_arg_name_lengths) == 1 and len(all_arg_name_lengths[0]) == 1: - continue - max_name_length = 0 - all_arg_name_lengths_index = 0 - arg_name_lengths = all_arg_name_lengths[all_arg_name_lengths_index] - max_name_length = max(arg_name_lengths or [0]) + 2 - arg_lengths_index = 0 - for token in line_tokens[first_arg_index:index]: - if token.is_argassign: - name_token = token.previous_token - while name_token.is_argname and not name_token.is_argname_start: - name_token = name_token.previous_token - name_column = len(name_token.formatted_whitespace_prefix.lstrip('\n')) - if name_column == first_arg_column: - if all_arg_name_lengths_index < len(all_arg_name_lengths): - if arg_lengths_index == len(arg_name_lengths): - all_arg_name_lengths_index += 1 - arg_name_lengths = all_arg_name_lengths[all_arg_name_lengths_index] - max_name_length = max(arg_name_lengths or [0]) + 2 - arg_lengths_index = 0 - - if arg_lengths_index < len(arg_name_lengths): - - assert arg_name_lengths[arg_lengths_index] < max_name_length - - padded_spaces = ' ' * ( - max_name_length - arg_name_lengths[arg_lengths_index] - 1) - arg_lengths_index += 1 - - assign_content = '{}{}'.format(padded_spaces, token.value.strip()) - existing_whitespace_prefix = \ - token.formatted_whitespace_prefix.lstrip('\n') - - # in case the existing spaces are larger than padded spaces - if (len(padded_spaces)==1 or len(padded_spaces)>1 and - len(existing_whitespace_prefix)>len(padded_spaces)): - token.whitespace_prefix = '' - elif assign_content.startswith(existing_whitespace_prefix): - assign_content = assign_content[len(existing_whitespace_prefix):] - - token.value = assign_content - - final_lines_index += 1 - process_content = True - break - - if not process_content: - final_lines_index += 1 - - -def _AlignDictColon(final_lines): - """Align colons in a dict to the same column""" - """NOTE One (nested) dict/list is one logical line!""" - final_lines_index = 0 - while final_lines_index < len(final_lines): - line = final_lines[final_lines_index] - if line.disable: - final_lines_index += 1 - continue - - assert line.tokens - process_content = False + # Update the assignment token values based on the max variable length + for all_pa_variables_lengths_index, pa_variables_lengths in enumerate( + all_pa_variables_lengths ): + if not pa_variables_lengths: + continue + this_line = final_lines[ final_lines_index + + all_pa_variables_lengths_index ] - for tok in line.tokens: - # make sure each dict entry on separate lines and - # the dict has more than one entry - if (tok.is_dict_key and tok.formatted_whitespace_prefix.startswith('\n') and - not tok.is_comment): + # only the first assignment operator on each line + pa_variables_lengths_index = 0 + for line_tok in this_line.tokens: + if line_tok.is_assign or line_tok.is_augassign: + assert pa_variables_lengths[ 0 ] < max_variables_length - this_line = line + if pa_variables_lengths_index < len( pa_variables_lengths ): + whitespace = ' ' * ( + max_variables_length - pa_variables_lengths[ 0 ] - + 1 ) - line_tokens = this_line.tokens - for open_index in range(len(line_tokens)): - line_tok = line_tokens[open_index] + assign_content = '{}{}'.format( + whitespace, line_tok.value.strip() ) - # check each time if the detected dict is the dict we aim for - if line_tok.value == '{' and line_tok.next_token.formatted_whitespace_prefix.startswith('\n'): - index = open_index - # skip the comments in the beginning - index += 1 - line_tok = line_tokens[index] - while not line_tok.is_dict_key and index < len(line_tokens)-1: - index += 1 - line_tok = line_tokens[index] - # in case empty dict, check if dict key again - if line_tok.is_dict_key and line_tok.formatted_whitespace_prefix.startswith('\n'): - closing = False # the closing bracket in dict '}'. - keys_content = '' - all_dict_keys_lengths = [] - dict_keys_lengths = [] - - # record the column number of the first key - first_key_column = len(line_tok.formatted_whitespace_prefix.lstrip('\n')) - key_column = first_key_column - - # while not closing: - while not closing: - prefix = line_tok.formatted_whitespace_prefix - newline = prefix.startswith('\n') - if newline: - # if comments inbetween, save, reset and continue to caluclate new alignment - if (style.Get('NEW_ALIGNMENT_AFTER_COMMENTLINE') - and dict_keys_lengths and line_tok.is_comment): - all_dict_keys_lengths.append(dict_keys_lengths) - dict_keys_lengths =[] - index += 1 - line_tok = line_tokens[index] - continue - if line_tok.is_dict_key_start: - keys_content = '' - prefix = prefix.lstrip('\n') - key_column = len(prefix) - # if the dict key is so long that it has multi-lines - # only caculate the last line that has the colon - elif line_tok.is_dict_key: - keys_content = '' - prefix = prefix.lstrip('\n') - elif line_tok.is_dict_key_start: - key_column = line_tok.column - - if line_tok.is_dict_colon and key_column == first_key_column: - dict_keys_lengths.append(len(keys_content)) - elif line_tok.is_dict_key and key_column == first_key_column: - keys_content += '{}{}'.format(prefix, line_tok.value) - - index += 1 - if index < len(line_tokens): - line_tok = line_tokens[index] - # when the matching closing bracket is never found - # due to edge cases where the closing bracket - # is not indented or dedented, e.g. ']}', with another bracket before - else: - all_dict_keys_lengths.append(dict_keys_lengths) - break - - # if there is new objects(list/tuple/dict) with its entries on newlines, - # or a function call with any of its arguments on newlines, - # save, reset and continue to calulate new alignment - if (line_tok.value in ['(', '[', '{'] and not line_tok.is_pseudo and line_tok.next_token - and line_tok.next_token.formatted_whitespace_prefix.startswith('\n')): - if dict_keys_lengths: - all_dict_keys_lengths.append(dict_keys_lengths) - dict_keys_lengths = [] - index += 1 - line_tok = line_tokens[index] - continue - # the matching closing bracket is either same indented or dedented - # accordingly to previous level's indentation - # the first found, immediately break the while loop - if line_tok.value == '}': - if line_tok.formatted_whitespace_prefix.startswith('\n'): - close_column = len(line_tok.formatted_whitespace_prefix.lstrip('\n')) - else: close_column = line_tok.column - if close_column < first_key_column: - if dict_keys_lengths: - all_dict_keys_lengths.append(dict_keys_lengths) - closing = True - - # update the alignment once one dict is processed - if all_dict_keys_lengths: - max_keys_length = 0 - all_dict_keys_lengths_index = 0 - dict_keys_lengths = all_dict_keys_lengths[all_dict_keys_lengths_index] - max_keys_length = max(dict_keys_lengths or [0]) + 2 - keys_lengths_index = 0 - for token in line_tokens[open_index+1:index]: - if token.is_dict_colon: - # check if the key has multiple tokens and - # get the first key token in this key - key_token = token.previous_token - while key_token.is_dict_key and not key_token.is_dict_key_start: - key_token = key_token.previous_token - key_column = len(key_token.formatted_whitespace_prefix.lstrip('\n')) - - if key_column == first_key_column: - - if keys_lengths_index == len(dict_keys_lengths): - all_dict_keys_lengths_index += 1 - dict_keys_lengths = all_dict_keys_lengths[all_dict_keys_lengths_index] - max_keys_length = max(dict_keys_lengths or [0]) + 2 - keys_lengths_index = 0 - - if keys_lengths_index < len(dict_keys_lengths): - assert dict_keys_lengths[keys_lengths_index] < max_keys_length - - padded_spaces = ' ' * ( - max_keys_length - dict_keys_lengths[keys_lengths_index] - 1) - keys_lengths_index += 1 - #NOTE if the existing whitespaces are larger than padded spaces - existing_whitespace_prefix = \ - token.formatted_whitespace_prefix.lstrip('\n') - colon_content = '{}{}'.format(padded_spaces, token.value.strip()) + existing_whitespace_prefix = \ + line_tok.formatted_whitespace_prefix.lstrip('\n') - # in case the existing spaces are larger than the paddes spaces - if (len(padded_spaces) == 1 or len(padded_spaces) > 1 - and len(existing_whitespace_prefix) >= len(padded_spaces)): - # remove the existing spaces - token.whitespace_prefix = '' - elif colon_content.startswith(existing_whitespace_prefix): - colon_content = colon_content[len(existing_whitespace_prefix):] + # in case the existing spaces are larger than padded spaces + if ( len( whitespace ) == 1 or len( whitespace ) > 1 and + len( existing_whitespace_prefix ) + > len( whitespace ) ): + line_tok.whitespace_prefix = '' + elif assign_content.startswith( + existing_whitespace_prefix ): + assign_content = assign_content[ + len( existing_whitespace_prefix ): ] - token.value = colon_content + # update the assignment operator value + line_tok.value = assign_content - final_lines_index += 1 + pa_variables_lengths_index += 1 - process_content = True - break + final_lines_index += len( all_pa_variables_lengths ) - if not process_content: - final_lines_index += 1 + process_content = True + break + if not process_content: + final_lines_index += 1 -def _FormatFinalLines(final_lines, verify): - """Compose the final output from the finalized lines.""" - formatted_code = [] - for line in final_lines: - formatted_line = [] - for tok in line.tokens: - if not tok.is_pseudo: - formatted_line.append(tok.formatted_whitespace_prefix) - formatted_line.append(tok.value) - elif (not tok.next_token.whitespace_prefix.startswith('\n') and - not tok.next_token.whitespace_prefix.startswith(' ')): - if (tok.previous_token.value == ':' or - tok.next_token.value not in ',}])'): - formatted_line.append(' ') +def _FormatFinalLines( final_lines, verify ): + """Compose the final output from the finalized lines.""" + formatted_code = [] + for line in final_lines: + formatted_line = [] + for tok in line.tokens: + if not tok.is_pseudo: + formatted_line.append( tok.formatted_whitespace_prefix ) + formatted_line.append( tok.value ) + elif ( not tok.next_token.whitespace_prefix.startswith( '\n' ) and + not tok.next_token.whitespace_prefix.startswith( ' ' ) ): + if ( tok.previous_token.value == ':' or + tok.next_token.value not in ',}])' ): + formatted_line.append( ' ' ) - formatted_code.append(''.join(formatted_line)) - if verify: - verifier.VerifyCode(formatted_code[-1]) + formatted_code.append( ''.join( formatted_line ) ) + if verify: + verifier.VerifyCode( formatted_code[ -1 ] ) - return ''.join(formatted_code) + '\n' + return ''.join( formatted_code ) + '\n' -class _StateNode(object): - """An edge in the solution space from 'previous.state' to 'state'. +class _StateNode( object ): + """An edge in the solution space from 'previous.state' to 'state'. Attributes: state: (format_decision_state.FormatDecisionState) The format decision state @@ -934,32 +614,31 @@ class _StateNode(object): previous: (_StateNode) The previous state node in the graph. """ - # TODO(morbo): Add a '__cmp__' method. + # TODO(morbo): Add a '__cmp__' method. - def __init__(self, state, newline, previous): - self.state = state.Clone() - self.newline = newline - self.previous = previous + def __init__( self, state, newline, previous ): + self.state = state.Clone() + self.newline = newline + self.previous = previous - def __repr__(self): # pragma: no cover - return 'StateNode(state=[\n{0}\n], newline={1})'.format( - self.state, self.newline) + def __repr__( self ): # pragma: no cover + return 'StateNode(state=[\n{0}\n], newline={1})'.format( + self.state, self.newline ) # A tuple of (penalty, count) that is used to prioritize the BFS. In case of # equal penalties, we prefer states that were inserted first. During state # generation, we make sure that we insert states first that break the line as # late as possible. -_OrderedPenalty = collections.namedtuple('OrderedPenalty', ['penalty', 'count']) +_OrderedPenalty = collections.namedtuple( 'OrderedPenalty', [ 'penalty', 'count' ] ) # An item in the prioritized BFS search queue. The 'StateNode's 'state' has # the given '_OrderedPenalty'. -_QueueItem = collections.namedtuple('QueueItem', - ['ordered_penalty', 'state_node']) +_QueueItem = collections.namedtuple( 'QueueItem', [ 'ordered_penalty', 'state_node' ] ) -def _AnalyzeSolutionSpace(initial_state): - """Analyze the entire solution space starting from initial_state. +def _AnalyzeSolutionSpace( initial_state ): + """Analyze the entire solution space starting from initial_state. This implements a variant of Dijkstra's algorithm on the graph that spans the solution space (LineStates are the nodes). The algorithm tries to find @@ -973,49 +652,49 @@ def _AnalyzeSolutionSpace(initial_state): Returns: True if a formatting solution was found. False otherwise. """ - count = 0 - seen = set() - p_queue = [] - - # Insert start element. - node = _StateNode(initial_state, False, None) - heapq.heappush(p_queue, _QueueItem(_OrderedPenalty(0, count), node)) - - count += 1 - while p_queue: - item = p_queue[0] - penalty = item.ordered_penalty.penalty - node = item.state_node - if not node.state.next_token: - break - heapq.heappop(p_queue) - - if count > 10000: - node.state.ignore_stack_for_comparison = True - - # Unconditionally add the state and check if it was present to avoid having - # to hash it twice in the common case (state hashing is expensive). - before_seen_count = len(seen) - seen.add(node.state) - # If seen didn't change size, the state was already present. - if before_seen_count == len(seen): - continue - - # FIXME(morbo): Add a 'decision' element? - - count = _AddNextStateToQueue(penalty, node, False, count, p_queue) - count = _AddNextStateToQueue(penalty, node, True, count, p_queue) - - if not p_queue: - # We weren't able to find a solution. Do nothing. - return False + count = 0 + seen = set() + p_queue = [] + + # Insert start element. + node = _StateNode( initial_state, False, None ) + heapq.heappush( p_queue, _QueueItem( _OrderedPenalty( 0, count ), node ) ) + + count += 1 + while p_queue: + item = p_queue[ 0 ] + penalty = item.ordered_penalty.penalty + node = item.state_node + if not node.state.next_token: + break + heapq.heappop( p_queue ) + + if count > 10000: + node.state.ignore_stack_for_comparison = True + + # Unconditionally add the state and check if it was present to avoid having + # to hash it twice in the common case (state hashing is expensive). + before_seen_count = len( seen ) + seen.add( node.state ) + # If seen didn't change size, the state was already present. + if before_seen_count == len( seen ): + continue + + # FIXME(morbo): Add a 'decision' element? - _ReconstructPath(initial_state, heapq.heappop(p_queue).state_node) - return True + count = _AddNextStateToQueue( penalty, node, False, count, p_queue ) + count = _AddNextStateToQueue( penalty, node, True, count, p_queue ) + if not p_queue: + # We weren't able to find a solution. Do nothing. + return False + + _ReconstructPath( initial_state, heapq.heappop( p_queue ).state_node ) + return True -def _AddNextStateToQueue(penalty, previous_node, newline, count, p_queue): - """Add the following state to the analysis queue. + +def _AddNextStateToQueue( penalty, previous_node, newline, count, p_queue ): + """Add the following state to the analysis queue. Assume the current state is 'previous_node' and has been reached with a penalty of 'penalty'. Insert a line break if 'newline' is True. @@ -1031,23 +710,23 @@ def _AddNextStateToQueue(penalty, previous_node, newline, count, p_queue): Returns: The updated number of elements in the queue. """ - must_split = previous_node.state.MustSplit() - if newline and not previous_node.state.CanSplit(must_split): - # Don't add a newline if the token cannot be split. - return count - if not newline and must_split: - # Don't add a token we must split but where we aren't splitting. - return count + must_split = previous_node.state.MustSplit() + if newline and not previous_node.state.CanSplit( must_split ): + # Don't add a newline if the token cannot be split. + return count + if not newline and must_split: + # Don't add a token we must split but where we aren't splitting. + return count - node = _StateNode(previous_node.state, newline, previous_node) - penalty += node.state.AddTokenToState( - newline=newline, dry_run=True, must_split=must_split) - heapq.heappush(p_queue, _QueueItem(_OrderedPenalty(penalty, count), node)) - return count + 1 + node = _StateNode( previous_node.state, newline, previous_node ) + penalty += node.state.AddTokenToState( + newline = newline, dry_run = True, must_split = must_split ) + heapq.heappush( p_queue, _QueueItem( _OrderedPenalty( penalty, count ), node ) ) + return count + 1 -def _ReconstructPath(initial_state, current): - """Reconstruct the path through the queue with lowest penalty. +def _ReconstructPath( initial_state, current ): + """Reconstruct the path through the queue with lowest penalty. Arguments: initial_state: (format_decision_state.FormatDecisionState) The initial state @@ -1055,21 +734,21 @@ def _ReconstructPath(initial_state, current): current: (_StateNode) The node in the decision graph that is the end point of the path with the least penalty. """ - path = collections.deque() + path = collections.deque() - while current.previous: - path.appendleft(current) - current = current.previous + while current.previous: + path.appendleft( current ) + current = current.previous - for node in path: - initial_state.AddTokenToState(newline=node.newline, dry_run=False) + for node in path: + initial_state.AddTokenToState( newline = node.newline, dry_run = False ) NESTED_DEPTH = [] -def _FormatFirstToken(first_token, indent_depth, prev_line, final_lines): - """Format the first token in the logical line. +def _FormatFirstToken( first_token, indent_depth, prev_line, final_lines ): + """Format the first token in the logical line. Add a newline and the required indent before the first token of the logical line. @@ -1082,39 +761,38 @@ def _FormatFirstToken(first_token, indent_depth, prev_line, final_lines): final_lines: (list of logical_line.LogicalLine) The logical lines that have already been processed. """ - global NESTED_DEPTH - while NESTED_DEPTH and NESTED_DEPTH[-1] > indent_depth: - NESTED_DEPTH.pop() - - first_nested = False - if _IsClassOrDef(first_token): - if not NESTED_DEPTH: - NESTED_DEPTH = [indent_depth] - elif NESTED_DEPTH[-1] < indent_depth: - first_nested = True - NESTED_DEPTH.append(indent_depth) - - first_token.AddWhitespacePrefix( - _CalculateNumberOfNewlines(first_token, indent_depth, prev_line, - final_lines, first_nested), - indent_level=indent_depth) - - -NO_BLANK_LINES = 1 -ONE_BLANK_LINE = 2 + global NESTED_DEPTH + while NESTED_DEPTH and NESTED_DEPTH[ -1 ] > indent_depth: + NESTED_DEPTH.pop() + + first_nested = False + if _IsClassOrDef( first_token ): + if not NESTED_DEPTH: + NESTED_DEPTH = [ indent_depth ] + elif NESTED_DEPTH[ -1 ] < indent_depth: + first_nested = True + NESTED_DEPTH.append( indent_depth ) + + first_token.AddWhitespacePrefix( + _CalculateNumberOfNewlines( + first_token, indent_depth, prev_line, final_lines, first_nested ), + indent_level = indent_depth ) + + +NO_BLANK_LINES = 1 +ONE_BLANK_LINE = 2 TWO_BLANK_LINES = 3 -def _IsClassOrDef(tok): - if tok.value in {'class', 'def', '@'}: - return True - return (tok.next_token and tok.value == 'async' and - tok.next_token.value == 'def') +def _IsClassOrDef( tok ): + if tok.value in { 'class', 'def', '@' }: + return True + return ( tok.next_token and tok.value == 'async' and tok.next_token.value == 'def' ) -def _CalculateNumberOfNewlines(first_token, indent_depth, prev_line, - final_lines, first_nested): - """Calculate the number of newlines we need to add. +def _CalculateNumberOfNewlines( + first_token, indent_depth, prev_line, final_lines, first_nested ): + """Calculate the number of newlines we need to add. Arguments: first_token: (format_token.FormatToken) The first token in the logical @@ -1129,102 +807,103 @@ def _CalculateNumberOfNewlines(first_token, indent_depth, prev_line, Returns: The number of newlines needed before the first token. """ - # TODO(morbo): Special handling for imports. - # TODO(morbo): Create a knob that can tune these. - if prev_line is None: - # The first line in the file. Don't add blank lines. - # FIXME(morbo): Is this correct? - if first_token.newlines is not None: - first_token.newlines = None - return 0 - - if first_token.is_docstring: - if (prev_line.first.value == 'class' and - style.Get('BLANK_LINE_BEFORE_CLASS_DOCSTRING')): - # Enforce a blank line before a class's docstring. - return ONE_BLANK_LINE - elif (prev_line.first.value.startswith('#') and - style.Get('BLANK_LINE_BEFORE_MODULE_DOCSTRING')): - # Enforce a blank line before a module's docstring. - return ONE_BLANK_LINE - # The docstring shouldn't have a newline before it. - return NO_BLANK_LINES - - if first_token.is_name and not indent_depth: - if prev_line.first.value in {'from', 'import'}: - # Support custom number of blank lines between top-level imports and - # variable definitions. - return 1 + style.Get( - 'BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES') - - prev_last_token = prev_line.last - if prev_last_token.is_docstring: - if (not indent_depth and first_token.value in {'class', 'def', 'async'}): - # Separate a class or function from the module-level docstring with - # appropriate number of blank lines. - return 1 + style.Get('BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION') - if (first_nested and - not style.Get('BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF') and - _IsClassOrDef(first_token)): - first_token.newlines = None - return NO_BLANK_LINES - if _NoBlankLinesBeforeCurrentToken(prev_last_token.value, first_token, - prev_last_token): - return NO_BLANK_LINES - else: - return ONE_BLANK_LINE - - if _IsClassOrDef(first_token): - # TODO(morbo): This can go once the blank line calculator is more - # sophisticated. - if not indent_depth: - # This is a top-level class or function. - is_inline_comment = prev_last_token.whitespace_prefix.count('\n') == 0 - if (not prev_line.disable and prev_last_token.is_comment and - not is_inline_comment): - # This token follows a non-inline comment. - if _NoBlankLinesBeforeCurrentToken(prev_last_token.value, first_token, - prev_last_token): - # Assume that the comment is "attached" to the current line. - # Therefore, we want two blank lines before the comment. - index = len(final_lines) - 1 - while index > 0: - if not final_lines[index - 1].is_comment: - break - index -= 1 - if final_lines[index - 1].first.value == '@': - final_lines[index].first.AdjustNewlinesBefore(NO_BLANK_LINES) - else: - prev_last_token.AdjustNewlinesBefore( - 1 + style.Get('BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION')) - if first_token.newlines is not None: + # TODO(morbo): Special handling for imports. + # TODO(morbo): Create a knob that can tune these. + if prev_line is None: + # The first line in the file. Don't add blank lines. + # FIXME(morbo): Is this correct? + if first_token.newlines is not None: first_token.newlines = None - return NO_BLANK_LINES - elif _IsClassOrDef(prev_line.first): - if first_nested and not style.Get( - 'BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'): - first_token.newlines = None + return 0 + + if first_token.is_docstring: + if ( prev_line.first.value == 'class' and + style.Get( 'BLANK_LINE_BEFORE_CLASS_DOCSTRING' ) ): + # Enforce a blank line before a class's docstring. + return ONE_BLANK_LINE + elif ( prev_line.first.value.startswith( '#' ) and + style.Get( 'BLANK_LINE_BEFORE_MODULE_DOCSTRING' ) ): + # Enforce a blank line before a module's docstring. + return ONE_BLANK_LINE + # The docstring shouldn't have a newline before it. return NO_BLANK_LINES - # Calculate how many newlines were between the original lines. We want to - # retain that formatting if it doesn't violate one of the style guide rules. - if first_token.is_comment: - first_token_lineno = first_token.lineno - first_token.value.count('\n') - else: - first_token_lineno = first_token.lineno + if first_token.is_name and not indent_depth: + if prev_line.first.value in { 'from', 'import' }: + # Support custom number of blank lines between top-level imports and + # variable definitions. + return 1 + style.Get( + 'BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES' ) + + prev_last_token = prev_line.last + if prev_last_token.is_docstring: + if ( not indent_depth and first_token.value in { 'class', 'def', 'async' } ): + # Separate a class or function from the module-level docstring with + # appropriate number of blank lines. + return 1 + style.Get( 'BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION' ) + if ( first_nested and + not style.Get( 'BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF' ) and + _IsClassOrDef( first_token ) ): + first_token.newlines = None + return NO_BLANK_LINES + if _NoBlankLinesBeforeCurrentToken( prev_last_token.value, first_token, + prev_last_token ): + return NO_BLANK_LINES + else: + return ONE_BLANK_LINE + + if _IsClassOrDef( first_token ): + # TODO(morbo): This can go once the blank line calculator is more + # sophisticated. + if not indent_depth: + # This is a top-level class or function. + is_inline_comment = prev_last_token.whitespace_prefix.count( '\n' ) == 0 + if ( not prev_line.disable and prev_last_token.is_comment and + not is_inline_comment ): + # This token follows a non-inline comment. + if _NoBlankLinesBeforeCurrentToken( prev_last_token.value, first_token, + prev_last_token ): + # Assume that the comment is "attached" to the current line. + # Therefore, we want two blank lines before the comment. + index = len( final_lines ) - 1 + while index > 0: + if not final_lines[ index - 1 ].is_comment: + break + index -= 1 + if final_lines[ index - 1 ].first.value == '@': + final_lines[ index ].first.AdjustNewlinesBefore( + NO_BLANK_LINES ) + else: + prev_last_token.AdjustNewlinesBefore( + 1 + style.Get( 'BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION' ) ) + if first_token.newlines is not None: + first_token.newlines = None + return NO_BLANK_LINES + elif _IsClassOrDef( prev_line.first ): + if first_nested and not style.Get( + 'BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF' ): + first_token.newlines = None + return NO_BLANK_LINES + + # Calculate how many newlines were between the original lines. We want to + # retain that formatting if it doesn't violate one of the style guide rules. + if first_token.is_comment: + first_token_lineno = first_token.lineno - first_token.value.count( '\n' ) + else: + first_token_lineno = first_token.lineno - prev_last_token_lineno = prev_last_token.lineno - if prev_last_token.is_multiline_string: - prev_last_token_lineno += prev_last_token.value.count('\n') + prev_last_token_lineno = prev_last_token.lineno + if prev_last_token.is_multiline_string: + prev_last_token_lineno += prev_last_token.value.count( '\n' ) - if first_token_lineno - prev_last_token_lineno > 1: - return ONE_BLANK_LINE + if first_token_lineno - prev_last_token_lineno > 1: + return ONE_BLANK_LINE - return NO_BLANK_LINES + return NO_BLANK_LINES -def _SingleOrMergedLines(lines): - """Generate the lines we want to format. +def _SingleOrMergedLines( lines ): + """Generate the lines we want to format. Arguments: lines: (list of logical_line.LogicalLine) Lines we want to format. @@ -1233,46 +912,49 @@ def _SingleOrMergedLines(lines): Either a single line, if the current line cannot be merged with the succeeding line, or the next two lines merged into one line. """ - index = 0 - last_was_merged = False - while index < len(lines): - if lines[index].disable: - line = lines[index] - index += 1 - while index < len(lines): - column = line.last.column + 2 - if lines[index].lineno != line.lineno: - break - if line.last.value != ':': - leaf = pytree.Leaf( - type=token.SEMI, value=';', context=('', (line.lineno, column))) - line.AppendToken( - format_token.FormatToken(leaf, pytree_utils.NodeName(leaf))) - for tok in lines[index].tokens: - line.AppendToken(tok) - index += 1 - yield line - elif line_joiner.CanMergeMultipleLines(lines[index:], last_was_merged): - # TODO(morbo): This splice is potentially very slow. Come up with a more - # performance-friendly way of determining if two lines can be merged. - next_line = lines[index + 1] - for tok in next_line.tokens: - lines[index].AppendToken(tok) - if (len(next_line.tokens) == 1 and next_line.first.is_multiline_string): - # This may be a multiline shebang. In that case, we want to retain the - # formatting. Otherwise, it could mess up the shell script's syntax. - lines[index].disable = True - yield lines[index] - index += 2 - last_was_merged = True - else: - yield lines[index] - index += 1 - last_was_merged = False - - -def _NoBlankLinesBeforeCurrentToken(text, cur_token, prev_token): - """Determine if there are no blank lines before the current token. + index = 0 + last_was_merged = False + while index < len( lines ): + if lines[ index ].disable: + line = lines[ index ] + index += 1 + while index < len( lines ): + column = line.last.column + 2 + if lines[ index ].lineno != line.lineno: + break + if line.last.value != ':': + leaf = pytree.Leaf( + type = token.SEMI, + value = ';', + context = ( '', ( line.lineno, column ) ) ) + line.AppendToken( + format_token.FormatToken( leaf, + pytree_utils.NodeName( leaf ) ) ) + for tok in lines[ index ].tokens: + line.AppendToken( tok ) + index += 1 + yield line + elif line_joiner.CanMergeMultipleLines( lines[ index : ], last_was_merged ): + # TODO(morbo): This splice is potentially very slow. Come up with a more + # performance-friendly way of determining if two lines can be merged. + next_line = lines[ index + 1 ] + for tok in next_line.tokens: + lines[ index ].AppendToken( tok ) + if ( len( next_line.tokens ) == 1 and next_line.first.is_multiline_string ): + # This may be a multiline shebang. In that case, we want to retain the + # formatting. Otherwise, it could mess up the shell script's syntax. + lines[ index ].disable = True + yield lines[ index ] + index += 2 + last_was_merged = True + else: + yield lines[ index ] + index += 1 + last_was_merged = False + + +def _NoBlankLinesBeforeCurrentToken( text, cur_token, prev_token ): + """Determine if there are no blank lines before the current token. The previous token is a docstring or comment. The prev_token_lineno is the start of the text of that token. Counting the number of newlines in its text @@ -1290,8 +972,8 @@ def _NoBlankLinesBeforeCurrentToken(text, cur_token, prev_token): Returns: True if there is no blank line before the current token. """ - cur_token_lineno = cur_token.lineno - if cur_token.is_comment: - cur_token_lineno -= cur_token.value.count('\n') - num_newlines = text.count('\n') if not prev_token.is_comment else 0 - return prev_token.lineno + num_newlines == cur_token_lineno - 1 + cur_token_lineno = cur_token.lineno + if cur_token.is_comment: + cur_token_lineno -= cur_token.value.count( '\n' ) + num_newlines = text.count( '\n' ) if not prev_token.is_comment else 0 + return prev_token.lineno + num_newlines == cur_token_lineno - 1 diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 79b68edcd..8f93d3ade 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -15,9 +15,9 @@ from yapf.yapflib import style # Generic split penalties -UNBREAKABLE = 1000**5 +UNBREAKABLE = 1000**5 VERY_STRONGLY_CONNECTED = 5000 -STRONGLY_CONNECTED = 2500 +STRONGLY_CONNECTED = 2500 ############################################################################# # Grammar-specific penalties - should be <= 1000 # @@ -25,15 +25,15 @@ # Lambdas shouldn't be split unless absolutely necessary or if # ALLOW_MULTILINE_LAMBDAS is True. -LAMBDA = 1000 +LAMBDA = 1000 MULTILINE_LAMBDA = 500 ANNOTATION = 100 -ARGUMENT = 25 +ARGUMENT = 25 # TODO: Assign real values. -RETURN_TYPE = 1 -DOTTED_NAME = 40 -EXPR = 10 -DICT_KEY_EXPR = 20 +RETURN_TYPE = 1 +DOTTED_NAME = 40 +EXPR = 10 +DICT_KEY_EXPR = 20 DICT_VALUE_EXPR = 11 diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index d9e9e5e9e..684bfb274 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -21,71 +21,70 @@ from yapf.yapflib import py3compat -class StyleConfigError(errors.YapfError): - """Raised when there's a problem reading the style configuration.""" - pass +class StyleConfigError( errors.YapfError ): + """Raised when there's a problem reading the style configuration.""" + pass -def Get(setting_name): - """Get a style setting.""" - return _style[setting_name] +def Get( setting_name ): + """Get a style setting.""" + return _style[ setting_name ] -def GetOrDefault(setting_name, default_value): - """Get a style setting or default value if the setting does not exist.""" - return _style.get(setting_name, default_value) +def GetOrDefault( setting_name, default_value ): + """Get a style setting or default value if the setting does not exist.""" + return _style.get( setting_name, default_value ) def Help(): - """Return dict mapping style names to help strings.""" - return _STYLE_HELP + """Return dict mapping style names to help strings.""" + return _STYLE_HELP -def SetGlobalStyle(style): - """Set a style dict.""" - global _style - global _GLOBAL_STYLE_FACTORY - factory = _GetStyleFactory(style) - if factory: - _GLOBAL_STYLE_FACTORY = factory - _style = style +def SetGlobalStyle( style ): + """Set a style dict.""" + global _style + global _GLOBAL_STYLE_FACTORY + factory = _GetStyleFactory( style ) + if factory: + _GLOBAL_STYLE_FACTORY = factory + _style = style _STYLE_HELP = dict( - ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=textwrap.dedent("""\ - Align closing bracket with visual indentation."""), - ALIGN_ASSIGNMENT=textwrap.dedent("""\ + ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT = textwrap.dedent( + """\ + Align closing bracket with visual indentation.""" ), + ALIGN_ASSIGNMENT = textwrap.dedent( + """\ Align assignment or augmented assignment operators. If there is a blank line or newline comment or objects with newline entries in between, - it will start new block alignment."""), - ALIGN_ARGUMENT_ASSIGNMENT=textwrap.dedent("""\ - Align assignment operators in the argument list if they are all split on newlines. - Arguments without assignment are ignored. - Arguments without assignment in between will initiate new block alignment calulation. - Newline comments or objects with newline entries will also start new block alignment."""), - ALIGN_DICT_COLON=textwrap.dedent("""\ - Align the colons in the dictionary - if all entries in dictionay are split on newlines. - or 'EACH_DICT_ENTRY_ON_SEPERATE_LINE' is set True. - """), - NEW_ALIGNMENT_AFTER_COMMENTLINE=textwrap.dedent("""\ - Start new assignment or colon alignment when there is a newline comment in between."""), - ALLOW_MULTILINE_LAMBDAS=textwrap.dedent("""\ - Allow lambdas to be formatted on more than one line."""), - ALLOW_MULTILINE_DICTIONARY_KEYS=textwrap.dedent("""\ + it will start new block alignment.""" ), + NEW_ALIGNMENT_AFTER_COMMENTLINE = textwrap.dedent( + """\ + Start new assignment or colon alignment when there is a newline comment in between.""" + ), + ALLOW_MULTILINE_LAMBDAS = textwrap.dedent( + """\ + Allow lambdas to be formatted on more than one line.""" ), + ALLOW_MULTILINE_DICTIONARY_KEYS = textwrap.dedent( + """\ Allow dictionary keys to exist on multiple lines. For example: x = { ('this is the first element of a tuple', 'this is the second element of a tuple'): value, - }"""), - ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=textwrap.dedent("""\ + }""" ), + ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS = textwrap.dedent( + """\ Allow splitting before a default / named assignment in an argument list. - """), - ALLOW_SPLIT_BEFORE_DICT_VALUE=textwrap.dedent("""\ - Allow splits before the dictionary value."""), - ARITHMETIC_PRECEDENCE_INDICATION=textwrap.dedent("""\ + """ ), + ALLOW_SPLIT_BEFORE_DICT_VALUE = textwrap.dedent( + """\ + Allow splits before the dictionary value.""" ), + ARITHMETIC_PRECEDENCE_INDICATION = textwrap.dedent( + """\ Let spacing indicate operator precedence. For example: a = 1 * 2 + 3 / 4 @@ -104,26 +103,32 @@ def SetGlobalStyle(style): e = 1*2 - 3 f = 1 + 2 + 3 + 4 - """), - BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=textwrap.dedent("""\ + """ ), + BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF = textwrap.dedent( + """\ Insert a blank line before a 'def' or 'class' immediately nested within another 'def' or 'class'. For example: class Foo: # <------ this blank line def method(): - ..."""), - BLANK_LINE_BEFORE_CLASS_DOCSTRING=textwrap.dedent("""\ - Insert a blank line before a class-level docstring."""), - BLANK_LINE_BEFORE_MODULE_DOCSTRING=textwrap.dedent("""\ - Insert a blank line before a module docstring."""), - BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=textwrap.dedent("""\ + ...""" ), + BLANK_LINE_BEFORE_CLASS_DOCSTRING = textwrap.dedent( + """\ + Insert a blank line before a class-level docstring.""" ), + BLANK_LINE_BEFORE_MODULE_DOCSTRING = textwrap.dedent( + """\ + Insert a blank line before a module docstring.""" ), + BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION = textwrap.dedent( + """\ Number of blank lines surrounding top-level function and class - definitions."""), - BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES=textwrap.dedent("""\ + definitions.""" ), + BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES = textwrap.dedent( + """\ Number of blank lines between top-level imports and variable - definitions."""), - COALESCE_BRACKETS=textwrap.dedent("""\ + definitions.""" ), + COALESCE_BRACKETS = textwrap.dedent( + """\ Do not split consecutive brackets. Only relevant when dedent_closing_brackets is set. For example: @@ -139,10 +144,11 @@ def method(): call_func_that_takes_a_dict({ 'key1': 'value1', 'key2': 'value2', - })"""), - COLUMN_LIMIT=textwrap.dedent("""\ - The column limit."""), - CONTINUATION_ALIGN_STYLE=textwrap.dedent("""\ + })""" ), + COLUMN_LIMIT = textwrap.dedent( """\ + The column limit.""" ), + CONTINUATION_ALIGN_STYLE = textwrap.dedent( + """\ The style for continuation alignment. Possible values are: - SPACE: Use spaces for continuation alignment. This is default behavior. @@ -151,10 +157,12 @@ def method(): CONTINUATION_INDENT_WIDTH spaces) for continuation alignment. - VALIGN-RIGHT: Vertically align continuation lines to multiple of INDENT_WIDTH columns. Slightly right (one tab or a few spaces) if - cannot vertically align continuation lines with indent characters."""), - CONTINUATION_INDENT_WIDTH=textwrap.dedent("""\ - Indent width used for line continuations."""), - DEDENT_CLOSING_BRACKETS=textwrap.dedent("""\ + cannot vertically align continuation lines with indent characters.""" ), + CONTINUATION_INDENT_WIDTH = textwrap.dedent( + """\ + Indent width used for line continuations.""" ), + DEDENT_CLOSING_BRACKETS = textwrap.dedent( + """\ Put closing brackets on a separate line, dedented, if the bracketed expression can't fit in a single line. Applies to all kinds of brackets, including function definitions and calls. For example: @@ -171,28 +179,34 @@ def method(): start_ts=now()-timedelta(days=3), end_ts=now(), ) # <--- this bracket is dedented and on a separate line - """), - DISABLE_ENDING_COMMA_HEURISTIC=textwrap.dedent("""\ + """ ), + DISABLE_ENDING_COMMA_HEURISTIC = textwrap.dedent( + """\ Disable the heuristic which places each list element on a separate line - if the list is comma-terminated."""), - EACH_DICT_ENTRY_ON_SEPARATE_LINE=textwrap.dedent("""\ - Place each dictionary entry onto its own line."""), - FORCE_MULTILINE_DICT=textwrap.dedent("""\ + if the list is comma-terminated.""" ), + EACH_DICT_ENTRY_ON_SEPARATE_LINE = textwrap.dedent( + """\ + Place each dictionary entry onto its own line.""" ), + FORCE_MULTILINE_DICT = textwrap.dedent( + """\ Require multiline dictionary even if it would normally fit on one line. For example: config = { 'key1': 'value1' - }"""), - I18N_COMMENT=textwrap.dedent("""\ + }""" ), + I18N_COMMENT = textwrap.dedent( + """\ The regex for an i18n comment. The presence of this comment stops reformatting of that line, because the comments are required to be - next to the string they translate."""), - I18N_FUNCTION_CALL=textwrap.dedent("""\ + next to the string they translate.""" ), + I18N_FUNCTION_CALL = textwrap.dedent( + """\ The i18n function call names. The presence of this function stops reformattting on that line, because the string it has cannot be moved - away from the i18n comment."""), - INDENT_CLOSING_BRACKETS=textwrap.dedent("""\ + away from the i18n comment.""" ), + INDENT_CLOSING_BRACKETS = textwrap.dedent( + """\ Put closing brackets on a separate line, indented, if the bracketed expression can't fit in a single line. Applies to all kinds of brackets, including function definitions and calls. For example: @@ -209,8 +223,9 @@ def method(): start_ts=now()-timedelta(days=3), end_ts=now(), ) # <--- this bracket is indented and on a separate line - """), - INDENT_DICTIONARY_VALUE=textwrap.dedent("""\ + """ ), + INDENT_DICTIONARY_VALUE = textwrap.dedent( + """\ Indent the dictionary value if it cannot fit on the same line as the dictionary key. For example: @@ -220,14 +235,17 @@ def method(): 'key2': value1 + value2, } - """), - INDENT_WIDTH=textwrap.dedent("""\ - The number of columns to use for indentation."""), - INDENT_BLANK_LINES=textwrap.dedent("""\ - Indent blank lines."""), - JOIN_MULTIPLE_LINES=textwrap.dedent("""\ - Join short lines into one line. E.g., single line 'if' statements."""), - NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=textwrap.dedent("""\ + """ ), + INDENT_WIDTH = textwrap.dedent( + """\ + The number of columns to use for indentation.""" ), + INDENT_BLANK_LINES = textwrap.dedent( """\ + Indent blank lines.""" ), + JOIN_MULTIPLE_LINES = textwrap.dedent( + """\ + Join short lines into one line. E.g., single line 'if' statements.""" ), + NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS = textwrap.dedent( + """\ Do not include spaces around selected binary operators. For example: 1 + 2 * 3 - 4 / 5 @@ -235,22 +253,27 @@ def method(): will be formatted as follows when configured with "*,/": 1 + 2*3 - 4/5 - """), - SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=textwrap.dedent("""\ + """ ), + SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET = textwrap.dedent( + """\ Insert a space between the ending comma and closing bracket of a list, - etc."""), - SPACE_INSIDE_BRACKETS=textwrap.dedent("""\ + etc.""" ), + SPACE_INSIDE_BRACKETS = textwrap.dedent( + """\ Use spaces inside brackets, braces, and parentheses. For example: method_call( 1 ) my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] my_set = { 1, 2, 3 } - """), - SPACES_AROUND_POWER_OPERATOR=textwrap.dedent("""\ - Use spaces around the power operator."""), - SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=textwrap.dedent("""\ - Use spaces around default or named assigns."""), - SPACES_AROUND_DICT_DELIMITERS=textwrap.dedent("""\ + """ ), + SPACES_AROUND_POWER_OPERATOR = textwrap.dedent( + """\ + Use spaces around the power operator.""" ), + SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN = textwrap.dedent( + """\ + Use spaces around default or named assigns.""" ), + SPACES_AROUND_DICT_DELIMITERS = textwrap.dedent( + """\ Adds a space after the opening '{' and before the ending '}' dict delimiters. @@ -259,8 +282,9 @@ def method(): will be formatted as: { 1: 2 } - """), - SPACES_AROUND_LIST_DELIMITERS=textwrap.dedent("""\ + """ ), + SPACES_AROUND_LIST_DELIMITERS = textwrap.dedent( + """\ Adds a space after the opening '[' and before the ending ']' list delimiters. @@ -269,13 +293,15 @@ def method(): will be formatted as: [ 1, 2 ] - """), - SPACES_AROUND_SUBSCRIPT_COLON=textwrap.dedent("""\ + """ ), + SPACES_AROUND_SUBSCRIPT_COLON = textwrap.dedent( + """\ Use spaces around the subscript / slice operator. For example: my_list[1 : 10 : 2] - """), - SPACES_AROUND_TUPLE_DELIMITERS=textwrap.dedent("""\ + """ ), + SPACES_AROUND_TUPLE_DELIMITERS = textwrap.dedent( + """\ Adds a space after the opening '(' and before the ending ')' tuple delimiters. @@ -284,8 +310,9 @@ def method(): will be formatted as: ( 1, 2, 3 ) - """), - SPACES_BEFORE_COMMENT=textwrap.dedent("""\ + """ ), + SPACES_BEFORE_COMMENT = textwrap.dedent( + """\ The number of spaces required before a trailing comment. This can be a single value (representing the number of spaces before each trailing comment) or list of values (representing @@ -326,33 +353,41 @@ def method(): a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length short # This is a shorter statement - """), # noqa - SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=textwrap.dedent("""\ + """ ), # noqa + SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED = textwrap.dedent( + """\ Split before arguments if the argument list is terminated by a - comma."""), - SPLIT_ALL_COMMA_SEPARATED_VALUES=textwrap.dedent("""\ - Split before arguments"""), - SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=textwrap.dedent("""\ + comma.""" ), + SPLIT_ALL_COMMA_SEPARATED_VALUES = textwrap.dedent( + """\ + Split before arguments""" ), + SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES = textwrap.dedent( + """\ Split before arguments, but do not split all subexpressions recursively - (unless needed)."""), - SPLIT_BEFORE_ARITHMETIC_OPERATOR=textwrap.dedent("""\ + (unless needed).""" ), + SPLIT_BEFORE_ARITHMETIC_OPERATOR = textwrap.dedent( + """\ Set to True to prefer splitting before '+', '-', '*', '/', '//', or '@' - rather than after."""), - SPLIT_BEFORE_BITWISE_OPERATOR=textwrap.dedent("""\ + rather than after.""" ), + SPLIT_BEFORE_BITWISE_OPERATOR = textwrap.dedent( + """\ Set to True to prefer splitting before '&', '|' or '^' rather than - after."""), - SPLIT_BEFORE_CLOSING_BRACKET=textwrap.dedent("""\ + after.""" ), + SPLIT_BEFORE_CLOSING_BRACKET = textwrap.dedent( + """\ Split before the closing bracket if a list or dict literal doesn't fit on - a single line."""), - SPLIT_BEFORE_DICT_SET_GENERATOR=textwrap.dedent("""\ + a single line.""" ), + SPLIT_BEFORE_DICT_SET_GENERATOR = textwrap.dedent( + """\ Split before a dictionary or set generator (comp_for). For example, note the split before the 'for': foo = { variable: 'Hello world, have a nice day!' for variable in bar if variable != 42 - }"""), - SPLIT_BEFORE_DOT=textwrap.dedent("""\ + }""" ), + SPLIT_BEFORE_DOT = textwrap.dedent( + """\ Split before the '.' if we need to split a longer expression: foo = ('This is a really long string: {}, {}, {}, {}'.format(a, b, c, d)) @@ -361,20 +396,25 @@ def method(): foo = ('This is a really long string: {}, {}, {}, {}' .format(a, b, c, d)) - """), # noqa - SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=textwrap.dedent("""\ + """ ), # noqa + SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN = textwrap.dedent( + """\ Split after the opening paren which surrounds an expression if it doesn't fit on a single line. - """), - SPLIT_BEFORE_FIRST_ARGUMENT=textwrap.dedent("""\ + """ ), + SPLIT_BEFORE_FIRST_ARGUMENT = textwrap.dedent( + """\ If an argument / parameter list is going to be split, then split before - the first argument."""), - SPLIT_BEFORE_LOGICAL_OPERATOR=textwrap.dedent("""\ + the first argument.""" ), + SPLIT_BEFORE_LOGICAL_OPERATOR = textwrap.dedent( + """\ Set to True to prefer splitting before 'and' or 'or' rather than - after."""), - SPLIT_BEFORE_NAMED_ASSIGNS=textwrap.dedent("""\ - Split named assignments onto individual lines."""), - SPLIT_COMPLEX_COMPREHENSION=textwrap.dedent("""\ + after.""" ), + SPLIT_BEFORE_NAMED_ASSIGNS = textwrap.dedent( + """\ + Split named assignments onto individual lines.""" ), + SPLIT_COMPLEX_COMPREHENSION = textwrap.dedent( + """\ Set to True to split list comprehensions and generators that have non-trivial expressions and multiple clauses before each of these clauses. For example: @@ -389,28 +429,37 @@ def method(): a_long_var + 100 for a_long_var in xrange(1000) if a_long_var % 10] - """), - SPLIT_PENALTY_AFTER_OPENING_BRACKET=textwrap.dedent("""\ - The penalty for splitting right after the opening bracket."""), - SPLIT_PENALTY_AFTER_UNARY_OPERATOR=textwrap.dedent("""\ - The penalty for splitting the line after a unary operator."""), - SPLIT_PENALTY_ARITHMETIC_OPERATOR=textwrap.dedent("""\ + """ ), + SPLIT_PENALTY_AFTER_OPENING_BRACKET = textwrap.dedent( + """\ + The penalty for splitting right after the opening bracket.""" ), + SPLIT_PENALTY_AFTER_UNARY_OPERATOR = textwrap.dedent( + """\ + The penalty for splitting the line after a unary operator.""" ), + SPLIT_PENALTY_ARITHMETIC_OPERATOR = textwrap.dedent( + """\ The penalty of splitting the line around the '+', '-', '*', '/', '//', - ``%``, and '@' operators."""), - SPLIT_PENALTY_BEFORE_IF_EXPR=textwrap.dedent("""\ - The penalty for splitting right before an if expression."""), - SPLIT_PENALTY_BITWISE_OPERATOR=textwrap.dedent("""\ + ``%``, and '@' operators.""" ), + SPLIT_PENALTY_BEFORE_IF_EXPR = textwrap.dedent( + """\ + The penalty for splitting right before an if expression.""" ), + SPLIT_PENALTY_BITWISE_OPERATOR = textwrap.dedent( + """\ The penalty of splitting the line around the '&', '|', and '^' - operators."""), - SPLIT_PENALTY_COMPREHENSION=textwrap.dedent("""\ + operators.""" ), + SPLIT_PENALTY_COMPREHENSION = textwrap.dedent( + """\ The penalty for splitting a list comprehension or generator - expression."""), - SPLIT_PENALTY_EXCESS_CHARACTER=textwrap.dedent("""\ - The penalty for characters over the column limit."""), - SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=textwrap.dedent("""\ + expression.""" ), + SPLIT_PENALTY_EXCESS_CHARACTER = textwrap.dedent( + """\ + The penalty for characters over the column limit.""" ), + SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT = textwrap.dedent( + """\ The penalty incurred by adding a line split to the logical line. The - more line splits added the higher the penalty."""), - SPLIT_PENALTY_IMPORT_NAMES=textwrap.dedent("""\ + more line splits added the higher the penalty.""" ), + SPLIT_PENALTY_IMPORT_NAMES = textwrap.dedent( + """\ The penalty of splitting a list of "import as" names. For example: from a_very_long_or_indented_module_name_yada_yad import (long_argument_1, @@ -421,201 +470,200 @@ def method(): from a_very_long_or_indented_module_name_yada_yad import ( long_argument_1, long_argument_2, long_argument_3) - """), # noqa - SPLIT_PENALTY_LOGICAL_OPERATOR=textwrap.dedent("""\ + """ ), # noqa + SPLIT_PENALTY_LOGICAL_OPERATOR = textwrap.dedent( + """\ The penalty of splitting the line around the 'and' and 'or' - operators."""), - USE_TABS=textwrap.dedent("""\ - Use the Tab character for indentation."""), - # BASED_ON_STYLE='Which predefined style this style is based on', + operators.""" ), + USE_TABS = textwrap.dedent( """\ + Use the Tab character for indentation.""" ), + # BASED_ON_STYLE='Which predefined style this style is based on', ) def CreatePEP8Style(): - """Create the PEP8 formatting style.""" - return dict( - ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=True, - ALIGN_ASSIGNMENT=False, - ALIGN_ARGUMENT_ASSIGNMENT=False, - ALIGN_DICT_COLON=False, - NEW_ALIGNMENT_AFTER_COMMENTLINE=False, - ALLOW_MULTILINE_LAMBDAS=False, - ALLOW_MULTILINE_DICTIONARY_KEYS=False, - ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=True, - ALLOW_SPLIT_BEFORE_DICT_VALUE=True, - ARITHMETIC_PRECEDENCE_INDICATION=False, - BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=True, - BLANK_LINE_BEFORE_CLASS_DOCSTRING=False, - BLANK_LINE_BEFORE_MODULE_DOCSTRING=False, - BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=2, - BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES=1, - COALESCE_BRACKETS=False, - COLUMN_LIMIT=79, - CONTINUATION_ALIGN_STYLE='SPACE', - CONTINUATION_INDENT_WIDTH=4, - DEDENT_CLOSING_BRACKETS=False, - INDENT_CLOSING_BRACKETS=False, - DISABLE_ENDING_COMMA_HEURISTIC=False, - EACH_DICT_ENTRY_ON_SEPARATE_LINE=True, - FORCE_MULTILINE_DICT=False, - I18N_COMMENT='', - I18N_FUNCTION_CALL='', - INDENT_DICTIONARY_VALUE=False, - INDENT_WIDTH=4, - INDENT_BLANK_LINES=False, - JOIN_MULTIPLE_LINES=True, - NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=set(), - SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=True, - SPACE_INSIDE_BRACKETS=False, - SPACES_AROUND_POWER_OPERATOR=False, - SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=False, - SPACES_AROUND_DICT_DELIMITERS=False, - SPACES_AROUND_LIST_DELIMITERS=False, - SPACES_AROUND_SUBSCRIPT_COLON=False, - SPACES_AROUND_TUPLE_DELIMITERS=False, - SPACES_BEFORE_COMMENT=2, - SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False, - SPLIT_ALL_COMMA_SEPARATED_VALUES=False, - SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=False, - SPLIT_BEFORE_ARITHMETIC_OPERATOR=False, - SPLIT_BEFORE_BITWISE_OPERATOR=True, - SPLIT_BEFORE_CLOSING_BRACKET=True, - SPLIT_BEFORE_DICT_SET_GENERATOR=True, - SPLIT_BEFORE_DOT=False, - SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=False, - SPLIT_BEFORE_FIRST_ARGUMENT=False, - SPLIT_BEFORE_LOGICAL_OPERATOR=True, - SPLIT_BEFORE_NAMED_ASSIGNS=True, - SPLIT_COMPLEX_COMPREHENSION=False, - SPLIT_PENALTY_AFTER_OPENING_BRACKET=300, - SPLIT_PENALTY_AFTER_UNARY_OPERATOR=10000, - SPLIT_PENALTY_ARITHMETIC_OPERATOR=300, - SPLIT_PENALTY_BEFORE_IF_EXPR=0, - SPLIT_PENALTY_BITWISE_OPERATOR=300, - SPLIT_PENALTY_COMPREHENSION=80, - SPLIT_PENALTY_EXCESS_CHARACTER=7000, - SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=30, - SPLIT_PENALTY_IMPORT_NAMES=0, - SPLIT_PENALTY_LOGICAL_OPERATOR=300, - USE_TABS=False, - ) + """Create the PEP8 formatting style.""" + return dict( + ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT = True, + ALIGN_ASSIGNMENT = False, + NEW_ALIGNMENT_AFTER_COMMENTLINE = False, + ALLOW_MULTILINE_LAMBDAS = False, + ALLOW_MULTILINE_DICTIONARY_KEYS = False, + ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS = True, + ALLOW_SPLIT_BEFORE_DICT_VALUE = True, + ARITHMETIC_PRECEDENCE_INDICATION = False, + BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF = True, + BLANK_LINE_BEFORE_CLASS_DOCSTRING = False, + BLANK_LINE_BEFORE_MODULE_DOCSTRING = False, + BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION = 2, + BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES = 1, + COALESCE_BRACKETS = False, + COLUMN_LIMIT = 79, + CONTINUATION_ALIGN_STYLE = 'SPACE', + CONTINUATION_INDENT_WIDTH = 4, + DEDENT_CLOSING_BRACKETS = False, + INDENT_CLOSING_BRACKETS = False, + DISABLE_ENDING_COMMA_HEURISTIC = False, + EACH_DICT_ENTRY_ON_SEPARATE_LINE = True, + FORCE_MULTILINE_DICT = False, + I18N_COMMENT = '', + I18N_FUNCTION_CALL = '', + INDENT_DICTIONARY_VALUE = False, + INDENT_WIDTH = 4, + INDENT_BLANK_LINES = False, + JOIN_MULTIPLE_LINES = True, + NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS = set(), + SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET = True, + SPACE_INSIDE_BRACKETS = False, + SPACES_AROUND_POWER_OPERATOR = False, + SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN = False, + SPACES_AROUND_DICT_DELIMITERS = False, + SPACES_AROUND_LIST_DELIMITERS = False, + SPACES_AROUND_SUBSCRIPT_COLON = False, + SPACES_AROUND_TUPLE_DELIMITERS = False, + SPACES_BEFORE_COMMENT = 2, + SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED = False, + SPLIT_ALL_COMMA_SEPARATED_VALUES = False, + SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES = False, + SPLIT_BEFORE_ARITHMETIC_OPERATOR = False, + SPLIT_BEFORE_BITWISE_OPERATOR = True, + SPLIT_BEFORE_CLOSING_BRACKET = True, + SPLIT_BEFORE_DICT_SET_GENERATOR = True, + SPLIT_BEFORE_DOT = False, + SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN = False, + SPLIT_BEFORE_FIRST_ARGUMENT = False, + SPLIT_BEFORE_LOGICAL_OPERATOR = True, + SPLIT_BEFORE_NAMED_ASSIGNS = True, + SPLIT_COMPLEX_COMPREHENSION = False, + SPLIT_PENALTY_AFTER_OPENING_BRACKET = 300, + SPLIT_PENALTY_AFTER_UNARY_OPERATOR = 10000, + SPLIT_PENALTY_ARITHMETIC_OPERATOR = 300, + SPLIT_PENALTY_BEFORE_IF_EXPR = 0, + SPLIT_PENALTY_BITWISE_OPERATOR = 300, + SPLIT_PENALTY_COMPREHENSION = 80, + SPLIT_PENALTY_EXCESS_CHARACTER = 7000, + SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT = 30, + SPLIT_PENALTY_IMPORT_NAMES = 0, + SPLIT_PENALTY_LOGICAL_OPERATOR = 300, + USE_TABS = False, + ) def CreateGoogleStyle(): - """Create the Google formatting style.""" - style = CreatePEP8Style() - style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False - style['COLUMN_LIMIT'] = 80 - style['INDENT_DICTIONARY_VALUE'] = True - style['INDENT_WIDTH'] = 4 - style['I18N_COMMENT'] = r'#\..*' - style['I18N_FUNCTION_CALL'] = ['N_', '_'] - style['JOIN_MULTIPLE_LINES'] = False - style['SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET'] = False - style['SPLIT_BEFORE_BITWISE_OPERATOR'] = False - style['SPLIT_BEFORE_DICT_SET_GENERATOR'] = False - style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False - style['SPLIT_COMPLEX_COMPREHENSION'] = True - style['SPLIT_PENALTY_COMPREHENSION'] = 2100 - return style + """Create the Google formatting style.""" + style = CreatePEP8Style() + style[ 'ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT' ] = False + style[ 'COLUMN_LIMIT' ] = 80 + style[ 'INDENT_DICTIONARY_VALUE' ] = True + style[ 'INDENT_WIDTH' ] = 4 + style[ 'I18N_COMMENT' ] = r'#\..*' + style[ 'I18N_FUNCTION_CALL' ] = [ 'N_', '_' ] + style[ 'JOIN_MULTIPLE_LINES' ] = False + style[ 'SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET' ] = False + style[ 'SPLIT_BEFORE_BITWISE_OPERATOR' ] = False + style[ 'SPLIT_BEFORE_DICT_SET_GENERATOR' ] = False + style[ 'SPLIT_BEFORE_LOGICAL_OPERATOR' ] = False + style[ 'SPLIT_COMPLEX_COMPREHENSION' ] = True + style[ 'SPLIT_PENALTY_COMPREHENSION' ] = 2100 + return style def CreateYapfStyle(): - """Create the YAPF formatting style.""" - style = CreateGoogleStyle() - style['ALLOW_MULTILINE_DICTIONARY_KEYS'] = True - style['ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS'] = False - style['INDENT_WIDTH'] = 2 - style['SPLIT_BEFORE_BITWISE_OPERATOR'] = True - style['SPLIT_BEFORE_DOT'] = True - style['SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN'] = True - return style + """Create the YAPF formatting style.""" + style = CreateGoogleStyle() + style[ 'ALLOW_MULTILINE_DICTIONARY_KEYS' ] = True + style[ 'ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS' ] = False + style[ 'INDENT_WIDTH' ] = 2 + style[ 'SPLIT_BEFORE_BITWISE_OPERATOR' ] = True + style[ 'SPLIT_BEFORE_DOT' ] = True + style[ 'SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN' ] = True + return style def CreateFacebookStyle(): - """Create the Facebook formatting style.""" - style = CreatePEP8Style() - style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False - style['BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'] = False - style['COLUMN_LIMIT'] = 80 - style['DEDENT_CLOSING_BRACKETS'] = True - style['INDENT_CLOSING_BRACKETS'] = False - style['INDENT_DICTIONARY_VALUE'] = True - style['JOIN_MULTIPLE_LINES'] = False - style['SPACES_BEFORE_COMMENT'] = 2 - style['SPLIT_PENALTY_AFTER_OPENING_BRACKET'] = 0 - style['SPLIT_PENALTY_BEFORE_IF_EXPR'] = 30 - style['SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT'] = 30 - style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False - style['SPLIT_BEFORE_BITWISE_OPERATOR'] = False - return style + """Create the Facebook formatting style.""" + style = CreatePEP8Style() + style[ 'ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT' ] = False + style[ 'BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF' ] = False + style[ 'COLUMN_LIMIT' ] = 80 + style[ 'DEDENT_CLOSING_BRACKETS' ] = True + style[ 'INDENT_CLOSING_BRACKETS' ] = False + style[ 'INDENT_DICTIONARY_VALUE' ] = True + style[ 'JOIN_MULTIPLE_LINES' ] = False + style[ 'SPACES_BEFORE_COMMENT' ] = 2 + style[ 'SPLIT_PENALTY_AFTER_OPENING_BRACKET' ] = 0 + style[ 'SPLIT_PENALTY_BEFORE_IF_EXPR' ] = 30 + style[ 'SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT' ] = 30 + style[ 'SPLIT_BEFORE_LOGICAL_OPERATOR' ] = False + style[ 'SPLIT_BEFORE_BITWISE_OPERATOR' ] = False + return style _STYLE_NAME_TO_FACTORY = dict( - pep8=CreatePEP8Style, - google=CreateGoogleStyle, - facebook=CreateFacebookStyle, - yapf=CreateYapfStyle, + pep8 = CreatePEP8Style, + google = CreateGoogleStyle, + facebook = CreateFacebookStyle, + yapf = CreateYapfStyle, ) _DEFAULT_STYLE_TO_FACTORY = [ - (CreateFacebookStyle(), CreateFacebookStyle), - (CreateGoogleStyle(), CreateGoogleStyle), - (CreatePEP8Style(), CreatePEP8Style), - (CreateYapfStyle(), CreateYapfStyle), + ( CreateFacebookStyle(), CreateFacebookStyle ), + ( CreateGoogleStyle(), CreateGoogleStyle ), + ( CreatePEP8Style(), CreatePEP8Style ), + ( CreateYapfStyle(), CreateYapfStyle ), ] -def _GetStyleFactory(style): - for def_style, factory in _DEFAULT_STYLE_TO_FACTORY: - if style == def_style: - return factory - return None +def _GetStyleFactory( style ): + for def_style, factory in _DEFAULT_STYLE_TO_FACTORY: + if style == def_style: + return factory + return None -def _ContinuationAlignStyleStringConverter(s): - """Option value converter for a continuation align style string.""" - accepted_styles = ('SPACE', 'FIXED', 'VALIGN-RIGHT') - if s: - r = s.strip('"\'').replace('_', '-').upper() - if r not in accepted_styles: - raise ValueError('unknown continuation align style: %r' % (s,)) - else: - r = accepted_styles[0] - return r +def _ContinuationAlignStyleStringConverter( s ): + """Option value converter for a continuation align style string.""" + accepted_styles = ( 'SPACE', 'FIXED', 'VALIGN-RIGHT' ) + if s: + r = s.strip( '"\'' ).replace( '_', '-' ).upper() + if r not in accepted_styles: + raise ValueError( 'unknown continuation align style: %r' % ( s,) ) + else: + r = accepted_styles[ 0 ] + return r -def _StringListConverter(s): - """Option value converter for a comma-separated list of strings.""" - return [part.strip() for part in s.split(',')] +def _StringListConverter( s ): + """Option value converter for a comma-separated list of strings.""" + return [ part.strip() for part in s.split( ',' ) ] -def _StringSetConverter(s): - """Option value converter for a comma-separated set of strings.""" - if len(s) > 2 and s[0] in '"\'': - s = s[1:-1] - return {part.strip() for part in s.split(',')} +def _StringSetConverter( s ): + """Option value converter for a comma-separated set of strings.""" + if len( s ) > 2 and s[ 0 ] in '"\'': + s = s[ 1 :-1 ] + return { part.strip() for part in s.split( ',' ) } -def _BoolConverter(s): - """Option value converter for a boolean.""" - return py3compat.CONFIGPARSER_BOOLEAN_STATES[s.lower()] +def _BoolConverter( s ): + """Option value converter for a boolean.""" + return py3compat.CONFIGPARSER_BOOLEAN_STATES[ s.lower() ] -def _IntListConverter(s): - """Option value converter for a comma-separated list of integers.""" - s = s.strip() - if s.startswith('[') and s.endswith(']'): - s = s[1:-1] +def _IntListConverter( s ): + """Option value converter for a comma-separated list of integers.""" + s = s.strip() + if s.startswith( '[' ) and s.endswith( ']' ): + s = s[ 1 :-1 ] - return [int(part.strip()) for part in s.split(',') if part.strip()] + return [ int( part.strip() ) for part in s.split( ',' ) if part.strip() ] -def _IntOrIntListConverter(s): - """Option value converter for an integer or list of integers.""" - if len(s) > 2 and s[0] in '"\'': - s = s[1:-1] - return _IntListConverter(s) if ',' in s else int(s) +def _IntOrIntListConverter( s ): + """Option value converter for an integer or list of integers.""" + if len( s ) > 2 and s[ 0 ] in '"\'': + s = s[ 1 :-1 ] + return _IntListConverter( s ) if ',' in s else int( s ) # Different style options need to have their values interpreted differently when @@ -626,75 +674,73 @@ def _IntOrIntListConverter(s): # # Note: this dict has to map all the supported style options. _STYLE_OPTION_VALUE_CONVERTER = dict( - ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=_BoolConverter, - ALIGN_ASSIGNMENT=_BoolConverter, - ALIGN_DICT_COLON=_BoolConverter, - NEW_ALIGNMENT_AFTER_COMMENTLINE=_BoolConverter, - ALIGN_ARGUMENT_ASSIGNMENT=_BoolConverter, - ALLOW_MULTILINE_LAMBDAS=_BoolConverter, - ALLOW_MULTILINE_DICTIONARY_KEYS=_BoolConverter, - ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=_BoolConverter, - ALLOW_SPLIT_BEFORE_DICT_VALUE=_BoolConverter, - ARITHMETIC_PRECEDENCE_INDICATION=_BoolConverter, - BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=_BoolConverter, - BLANK_LINE_BEFORE_CLASS_DOCSTRING=_BoolConverter, - BLANK_LINE_BEFORE_MODULE_DOCSTRING=_BoolConverter, - BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=int, - BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES=int, - COALESCE_BRACKETS=_BoolConverter, - COLUMN_LIMIT=int, - CONTINUATION_ALIGN_STYLE=_ContinuationAlignStyleStringConverter, - CONTINUATION_INDENT_WIDTH=int, - DEDENT_CLOSING_BRACKETS=_BoolConverter, - INDENT_CLOSING_BRACKETS=_BoolConverter, - DISABLE_ENDING_COMMA_HEURISTIC=_BoolConverter, - EACH_DICT_ENTRY_ON_SEPARATE_LINE=_BoolConverter, - FORCE_MULTILINE_DICT=_BoolConverter, - I18N_COMMENT=str, - I18N_FUNCTION_CALL=_StringListConverter, - INDENT_DICTIONARY_VALUE=_BoolConverter, - INDENT_WIDTH=int, - INDENT_BLANK_LINES=_BoolConverter, - JOIN_MULTIPLE_LINES=_BoolConverter, - NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=_StringSetConverter, - SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=_BoolConverter, - SPACE_INSIDE_BRACKETS=_BoolConverter, - SPACES_AROUND_POWER_OPERATOR=_BoolConverter, - SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=_BoolConverter, - SPACES_AROUND_DICT_DELIMITERS=_BoolConverter, - SPACES_AROUND_LIST_DELIMITERS=_BoolConverter, - SPACES_AROUND_SUBSCRIPT_COLON=_BoolConverter, - SPACES_AROUND_TUPLE_DELIMITERS=_BoolConverter, - SPACES_BEFORE_COMMENT=_IntOrIntListConverter, - SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter, - SPLIT_ALL_COMMA_SEPARATED_VALUES=_BoolConverter, - SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=_BoolConverter, - SPLIT_BEFORE_ARITHMETIC_OPERATOR=_BoolConverter, - SPLIT_BEFORE_BITWISE_OPERATOR=_BoolConverter, - SPLIT_BEFORE_CLOSING_BRACKET=_BoolConverter, - SPLIT_BEFORE_DICT_SET_GENERATOR=_BoolConverter, - SPLIT_BEFORE_DOT=_BoolConverter, - SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=_BoolConverter, - SPLIT_BEFORE_FIRST_ARGUMENT=_BoolConverter, - SPLIT_BEFORE_LOGICAL_OPERATOR=_BoolConverter, - SPLIT_BEFORE_NAMED_ASSIGNS=_BoolConverter, - SPLIT_COMPLEX_COMPREHENSION=_BoolConverter, - SPLIT_PENALTY_AFTER_OPENING_BRACKET=int, - SPLIT_PENALTY_AFTER_UNARY_OPERATOR=int, - SPLIT_PENALTY_ARITHMETIC_OPERATOR=int, - SPLIT_PENALTY_BEFORE_IF_EXPR=int, - SPLIT_PENALTY_BITWISE_OPERATOR=int, - SPLIT_PENALTY_COMPREHENSION=int, - SPLIT_PENALTY_EXCESS_CHARACTER=int, - SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=int, - SPLIT_PENALTY_IMPORT_NAMES=int, - SPLIT_PENALTY_LOGICAL_OPERATOR=int, - USE_TABS=_BoolConverter, + ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT = _BoolConverter, + ALIGN_ASSIGNMENT = _BoolConverter, + NEW_ALIGNMENT_AFTER_COMMENTLINE = _BoolConverter, + ALLOW_MULTILINE_LAMBDAS = _BoolConverter, + ALLOW_MULTILINE_DICTIONARY_KEYS = _BoolConverter, + ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS = _BoolConverter, + ALLOW_SPLIT_BEFORE_DICT_VALUE = _BoolConverter, + ARITHMETIC_PRECEDENCE_INDICATION = _BoolConverter, + BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF = _BoolConverter, + BLANK_LINE_BEFORE_CLASS_DOCSTRING = _BoolConverter, + BLANK_LINE_BEFORE_MODULE_DOCSTRING = _BoolConverter, + BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION = int, + BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES = int, + COALESCE_BRACKETS = _BoolConverter, + COLUMN_LIMIT = int, + CONTINUATION_ALIGN_STYLE = _ContinuationAlignStyleStringConverter, + CONTINUATION_INDENT_WIDTH = int, + DEDENT_CLOSING_BRACKETS = _BoolConverter, + INDENT_CLOSING_BRACKETS = _BoolConverter, + DISABLE_ENDING_COMMA_HEURISTIC = _BoolConverter, + EACH_DICT_ENTRY_ON_SEPARATE_LINE = _BoolConverter, + FORCE_MULTILINE_DICT = _BoolConverter, + I18N_COMMENT = str, + I18N_FUNCTION_CALL = _StringListConverter, + INDENT_DICTIONARY_VALUE = _BoolConverter, + INDENT_WIDTH = int, + INDENT_BLANK_LINES = _BoolConverter, + JOIN_MULTIPLE_LINES = _BoolConverter, + NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS = _StringSetConverter, + SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET = _BoolConverter, + SPACE_INSIDE_BRACKETS = _BoolConverter, + SPACES_AROUND_POWER_OPERATOR = _BoolConverter, + SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN = _BoolConverter, + SPACES_AROUND_DICT_DELIMITERS = _BoolConverter, + SPACES_AROUND_LIST_DELIMITERS = _BoolConverter, + SPACES_AROUND_SUBSCRIPT_COLON = _BoolConverter, + SPACES_AROUND_TUPLE_DELIMITERS = _BoolConverter, + SPACES_BEFORE_COMMENT = _IntOrIntListConverter, + SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED = _BoolConverter, + SPLIT_ALL_COMMA_SEPARATED_VALUES = _BoolConverter, + SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES = _BoolConverter, + SPLIT_BEFORE_ARITHMETIC_OPERATOR = _BoolConverter, + SPLIT_BEFORE_BITWISE_OPERATOR = _BoolConverter, + SPLIT_BEFORE_CLOSING_BRACKET = _BoolConverter, + SPLIT_BEFORE_DICT_SET_GENERATOR = _BoolConverter, + SPLIT_BEFORE_DOT = _BoolConverter, + SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN = _BoolConverter, + SPLIT_BEFORE_FIRST_ARGUMENT = _BoolConverter, + SPLIT_BEFORE_LOGICAL_OPERATOR = _BoolConverter, + SPLIT_BEFORE_NAMED_ASSIGNS = _BoolConverter, + SPLIT_COMPLEX_COMPREHENSION = _BoolConverter, + SPLIT_PENALTY_AFTER_OPENING_BRACKET = int, + SPLIT_PENALTY_AFTER_UNARY_OPERATOR = int, + SPLIT_PENALTY_ARITHMETIC_OPERATOR = int, + SPLIT_PENALTY_BEFORE_IF_EXPR = int, + SPLIT_PENALTY_BITWISE_OPERATOR = int, + SPLIT_PENALTY_COMPREHENSION = int, + SPLIT_PENALTY_EXCESS_CHARACTER = int, + SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT = int, + SPLIT_PENALTY_IMPORT_NAMES = int, + SPLIT_PENALTY_LOGICAL_OPERATOR = int, + USE_TABS = _BoolConverter, ) -def CreateStyleFromConfig(style_config): - """Create a style dict from the given config. +def CreateStyleFromConfig( style_config ): + """Create a style dict from the given config. Arguments: style_config: either a style name or a file name. The file is expected to @@ -710,107 +756,108 @@ def CreateStyleFromConfig(style_config): StyleConfigError: if an unknown style option was encountered. """ - def GlobalStyles(): - for style, _ in _DEFAULT_STYLE_TO_FACTORY: - yield style - - def_style = False - if style_config is None: - for style in GlobalStyles(): - if _style == style: - def_style = True - break - if not def_style: - return _style - return _GLOBAL_STYLE_FACTORY() - - if isinstance(style_config, dict): - config = _CreateConfigParserFromConfigDict(style_config) - elif isinstance(style_config, py3compat.basestring): - style_factory = _STYLE_NAME_TO_FACTORY.get(style_config.lower()) - if style_factory is not None: - return style_factory() - if style_config.startswith('{'): - # Most likely a style specification from the command line. - config = _CreateConfigParserFromConfigString(style_config) - else: - # Unknown config name: assume it's a file name then. - config = _CreateConfigParserFromConfigFile(style_config) - return _CreateStyleFromConfigParser(config) - - -def _CreateConfigParserFromConfigDict(config_dict): - config = py3compat.ConfigParser() - config.add_section('style') - for key, value in config_dict.items(): - config.set('style', key, str(value)) - return config - - -def _CreateConfigParserFromConfigString(config_string): - """Given a config string from the command line, return a config parser.""" - if config_string[0] != '{' or config_string[-1] != '}': - raise StyleConfigError( - "Invalid style dict syntax: '{}'.".format(config_string)) - config = py3compat.ConfigParser() - config.add_section('style') - for key, value, _ in re.findall( - r'([a-zA-Z0-9_]+)\s*[:=]\s*' - r'(?:' - r'((?P[\'"]).*?(?P=quote)|' - r'[a-zA-Z0-9_]+)' - r')', config_string): # yapf: disable - config.set('style', key, value) - return config - - -def _CreateConfigParserFromConfigFile(config_filename): - """Read the file and return a ConfigParser object.""" - if not os.path.exists(config_filename): - # Provide a more meaningful error here. - raise StyleConfigError( - '"{0}" is not a valid style or file path'.format(config_filename)) - with open(config_filename) as style_file: + def GlobalStyles(): + for style, _ in _DEFAULT_STYLE_TO_FACTORY: + yield style + + def_style = False + if style_config is None: + for style in GlobalStyles(): + if _style == style: + def_style = True + break + if not def_style: + return _style + return _GLOBAL_STYLE_FACTORY() + + if isinstance( style_config, dict ): + config = _CreateConfigParserFromConfigDict( style_config ) + elif isinstance( style_config, py3compat.basestring ): + style_factory = _STYLE_NAME_TO_FACTORY.get( style_config.lower() ) + if style_factory is not None: + return style_factory() + if style_config.startswith( '{' ): + # Most likely a style specification from the command line. + config = _CreateConfigParserFromConfigString( style_config ) + else: + # Unknown config name: assume it's a file name then. + config = _CreateConfigParserFromConfigFile( style_config ) + return _CreateStyleFromConfigParser( config ) + + +def _CreateConfigParserFromConfigDict( config_dict ): config = py3compat.ConfigParser() - if config_filename.endswith(PYPROJECT_TOML): - try: - import toml - except ImportError: - raise errors.YapfError( - "toml package is needed for using pyproject.toml as a " - "configuration file") - - pyproject_toml = toml.load(style_file) - style_dict = pyproject_toml.get("tool", {}).get("yapf", None) - if style_dict is None: - raise StyleConfigError( - 'Unable to find section [tool.yapf] in {0}'.format(config_filename)) - config.add_section('style') - for k, v in style_dict.items(): - config.set('style', k, str(v)) - return config - - config.read_file(style_file) - if config_filename.endswith(SETUP_CONFIG): - if not config.has_section('yapf'): - raise StyleConfigError( - 'Unable to find section [yapf] in {0}'.format(config_filename)) - return config + config.add_section( 'style' ) + for key, value in config_dict.items(): + config.set( 'style', key, str( value ) ) + return config - if config_filename.endswith(LOCAL_STYLE): - if not config.has_section('style'): - raise StyleConfigError( - 'Unable to find section [style] in {0}'.format(config_filename)) - return config - if not config.has_section('style'): - raise StyleConfigError( - 'Unable to find section [style] in {0}'.format(config_filename)) +def _CreateConfigParserFromConfigString( config_string ): + """Given a config string from the command line, return a config parser.""" + if config_string[ 0 ] != '{' or config_string[ -1 ] != '}': + raise StyleConfigError( + "Invalid style dict syntax: '{}'.".format( config_string ) ) + config = py3compat.ConfigParser() + config.add_section( 'style' ) + for key, value, _ in re.findall( + r'([a-zA-Z0-9_]+)\s*[:=]\s*' + r'(?:' + r'((?P[\'"]).*?(?P=quote)|' + r'[a-zA-Z0-9_]+)' + r')', config_string): # yapf: disable + config.set( 'style', key, value ) return config -def _CreateStyleFromConfigParser(config): - """Create a style dict from a configuration file. +def _CreateConfigParserFromConfigFile( config_filename ): + """Read the file and return a ConfigParser object.""" + if not os.path.exists( config_filename ): + # Provide a more meaningful error here. + raise StyleConfigError( + '"{0}" is not a valid style or file path'.format( config_filename ) ) + with open( config_filename ) as style_file: + config = py3compat.ConfigParser() + if config_filename.endswith( PYPROJECT_TOML ): + try: + import toml + except ImportError: + raise errors.YapfError( + "toml package is needed for using pyproject.toml as a " + "configuration file" ) + + pyproject_toml = toml.load( style_file ) + style_dict = pyproject_toml.get( "tool", {} ).get( "yapf", None ) + if style_dict is None: + raise StyleConfigError( + 'Unable to find section [tool.yapf] in {0}'.format( + config_filename ) ) + config.add_section( 'style' ) + for k, v in style_dict.items(): + config.set( 'style', k, str( v ) ) + return config + + config.read_file( style_file ) + if config_filename.endswith( SETUP_CONFIG ): + if not config.has_section( 'yapf' ): + raise StyleConfigError( + 'Unable to find section [yapf] in {0}'.format( config_filename ) ) + return config + + if config_filename.endswith( LOCAL_STYLE ): + if not config.has_section( 'style' ): + raise StyleConfigError( + 'Unable to find section [style] in {0}'.format( config_filename ) ) + return config + + if not config.has_section( 'style' ): + raise StyleConfigError( + 'Unable to find section [style] in {0}'.format( config_filename ) ) + return config + + +def _CreateStyleFromConfigParser( config ): + """Create a style dict from a configuration file. Arguments: config: a ConfigParser object. @@ -821,45 +868,45 @@ def _CreateStyleFromConfigParser(config): Raises: StyleConfigError: if an unknown style option was encountered. """ - # Initialize the base style. - section = 'yapf' if config.has_section('yapf') else 'style' - if config.has_option('style', 'based_on_style'): - based_on = config.get('style', 'based_on_style').lower() - base_style = _STYLE_NAME_TO_FACTORY[based_on]() - elif config.has_option('yapf', 'based_on_style'): - based_on = config.get('yapf', 'based_on_style').lower() - base_style = _STYLE_NAME_TO_FACTORY[based_on]() - else: - base_style = _GLOBAL_STYLE_FACTORY() - - # Read all options specified in the file and update the style. - for option, value in config.items(section): - if option.lower() == 'based_on_style': - # Now skip this one - we've already handled it and it's not one of the - # recognized style options. - continue - option = option.upper() - if option not in _STYLE_OPTION_VALUE_CONVERTER: - raise StyleConfigError('Unknown style option "{0}"'.format(option)) - try: - base_style[option] = _STYLE_OPTION_VALUE_CONVERTER[option](value) - except ValueError: - raise StyleConfigError("'{}' is not a valid setting for {}.".format( - value, option)) - return base_style + # Initialize the base style. + section = 'yapf' if config.has_section( 'yapf' ) else 'style' + if config.has_option( 'style', 'based_on_style' ): + based_on = config.get( 'style', 'based_on_style' ).lower() + base_style = _STYLE_NAME_TO_FACTORY[ based_on ]() + elif config.has_option( 'yapf', 'based_on_style' ): + based_on = config.get( 'yapf', 'based_on_style' ).lower() + base_style = _STYLE_NAME_TO_FACTORY[ based_on ]() + else: + base_style = _GLOBAL_STYLE_FACTORY() + + # Read all options specified in the file and update the style. + for option, value in config.items( section ): + if option.lower() == 'based_on_style': + # Now skip this one - we've already handled it and it's not one of the + # recognized style options. + continue + option = option.upper() + if option not in _STYLE_OPTION_VALUE_CONVERTER: + raise StyleConfigError( 'Unknown style option "{0}"'.format( option ) ) + try: + base_style[ option ] = _STYLE_OPTION_VALUE_CONVERTER[ option ]( value ) + except ValueError: + raise StyleConfigError( + "'{}' is not a valid setting for {}.".format( value, option ) ) + return base_style # The default style - used if yapf is not invoked without specifically # requesting a formatting style. -DEFAULT_STYLE = 'pep8' +DEFAULT_STYLE = 'pep8' DEFAULT_STYLE_FACTORY = CreatePEP8Style _GLOBAL_STYLE_FACTORY = CreatePEP8Style # The name of the file to use for global style definition. GLOBAL_STYLE = ( os.path.join( - os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'), 'yapf', - 'style')) + os.getenv( 'XDG_CONFIG_HOME' ) or os.path.expanduser( '~/.config' ), 'yapf', + 'style' ) ) # The name of the file to use for directory-local style definition. LOCAL_STYLE = '.style.yapf' @@ -876,4 +923,4 @@ def _CreateStyleFromConfigParser(config): # Refactor this so that the style is passed around through yapf rather than # being global. _style = None -SetGlobalStyle(_GLOBAL_STYLE_FACTORY()) +SetGlobalStyle( _GLOBAL_STYLE_FACTORY() ) diff --git a/yapf/yapflib/subtypes.py b/yapf/yapflib/subtypes.py index b4b7efe75..e675c41c1 100644 --- a/yapf/yapflib/subtypes.py +++ b/yapf/yapflib/subtypes.py @@ -13,28 +13,28 @@ # limitations under the License. """Token subtypes used to improve formatting.""" -NONE = 0 -UNARY_OPERATOR = 1 -BINARY_OPERATOR = 2 -SUBSCRIPT_COLON = 3 -SUBSCRIPT_BRACKET = 4 -DEFAULT_OR_NAMED_ASSIGN = 5 +NONE = 0 +UNARY_OPERATOR = 1 +BINARY_OPERATOR = 2 +SUBSCRIPT_COLON = 3 +SUBSCRIPT_BRACKET = 4 +DEFAULT_OR_NAMED_ASSIGN = 5 DEFAULT_OR_NAMED_ASSIGN_ARG_LIST = 6 -VARARGS_LIST = 7 -VARARGS_STAR = 8 -KWARGS_STAR_STAR = 9 -ASSIGN_OPERATOR = 10 -DICTIONARY_KEY = 11 -DICTIONARY_KEY_PART = 12 -DICTIONARY_VALUE = 13 -DICT_SET_GENERATOR = 14 -COMP_EXPR = 15 -COMP_FOR = 16 -COMP_IF = 17 -FUNC_DEF = 18 -DECORATOR = 19 -TYPED_NAME = 20 -TYPED_NAME_ARG_LIST = 21 -SIMPLE_EXPRESSION = 22 -PARAMETER_START = 23 -PARAMETER_STOP = 24 +VARARGS_LIST = 7 +VARARGS_STAR = 8 +KWARGS_STAR_STAR = 9 +ASSIGN_OPERATOR = 10 +DICTIONARY_KEY = 11 +DICTIONARY_KEY_PART = 12 +DICTIONARY_VALUE = 13 +DICT_SET_GENERATOR = 14 +COMP_EXPR = 15 +COMP_FOR = 16 +COMP_IF = 17 +FUNC_DEF = 18 +DECORATOR = 19 +TYPED_NAME = 20 +TYPED_NAME_ARG_LIST = 21 +SIMPLE_EXPRESSION = 22 +PARAMETER_START = 23 +PARAMETER_STOP = 24 diff --git a/yapf/yapflib/verifier.py b/yapf/yapflib/verifier.py index bcbe6fb6b..80cfebc08 100644 --- a/yapf/yapflib/verifier.py +++ b/yapf/yapflib/verifier.py @@ -25,13 +25,13 @@ import textwrap -class InternalError(Exception): - """Internal error in verifying formatted code.""" - pass +class InternalError( Exception ): + """Internal error in verifying formatted code.""" + pass -def VerifyCode(code): - """Verify that the reformatted code is syntactically correct. +def VerifyCode( code ): + """Verify that the reformatted code is syntactically correct. Arguments: code: (unicode) The reformatted code snippet. @@ -39,55 +39,57 @@ def VerifyCode(code): Raises: SyntaxError if the code was reformatted incorrectly. """ - try: - compile(textwrap.dedent(code).encode('UTF-8'), '', 'exec') - except SyntaxError: try: - ast.parse(textwrap.dedent(code.lstrip('\n')).lstrip(), '', 'exec') + compile( textwrap.dedent( code ).encode( 'UTF-8' ), '', 'exec' ) except SyntaxError: - try: - normalized_code = _NormalizeCode(code) - compile(normalized_code.encode('UTF-8'), '', 'exec') - except SyntaxError: - raise InternalError(sys.exc_info()[1]) + try: + ast.parse( + textwrap.dedent( code.lstrip( '\n' ) ).lstrip(), '', 'exec' ) + except SyntaxError: + try: + normalized_code = _NormalizeCode( code ) + compile( normalized_code.encode( 'UTF-8' ), '', 'exec' ) + except SyntaxError: + raise InternalError( sys.exc_info()[ 1 ] ) -def _NormalizeCode(code): - """Make sure that the code snippet is compilable.""" - code = textwrap.dedent(code.lstrip('\n')).lstrip() +def _NormalizeCode( code ): + """Make sure that the code snippet is compilable.""" + code = textwrap.dedent( code.lstrip( '\n' ) ).lstrip() - # Split the code to lines and get rid of all leading full-comment lines as - # they can mess up the normalization attempt. - lines = code.split('\n') - i = 0 - for i, line in enumerate(lines): - line = line.strip() - if line and not line.startswith('#'): - break - code = '\n'.join(lines[i:]) + '\n' + # Split the code to lines and get rid of all leading full-comment lines as + # they can mess up the normalization attempt. + lines = code.split( '\n' ) + i = 0 + for i, line in enumerate( lines ): + line = line.strip() + if line and not line.startswith( '#' ): + break + code = '\n'.join( lines[ i : ] ) + '\n' - if re.match(r'(if|while|for|with|def|class|async|await)\b', code): - code += '\n pass' - elif re.match(r'(elif|else)\b', code): - try: - try_code = 'if True:\n pass\n' + code + '\n pass' - ast.parse( - textwrap.dedent(try_code.lstrip('\n')).lstrip(), '', 'exec') - code = try_code - except SyntaxError: - # The assumption here is that the code is on a single line. - code = 'if True: pass\n' + code - elif code.startswith('@'): - code += '\ndef _():\n pass' - elif re.match(r'try\b', code): - code += '\n pass\nexcept:\n pass' - elif re.match(r'(except|finally)\b', code): - code = 'try:\n pass\n' + code + '\n pass' - elif re.match(r'(return|yield)\b', code): - code = 'def _():\n ' + code - elif re.match(r'(continue|break)\b', code): - code = 'while True:\n ' + code - elif re.match(r'print\b', code): - code = 'from __future__ import print_function\n' + code + if re.match( r'(if|while|for|with|def|class|async|await)\b', code ): + code += '\n pass' + elif re.match( r'(elif|else)\b', code ): + try: + try_code = 'if True:\n pass\n' + code + '\n pass' + ast.parse( + textwrap.dedent( try_code.lstrip( '\n' ) ).lstrip(), '', + 'exec' ) + code = try_code + except SyntaxError: + # The assumption here is that the code is on a single line. + code = 'if True: pass\n' + code + elif code.startswith( '@' ): + code += '\ndef _():\n pass' + elif re.match( r'try\b', code ): + code += '\n pass\nexcept:\n pass' + elif re.match( r'(except|finally)\b', code ): + code = 'try:\n pass\n' + code + '\n pass' + elif re.match( r'(return|yield)\b', code ): + code = 'def _():\n ' + code + elif re.match( r'(continue|break)\b', code ): + code = 'while True:\n ' + code + elif re.match( r'print\b', code ): + code = 'from __future__ import print_function\n' + code - return code + '\n' + return code + '\n' diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index c17451434..e8ae26e87 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -51,14 +51,15 @@ from yapf.yapflib import style -def FormatFile(filename, - style_config=None, - lines=None, - print_diff=False, - verify=False, - in_place=False, - logger=None): - """Format a single Python file and return the formatted code. +def FormatFile( + filename, + style_config = None, + lines = None, + print_diff = False, + verify = False, + in_place = False, + logger = None ): + """Format a single Python file and return the formatted code. Arguments: filename: (unicode) The file to reformat. @@ -84,33 +85,33 @@ def FormatFile(filename, IOError: raised if there was an error reading the file. ValueError: raised if in_place and print_diff are both specified. """ - _CheckPythonVersion() - - if in_place and print_diff: - raise ValueError('Cannot pass both in_place and print_diff.') - - original_source, newline, encoding = ReadFile(filename, logger) - reformatted_source, changed = FormatCode( - original_source, - style_config=style_config, - filename=filename, - lines=lines, - print_diff=print_diff, - verify=verify) - if reformatted_source.rstrip('\n'): - lines = reformatted_source.rstrip('\n').split('\n') - reformatted_source = newline.join(iter(lines)) + newline - if in_place: - if original_source and original_source != reformatted_source: - file_resources.WriteReformattedCode(filename, reformatted_source, - encoding, in_place) - return None, encoding, changed - - return reformatted_source, encoding, changed - - -def FormatTree(tree, style_config=None, lines=None, verify=False): - """Format a parsed lib2to3 pytree. + _CheckPythonVersion() + + if in_place and print_diff: + raise ValueError( 'Cannot pass both in_place and print_diff.' ) + + original_source, newline, encoding = ReadFile( filename, logger ) + reformatted_source, changed = FormatCode( + original_source, + style_config = style_config, + filename = filename, + lines = lines, + print_diff = print_diff, + verify = verify ) + if reformatted_source.rstrip( '\n' ): + lines = reformatted_source.rstrip( '\n' ).split( '\n' ) + reformatted_source = newline.join( iter( lines ) ) + newline + if in_place: + if original_source and original_source != reformatted_source: + file_resources.WriteReformattedCode( + filename, reformatted_source, encoding, in_place ) + return None, encoding, changed + + return reformatted_source, encoding, changed + + +def FormatTree( tree, style_config = None, lines = None, verify = False ): + """Format a parsed lib2to3 pytree. This provides an alternative entry point to YAPF. @@ -128,33 +129,34 @@ def FormatTree(tree, style_config=None, lines=None, verify=False): Returns: The source formatted according to the given formatting style. """ - _CheckPythonVersion() - style.SetGlobalStyle(style.CreateStyleFromConfig(style_config)) - - # Run passes on the tree, modifying it in place. - comment_splicer.SpliceComments(tree) - continuation_splicer.SpliceContinuations(tree) - subtype_assigner.AssignSubtypes(tree) - identify_container.IdentifyContainers(tree) - split_penalty.ComputeSplitPenalties(tree) - blank_line_calculator.CalculateBlankLines(tree) - - llines = pytree_unwrapper.UnwrapPyTree(tree) - for lline in llines: - lline.CalculateFormattingInformation() - - lines = _LineRangesToSet(lines) - _MarkLinesToFormat(llines, lines) - return reformatter.Reformat(_SplitSemicolons(llines), verify, lines) - - -def FormatCode(unformatted_source, - filename='', - style_config=None, - lines=None, - print_diff=False, - verify=False): - """Format a string of Python code. + _CheckPythonVersion() + style.SetGlobalStyle( style.CreateStyleFromConfig( style_config ) ) + + # Run passes on the tree, modifying it in place. + comment_splicer.SpliceComments( tree ) + continuation_splicer.SpliceContinuations( tree ) + subtype_assigner.AssignSubtypes( tree ) + identify_container.IdentifyContainers( tree ) + split_penalty.ComputeSplitPenalties( tree ) + blank_line_calculator.CalculateBlankLines( tree ) + + llines = pytree_unwrapper.UnwrapPyTree( tree ) + for lline in llines: + lline.CalculateFormattingInformation() + + lines = _LineRangesToSet( lines ) + _MarkLinesToFormat( llines, lines ) + return reformatter.Reformat( _SplitSemicolons( llines ), verify, lines ) + + +def FormatCode( + unformatted_source, + filename = '', + style_config = None, + lines = None, + print_diff = False, + verify = False ): + """Format a string of Python code. This provides an alternative entry point to YAPF. @@ -176,39 +178,39 @@ def FormatCode(unformatted_source, Tuple of (reformatted_source, changed). reformatted_source conforms to the desired formatting style. changed is True if the source changed. """ - try: - tree = pytree_utils.ParseCodeToTree(unformatted_source) - except Exception as e: - e.filename = filename - raise errors.YapfError(errors.FormatErrorMsg(e)) + try: + tree = pytree_utils.ParseCodeToTree( unformatted_source ) + except Exception as e: + e.filename = filename + raise errors.YapfError( errors.FormatErrorMsg( e ) ) - reformatted_source = FormatTree( - tree, style_config=style_config, lines=lines, verify=verify) + reformatted_source = FormatTree( + tree, style_config = style_config, lines = lines, verify = verify ) - if unformatted_source == reformatted_source: - return '' if print_diff else reformatted_source, False + if unformatted_source == reformatted_source: + return '' if print_diff else reformatted_source, False - code_diff = _GetUnifiedDiff( - unformatted_source, reformatted_source, filename=filename) + code_diff = _GetUnifiedDiff( + unformatted_source, reformatted_source, filename = filename ) - if print_diff: - return code_diff, code_diff.strip() != '' # pylint: disable=g-explicit-bool-comparison # noqa + if print_diff: + return code_diff, code_diff.strip() != '' # pylint: disable=g-explicit-bool-comparison # noqa - return reformatted_source, True + return reformatted_source, True -def _CheckPythonVersion(): # pragma: no cover - errmsg = 'yapf is only supported for Python 2.7 or 3.6+' - if sys.version_info[0] == 2: - if sys.version_info[1] < 7: - raise RuntimeError(errmsg) - elif sys.version_info[0] == 3: - if sys.version_info[1] < 6: - raise RuntimeError(errmsg) +def _CheckPythonVersion(): # pragma: no cover + errmsg = 'yapf is only supported for Python 2.7 or 3.6+' + if sys.version_info[ 0 ] == 2: + if sys.version_info[ 1 ] < 7: + raise RuntimeError( errmsg ) + elif sys.version_info[ 0 ] == 3: + if sys.version_info[ 1 ] < 6: + raise RuntimeError( errmsg ) -def ReadFile(filename, logger=None): - """Read the contents of the file. +def ReadFile( filename, logger = None ): + """Read the contents of the file. An optional logger can be specified to emit messages to your favorite logging stream. If specified, then no exception is raised. This is external so that it @@ -224,99 +226,106 @@ def ReadFile(filename, logger=None): Raises: IOError: raised if there was an error reading the file. """ - try: - encoding = file_resources.FileEncoding(filename) - - # Preserves line endings. - with py3compat.open_with_encoding( - filename, mode='r', encoding=encoding, newline='') as fd: - lines = fd.readlines() - - line_ending = file_resources.LineEnding(lines) - source = '\n'.join(line.rstrip('\r\n') for line in lines) + '\n' - return source, line_ending, encoding - except IOError as e: # pragma: no cover - if logger: - logger(e) - e.args = (e.args[0], (filename, e.args[1][1], e.args[1][2], e.args[1][3])) - raise - except UnicodeDecodeError as e: # pragma: no cover - if logger: - logger('Could not parse %s! Consider excluding this file with --exclude.', - filename) - logger(e) - e.args = (e.args[0], (filename, e.args[1][1], e.args[1][2], e.args[1][3])) - raise - - -def _SplitSemicolons(lines): - res = [] - for line in lines: - res.extend(line.Split()) - return res + try: + encoding = file_resources.FileEncoding( filename ) + + # Preserves line endings. + with py3compat.open_with_encoding( filename, mode = 'r', encoding = encoding, + newline = '' ) as fd: + lines = fd.readlines() + + line_ending = file_resources.LineEnding( lines ) + source = '\n'.join( line.rstrip( '\r\n' ) for line in lines ) + '\n' + return source, line_ending, encoding + except IOError as e: # pragma: no cover + if logger: + logger( e ) + e.args = ( + e.args[ 0 ], + ( filename, e.args[ 1 ][ 1 ], e.args[ 1 ][ 2 ], e.args[ 1 ][ 3 ] ) ) + raise + except UnicodeDecodeError as e: # pragma: no cover + if logger: + logger( + 'Could not parse %s! Consider excluding this file with --exclude.', + filename ) + logger( e ) + e.args = ( + e.args[ 0 ], + ( filename, e.args[ 1 ][ 1 ], e.args[ 1 ][ 2 ], e.args[ 1 ][ 3 ] ) ) + raise + + +def _SplitSemicolons( lines ): + res = [] + for line in lines: + res.extend( line.Split() ) + return res DISABLE_PATTERN = r'^#.*\byapf:\s*disable\b' -ENABLE_PATTERN = r'^#.*\byapf:\s*enable\b' - - -def _LineRangesToSet(line_ranges): - """Return a set of lines in the range.""" - - if line_ranges is None: - return None - - line_set = set() - for low, high in sorted(line_ranges): - line_set.update(range(low, high + 1)) - - return line_set - - -def _MarkLinesToFormat(llines, lines): - """Skip sections of code that we shouldn't reformat.""" - if lines: - for uwline in llines: - uwline.disable = not lines.intersection( - range(uwline.lineno, uwline.last.lineno + 1)) - - # Now go through the lines and disable any lines explicitly marked as - # disabled. - index = 0 - while index < len(llines): - uwline = llines[index] - if uwline.is_comment: - if _DisableYAPF(uwline.first.value.strip()): +ENABLE_PATTERN = r'^#.*\byapf:\s*enable\b' + + +def _LineRangesToSet( line_ranges ): + """Return a set of lines in the range.""" + + if line_ranges is None: + return None + + line_set = set() + for low, high in sorted( line_ranges ): + line_set.update( range( low, high + 1 ) ) + + return line_set + + +def _MarkLinesToFormat( llines, lines ): + """Skip sections of code that we shouldn't reformat.""" + if lines: + for uwline in llines: + uwline.disable = not lines.intersection( + range( uwline.lineno, uwline.last.lineno + 1 ) ) + + # Now go through the lines and disable any lines explicitly marked as + # disabled. + index = 0 + while index < len( llines ): + uwline = llines[ index ] + if uwline.is_comment: + if _DisableYAPF( uwline.first.value.strip() ): + index += 1 + while index < len( llines ): + uwline = llines[ index ] + line = uwline.first.value.strip() + if uwline.is_comment and _EnableYAPF( line ): + if not _DisableYAPF( line ): + break + uwline.disable = True + index += 1 + elif re.search( DISABLE_PATTERN, uwline.last.value.strip(), re.IGNORECASE ): + uwline.disable = True index += 1 - while index < len(llines): - uwline = llines[index] - line = uwline.first.value.strip() - if uwline.is_comment and _EnableYAPF(line): - if not _DisableYAPF(line): - break - uwline.disable = True - index += 1 - elif re.search(DISABLE_PATTERN, uwline.last.value.strip(), re.IGNORECASE): - uwline.disable = True - index += 1 -def _DisableYAPF(line): - return (re.search(DISABLE_PATTERN, - line.split('\n')[0].strip(), re.IGNORECASE) or - re.search(DISABLE_PATTERN, - line.split('\n')[-1].strip(), re.IGNORECASE)) +def _DisableYAPF( line ): + return ( + re.search( DISABLE_PATTERN, + line.split( '\n' )[ 0 ].strip(), re.IGNORECASE ) or + re.search( DISABLE_PATTERN, + line.split( '\n' )[ -1 ].strip(), re.IGNORECASE ) ) -def _EnableYAPF(line): - return (re.search(ENABLE_PATTERN, - line.split('\n')[0].strip(), re.IGNORECASE) or - re.search(ENABLE_PATTERN, - line.split('\n')[-1].strip(), re.IGNORECASE)) +def _EnableYAPF( line ): + return ( + re.search( ENABLE_PATTERN, + line.split( '\n' )[ 0 ].strip(), re.IGNORECASE ) or + re.search( ENABLE_PATTERN, + line.split( '\n' )[ -1 ].strip(), re.IGNORECASE ) ) -def _GetUnifiedDiff(before, after, filename='code'): - """Get a unified diff of the changes. +def _GetUnifiedDiff( before, after, filename = 'code' ): + """Get a unified diff of the changes. Arguments: before: (unicode) The original source code. @@ -326,14 +335,14 @@ def _GetUnifiedDiff(before, after, filename='code'): Returns: The unified diff text. """ - before = before.splitlines() - after = after.splitlines() - return '\n'.join( - difflib.unified_diff( - before, - after, - filename, - filename, - '(original)', - '(reformatted)', - lineterm='')) + '\n' + before = before.splitlines() + after = after.splitlines() + return '\n'.join( + difflib.unified_diff( + before, + after, + filename, + filename, + '(original)', + '(reformatted)', + lineterm = '' ) ) + '\n' diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index 3bb1ce9f5..e73f1ea8a 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -90,37 +90,6 @@ def testIsMultilineString(self): pytree.Leaf(token.STRING, 'r"""hello"""'), 'STRING') self.assertTrue(tok.is_multiline_string) - #------------test argument names------------ - # fun( - # a='hello world', - # # comment, - # b='') - child1 = pytree.Leaf(token.NAME, 'a') - child2 = pytree.Leaf(token.EQUAL, '=') - child3 = pytree.Leaf(token.STRING, "'hello world'") - child4 = pytree.Leaf(token.COMMA, ',') - child5 = pytree.Leaf(token.COMMENT,'# comment') - child6 = pytree.Leaf(token.COMMA, ',') - child7 = pytree.Leaf(token.NAME, 'b') - child8 = pytree.Leaf(token.EQUAL, '=') - child9 = pytree.Leaf(token.STRING, "''") - node_type = pygram.python_grammar.symbol2number['arglist'] - node = pytree.Node(node_type, [child1, child2, child3, child4, child5, - child6, child7, child8,child9]) - subtype_assigner.AssignSubtypes(node) - - def testIsArgName(self, node=node): - tok = format_token.FormatToken(node.children[0],'NAME') - self.assertTrue(tok.is_argname) - - def testIsArgAssign(self, node=node): - tok = format_token.FormatToken(node.children[1], 'EQUAL') - self.assertTrue(tok.is_argassign) - - # test if comment inside is not argname - def testCommentNotIsArgName(self, node=node): - tok = format_token.FormatToken(node.children[4], 'COMMENT') - self.assertFalse(tok.is_argname) if __name__ == '__main__': unittest.main() diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 0eeeefdce..798dbab9a 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -3191,8 +3191,9 @@ def testAlignAssignBlankLineInbetween(self): def testAlignAssignCommentLineInbetween(self): try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{align_assignment: true,' - 'new_alignment_after_commentline = true}')) + style.CreateStyleFromConfig( + '{align_assignment: true,' + 'new_alignment_after_commentline = true}')) unformatted_code = textwrap.dedent("""\ val_first = 1 val_second += 2 @@ -3285,244 +3286,6 @@ def testAlignAssignWithOnlyOneAssignmentLine(self): finally: style.SetGlobalStyle(style.CreateYapfStyle()) - ########## for Align_ArgAssign()########### - def testAlignArgAssignTypedName(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig('{align_argument_assignment: true,' - 'split_before_first_argument: true}')) - unformatted_code = textwrap.dedent("""\ -def f1( - self, - *, - app_name:str="", - server=None, - main_app=None, - db: Optional[NemDB]=None, - root: Optional[str]="", - conf: Optional[dict]={1, 2}, - ini_section: str="" -): pass -""") - expected_formatted_code = textwrap.dedent("""\ -def f1( - self, - *, - app_name: str = "", - server =None, - main_app =None, - db: Optional[NemDB] = None, - root: Optional[str] = "", - conf: Optional[dict] = {1, 2}, - ini_section: str = ""): - pass -""") - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) - finally: - style.SetGlobalStyle(style.CreateYapfStyle()) - - # test both object/nested argument list with newlines and - # argument without assignment in between - def testAlignArgAssignNestedArglistInBetween(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig('{align_argument_assignment: true}')) - unformatted_code = textwrap.dedent("""\ -arglist = test( - first_argument='', - second_argument=fun( - self, role=None, client_name='', client_id=1, very_long_long_long_long_long='' - ), - third_argument=3, - fourth_argument=4 -) -""") - expected_formatted_code = textwrap.dedent("""\ -arglist = test( - first_argument ='', - second_argument =fun( - self, - role =None, - client_name ='', - client_id =1, - very_long_long_long_long_long =''), - third_argument =3, - fourth_argument =4) -""") - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) - finally: - style.SetGlobalStyle(style.CreateYapfStyle()) - - # start new alignment after comment line in between - def testAlignArgAssignCommentLineInBetween(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig('{align_argument_assignment: true,' - 'new_alignment_after_commentline:true}')) - unformatted_code = textwrap.dedent("""\ -arglist = test( - client_id=0, - username_id=1, - # comment - user_name='xxxxxxxxxxxxxxxxxxxxx' -) -""") - expected_formatted_code = textwrap.dedent("""\ -arglist = test( - client_id =0, - username_id =1, - # comment - user_name ='xxxxxxxxxxxxxxxxxxxxx') -""") - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) - finally: - style.SetGlobalStyle(style.CreateYapfStyle()) - - def testAlignArgAssignWithOnlyFirstArgOnNewline(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig('{align_argument_assignment: true}')) - unformatted_code = textwrap.dedent("""\ -arglist = self.get_data_from_excelsheet( - client_id=0, username_id=1, user_name='xxxxxxxxxxxxxxxxxxxx') -""") - expected_formatted_code = unformatted_code - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) - finally: - style.SetGlobalStyle(style.CreateYapfStyle()) - - def testAlignArgAssignArgumentsCanFitInOneLine(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig('{align_argument_assignment: true}')) - unformatted_code = textwrap.dedent("""\ -def function( - first_argument_xxxxxx =(0,), - second_argument =None -) -> None: - pass -""") - expected_formatted_code = textwrap.dedent("""\ -def function(first_argument_xxxxxx=(0,), second_argument=None) -> None: - pass -""") - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) - finally: - style.SetGlobalStyle(style.CreateYapfStyle()) - - ########for align dictionary colons######### - def testAlignDictColonNestedDictInBetween(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig('{align_dict_colon: true}')) - unformatted_code = textwrap.dedent("""\ -fields = [{"type": "text","required": True,"html": {"attr": 'style="width: 250px;" maxlength="30"',"page": 0,}, - "list" : [1, 2, 3, 4]}] -""") - expected_formatted_code = textwrap.dedent("""\ -fields = [{ - "type" : "text", - "required" : True, - "html" : { - "attr" : 'style="width: 250px;" maxlength="30"', - "page" : 0, - }, - "list" : [1, 2, 3, 4] -}] -""") - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) - finally: - style.SetGlobalStyle(style.CreateYapfStyle()) - - def testAlignDictColonCommentLineInBetween(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig('{align_dict_colon: true,' - 'new_alignment_after_commentline: true}')) - unformatted_code = textwrap.dedent("""\ -fields = [{ - "type": "text", - "required": True, - # comment - "list": [1, 2, 3, 4]}] -""") - expected_formatted_code = textwrap.dedent("""\ -fields = [{ - "type" : "text", - "required" : True, - # comment - "list" : [1, 2, 3, 4] -}] -""") - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) - finally: - style.SetGlobalStyle(style.CreateYapfStyle()) - - def testAlignDictColonLargerExistingSpacesBefore(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig('{align_dict_colon: true}')) - unformatted_code = textwrap.dedent("""\ -fields = [{ - "type" : "text", - "required" : True, - "list" : [1, 2, 3, 4], -}] -""") - expected_formatted_code = textwrap.dedent("""\ -fields = [{ - "type" : "text", - "required" : True, - "list" : [1, 2, 3, 4], -}] -""") - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) - finally: - style.SetGlobalStyle(style.CreateYapfStyle()) - - def testAlignDictColonCommentAfterOpenBracket(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig('{align_dict_colon: true}')) - unformatted_code = textwrap.dedent("""\ -fields = [{ - # comment - "type": "text", - "required": True, - "list": [1, 2, 3, 4]}] -""") - expected_formatted_code = textwrap.dedent("""\ -fields = [{ - # comment - "type" : "text", - "required" : True, - "list" : [1, 2, 3, 4] -}] -""") - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) - finally: - style.SetGlobalStyle(style.CreateYapfStyle()) - - - if __name__ == '__main__': unittest.main() diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index 97f9cd3ac..8616169c9 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -129,87 +129,6 @@ def testFuncCallWithDefaultAssign(self): ], ]) - #----test comment subtype inside the argument list---- - def testCommentSubtypesInsideArglist(self): - code = textwrap.dedent("""\ - foo( - # comment - x, - a='hello world') - """) - llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes(llines, [ - [ - ('foo', {subtypes.NONE}), - ('(', {subtypes.NONE}), - ('# comment', {subtypes.NONE, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST}), - ('x', { - subtypes.NONE, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST}), - (',', {subtypes.NONE}), - ('a', { - subtypes.NONE, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST}), - ('=', {subtypes.DEFAULT_OR_NAMED_ASSIGN}), - ("'hello world'", {subtypes.NONE}), - (')', {subtypes.NONE}), - ], - ]) - - # ----test typed arguments subtypes------ - def testTypedArgumentsInsideArglist(self): - code = textwrap.dedent("""\ -def foo( - self, - preprocess: Callable[[str], str] = identity - ): pass -""") - llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes(llines, [ - [ - ('def', {subtypes.NONE}), - ('foo', {subtypes.FUNC_DEF}), - ('(', {subtypes.NONE}), - ('self', {subtypes.NONE, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - subtypes.PARAMETER_START, - subtypes.PARAMETER_STOP}), - (',', {subtypes.NONE}), - ('preprocess', { - subtypes.NONE, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - subtypes.PARAMETER_START, - subtypes.TYPED_NAME_ARG_LIST}), - (':', { - subtypes.TYPED_NAME, - subtypes.TYPED_NAME_ARG_LIST}), - ('Callable', {subtypes.TYPED_NAME_ARG_LIST}), - ('[', { - subtypes.SUBSCRIPT_BRACKET, - subtypes.TYPED_NAME_ARG_LIST}), - ('[', {subtypes.TYPED_NAME_ARG_LIST}), - ('str', {subtypes.TYPED_NAME_ARG_LIST}), - (']', {subtypes.TYPED_NAME_ARG_LIST}), - (',', {subtypes.TYPED_NAME_ARG_LIST}), - ('str', {subtypes.TYPED_NAME_ARG_LIST}), - (']', { - subtypes.SUBSCRIPT_BRACKET, - subtypes.TYPED_NAME_ARG_LIST}), - ('=', { - subtypes.DEFAULT_OR_NAMED_ASSIGN, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - subtypes.TYPED_NAME}), - ('identity', { - subtypes.NONE, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - subtypes.PARAMETER_STOP}), - (')', {subtypes.NONE}), - (':', {subtypes.NONE})], - [('pass', {subtypes.NONE}), - ], - ]) - def testSetComprehension(self): code = textwrap.dedent("""\ def foo(strs): From d374b7d4fb30fa8a156b972da8ac1f64a567ff6d Mon Sep 17 00:00:00 2001 From: Xiao Wang Date: Mon, 3 Oct 2022 15:53:10 +0200 Subject: [PATCH 572/719] run the assignment align over the yapf codes --- yapf/__init__.py | 542 ++--- yapf/pyparser/pyparser.py | 143 +- yapf/pyparser/pyparser_utils.py | 92 +- yapf/pyparser/split_penalty_visitor.py | 1777 +++++++++-------- yapf/pytree/blank_line_calculator.py | 233 +-- yapf/pytree/comment_splicer.py | 512 +++-- yapf/pytree/continuation_splicer.py | 40 +- yapf/pytree/pytree_unwrapper.py | 531 ++--- yapf/pytree/pytree_utils.py | 289 +-- yapf/pytree/pytree_visitor.py | 90 +- yapf/pytree/split_penalty.py | 1102 ++++++----- yapf/pytree/subtype_assigner.py | 864 ++++---- yapf/third_party/yapf_diff/yapf_diff.py | 198 +- yapf/yapflib/errors.py | 21 +- yapf/yapflib/file_resources.py | 406 ++-- yapf/yapflib/format_decision_state.py | 2075 ++++++++++---------- yapf/yapflib/format_token.py | 489 ++--- yapf/yapflib/identify_container.py | 60 +- yapf/yapflib/line_joiner.py | 84 +- yapf/yapflib/logical_line.py | 1146 ++++++----- yapf/yapflib/object_state.py | 296 +-- yapf/yapflib/py3compat.py | 158 +- yapf/yapflib/reformatter.py | 1436 +++++++------- yapf/yapflib/style.py | 966 ++++----- yapf/yapflib/verifier.py | 102 +- yapf/yapflib/yapf_api.py | 356 ++-- yapftests/blank_line_calculator_test.py | 69 +- yapftests/comment_splicer_test.py | 62 +- yapftests/file_resources_test.py | 137 +- yapftests/format_decision_state_test.py | 8 +- yapftests/line_joiner_test.py | 18 +- yapftests/logical_line_test.py | 22 +- yapftests/main_test.py | 11 +- yapftests/pytree_unwrapper_test.py | 273 +-- yapftests/pytree_utils_test.py | 62 +- yapftests/pytree_visitor_test.py | 10 +- yapftests/reformatter_basic_test.py | 983 ++++++---- yapftests/reformatter_buganizer_test.py | 541 +++-- yapftests/reformatter_facebook_test.py | 95 +- yapftests/reformatter_pep8_test.py | 274 ++- yapftests/reformatter_python3_test.py | 109 +- yapftests/reformatter_style_config_test.py | 54 +- yapftests/reformatter_verify_test.py | 26 +- yapftests/split_penalty_test.py | 272 +-- yapftests/style_test.py | 57 +- yapftests/subtype_assigner_test.py | 421 ++-- yapftests/utils.py | 34 +- yapftests/yapf_test.py | 500 +++-- yapftests/yapf_test_helper.py | 2 +- 49 files changed, 9393 insertions(+), 8655 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index e8825c1cb..2b69c1ddc 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -41,8 +41,8 @@ __version__ = '0.32.0' -def main( argv ): - """Main program. +def main(argv): + """Main program. Arguments: argv: command-line arguments, such as sys.argv (including the program name @@ -55,116 +55,116 @@ def main( argv ): Raises: YapfError: if none of the supplied files were Python files. """ - parser = _BuildParser() - args = parser.parse_args( argv[ 1 : ] ) - style_config = args.style - - if args.style_help: - _PrintHelp( args ) - return 0 - - if args.lines and len( args.files ) > 1: - parser.error( 'cannot use -l/--lines with more than one file' ) - - lines = _GetLines( args.lines ) if args.lines is not None else None - if not args.files: - # No arguments specified. Read code from stdin. - if args.in_place or args.diff: - parser.error( - 'cannot use --in-place or --diff flags when reading ' - 'from stdin' ) - - original_source = [] - while True: - # Test that sys.stdin has the "closed" attribute. When using pytest, it - # co-opts sys.stdin, which makes the "main_tests.py" fail. This is gross. - if hasattr( sys.stdin, "closed" ) and sys.stdin.closed: - break - try: - # Use 'raw_input' instead of 'sys.stdin.read', because otherwise the - # user will need to hit 'Ctrl-D' more than once if they're inputting - # the program by hand. 'raw_input' throws an EOFError exception if - # 'Ctrl-D' is pressed, which makes it easy to bail out of this loop. - original_source.append( py3compat.raw_input() ) - except EOFError: - break - except KeyboardInterrupt: - return 1 - - if style_config is None and not args.no_local_style: - style_config = file_resources.GetDefaultStyleForDir( os.getcwd() ) - - source = [ line.rstrip() for line in original_source ] - source[ 0 ] = py3compat.removeBOM( source[ 0 ] ) - - try: - reformatted_source, _ = yapf_api.FormatCode( - py3compat.unicode( '\n'.join( source ) + '\n' ), - filename = '', - style_config = style_config, - lines = lines, - verify = args.verify ) - except errors.YapfError: - raise - except Exception as e: - raise errors.YapfError( errors.FormatErrorMsg( e ) ) - - file_resources.WriteReformattedCode( '', reformatted_source ) - return 0 - - # Get additional exclude patterns from ignorefile - exclude_patterns_from_ignore_file = file_resources.GetExcludePatternsForDir( - os.getcwd() ) - - files = file_resources.GetCommandLineFiles( - args.files, args.recursive, - ( args.exclude or [] ) + exclude_patterns_from_ignore_file ) - if not files: - raise errors.YapfError( 'input filenames did not match any python files' ) - - changed = FormatFiles( - files, - lines, - style_config = args.style, - no_local_style = args.no_local_style, - in_place = args.in_place, - print_diff = args.diff, - verify = args.verify, - parallel = args.parallel, - quiet = args.quiet, - verbose = args.verbose ) - return 1 if changed and ( args.diff or args.quiet ) else 0 - - -def _PrintHelp( args ): - """Prints the help menu.""" - - if args.style is None and not args.no_local_style: - args.style = file_resources.GetDefaultStyleForDir( os.getcwd() ) - style.SetGlobalStyle( style.CreateStyleFromConfig( args.style ) ) - print( '[style]' ) - for option, docstring in sorted( style.Help().items() ): - for line in docstring.splitlines(): - print( '#', line and ' ' or '', line, sep = '' ) - option_value = style.Get( option ) - if isinstance( option_value, ( set, list ) ): - option_value = ', '.join( map( str, option_value ) ) - print( option.lower(), '=', option_value, sep = '' ) - print() + parser = _BuildParser() + args = parser.parse_args(argv[1:]) + style_config = args.style + + if args.style_help: + _PrintHelp(args) + return 0 + + if args.lines and len(args.files) > 1: + parser.error('cannot use -l/--lines with more than one file') + + lines = _GetLines(args.lines) if args.lines is not None else None + if not args.files: + # No arguments specified. Read code from stdin. + if args.in_place or args.diff: + parser.error( + 'cannot use --in-place or --diff flags when reading ' + 'from stdin') + + original_source = [] + while True: + # Test that sys.stdin has the "closed" attribute. When using pytest, it + # co-opts sys.stdin, which makes the "main_tests.py" fail. This is gross. + if hasattr(sys.stdin, "closed") and sys.stdin.closed: + break + try: + # Use 'raw_input' instead of 'sys.stdin.read', because otherwise the + # user will need to hit 'Ctrl-D' more than once if they're inputting + # the program by hand. 'raw_input' throws an EOFError exception if + # 'Ctrl-D' is pressed, which makes it easy to bail out of this loop. + original_source.append(py3compat.raw_input()) + except EOFError: + break + except KeyboardInterrupt: + return 1 + + if style_config is None and not args.no_local_style: + style_config = file_resources.GetDefaultStyleForDir(os.getcwd()) + + source = [line.rstrip() for line in original_source] + source[0] = py3compat.removeBOM(source[0]) + + try: + reformatted_source, _ = yapf_api.FormatCode( + py3compat.unicode('\n'.join(source) + '\n'), + filename='', + style_config=style_config, + lines=lines, + verify=args.verify) + except errors.YapfError: + raise + except Exception as e: + raise errors.YapfError(errors.FormatErrorMsg(e)) + + file_resources.WriteReformattedCode('', reformatted_source) + return 0 + + # Get additional exclude patterns from ignorefile + exclude_patterns_from_ignore_file = file_resources.GetExcludePatternsForDir( + os.getcwd()) + + files = file_resources.GetCommandLineFiles( + args.files, args.recursive, + (args.exclude or []) + exclude_patterns_from_ignore_file) + if not files: + raise errors.YapfError('input filenames did not match any python files') + + changed = FormatFiles( + files, + lines, + style_config=args.style, + no_local_style=args.no_local_style, + in_place=args.in_place, + print_diff=args.diff, + verify=args.verify, + parallel=args.parallel, + quiet=args.quiet, + verbose=args.verbose) + return 1 if changed and (args.diff or args.quiet) else 0 + + +def _PrintHelp(args): + """Prints the help menu.""" + + if args.style is None and not args.no_local_style: + args.style = file_resources.GetDefaultStyleForDir(os.getcwd()) + style.SetGlobalStyle(style.CreateStyleFromConfig(args.style)) + print('[style]') + for option, docstring in sorted(style.Help().items()): + for line in docstring.splitlines(): + print('#', line and ' ' or '', line, sep='') + option_value = style.Get(option) + if isinstance(option_value, (set, list)): + option_value = ', '.join(map(str, option_value)) + print(option.lower(), '=', option_value, sep='') + print() def FormatFiles( - filenames, - lines, - style_config = None, - no_local_style = False, - in_place = False, - print_diff = False, - verify = False, - parallel = False, - quiet = False, - verbose = False ): - """Format a list of files. + filenames, + lines, + style_config=None, + no_local_style=False, + in_place=False, + print_diff=False, + verify=False, + parallel=False, + quiet=False, + verbose=False): + """Format a list of files. Arguments: filenames: (list of unicode) A list of files to reformat. @@ -186,68 +186,68 @@ def FormatFiles( Returns: True if the source code changed in any of the files being formatted. """ - changed = False - if parallel: - import multiprocessing # pylint: disable=g-import-not-at-top - import concurrent.futures # pylint: disable=g-import-not-at-top - workers = min( multiprocessing.cpu_count(), len( filenames ) ) - with concurrent.futures.ProcessPoolExecutor( workers ) as executor: - future_formats = [ - executor.submit( - _FormatFile, filename, lines, style_config, no_local_style, - in_place, print_diff, verify, quiet, verbose ) - for filename in filenames - ] - for future in concurrent.futures.as_completed( future_formats ): - changed |= future.result() - else: - for filename in filenames: - changed |= _FormatFile( - filename, lines, style_config, no_local_style, in_place, print_diff, - verify, quiet, verbose ) - return changed + changed = False + if parallel: + import multiprocessing # pylint: disable=g-import-not-at-top + import concurrent.futures # pylint: disable=g-import-not-at-top + workers = min(multiprocessing.cpu_count(), len(filenames)) + with concurrent.futures.ProcessPoolExecutor(workers) as executor: + future_formats = [ + executor.submit( + _FormatFile, filename, lines, style_config, no_local_style, + in_place, print_diff, verify, quiet, verbose) + for filename in filenames + ] + for future in concurrent.futures.as_completed(future_formats): + changed |= future.result() + else: + for filename in filenames: + changed |= _FormatFile( + filename, lines, style_config, no_local_style, in_place, print_diff, + verify, quiet, verbose) + return changed def _FormatFile( + filename, + lines, + style_config=None, + no_local_style=False, + in_place=False, + print_diff=False, + verify=False, + quiet=False, + verbose=False): + """Format an individual file.""" + if verbose and not quiet: + print('Reformatting %s' % filename) + + if style_config is None and not no_local_style: + style_config = file_resources.GetDefaultStyleForDir( + os.path.dirname(filename)) + + try: + reformatted_code, encoding, has_change = yapf_api.FormatFile( filename, - lines, - style_config = None, - no_local_style = False, - in_place = False, - print_diff = False, - verify = False, - quiet = False, - verbose = False ): - """Format an individual file.""" - if verbose and not quiet: - print( 'Reformatting %s' % filename ) - - if style_config is None and not no_local_style: - style_config = file_resources.GetDefaultStyleForDir( - os.path.dirname( filename ) ) - - try: - reformatted_code, encoding, has_change = yapf_api.FormatFile( - filename, - in_place = in_place, - style_config = style_config, - lines = lines, - print_diff = print_diff, - verify = verify, - logger = logging.warning ) - except errors.YapfError: - raise - except Exception as e: - raise errors.YapfError( errors.FormatErrorMsg( e ) ) - - if not in_place and not quiet and reformatted_code: - file_resources.WriteReformattedCode( - filename, reformatted_code, encoding, in_place ) - return has_change - - -def _GetLines( line_strings ): - """Parses the start and end lines from a line string like 'start-end'. + in_place=in_place, + style_config=style_config, + lines=lines, + print_diff=print_diff, + verify=verify, + logger=logging.warning) + except errors.YapfError: + raise + except Exception as e: + raise errors.YapfError(errors.FormatErrorMsg(e)) + + if not in_place and not quiet and reformatted_code: + file_resources.WriteReformattedCode( + filename, reformatted_code, encoding, in_place) + return has_change + + +def _GetLines(line_strings): + """Parses the start and end lines from a line string like 'start-end'. Arguments: line_strings: (array of string) A list of strings representing a line @@ -259,117 +259,117 @@ def _GetLines( line_strings ): Raises: ValueError: If the line string failed to parse or was an invalid line range. """ - lines = [] - for line_string in line_strings: - # The 'list' here is needed by Python 3. - line = list( map( int, line_string.split( '-', 1 ) ) ) - if line[ 0 ] < 1: - raise errors.YapfError( 'invalid start of line range: %r' % line ) - if line[ 0 ] > line[ 1 ]: - raise errors.YapfError( 'end comes before start in line range: %r' % line ) - lines.append( tuple( line ) ) - return lines + lines = [] + for line_string in line_strings: + # The 'list' here is needed by Python 3. + line = list(map(int, line_string.split('-', 1))) + if line[0] < 1: + raise errors.YapfError('invalid start of line range: %r' % line) + if line[0] > line[1]: + raise errors.YapfError('end comes before start in line range: %r' % line) + lines.append(tuple(line)) + return lines def _BuildParser(): - """Constructs the parser for the command line arguments. + """Constructs the parser for the command line arguments. Returns: An ArgumentParser instance for the CLI. """ - parser = argparse.ArgumentParser( - prog = 'yapf', description = 'Formatter for Python code.' ) - parser.add_argument( - '-v', - '--version', - action = 'version', - version = '%(prog)s {}'.format( __version__ ) ) - - diff_inplace_quiet_group = parser.add_mutually_exclusive_group() - diff_inplace_quiet_group.add_argument( - '-d', - '--diff', - action = 'store_true', - help = 'print the diff for the fixed source' ) - diff_inplace_quiet_group.add_argument( - '-i', - '--in-place', - action = 'store_true', - help = 'make changes to files in place' ) - diff_inplace_quiet_group.add_argument( - '-q', - '--quiet', - action = 'store_true', - help = 'output nothing and set return value' ) - - lines_recursive_group = parser.add_mutually_exclusive_group() - lines_recursive_group.add_argument( - '-r', - '--recursive', - action = 'store_true', - help = 'run recursively over directories' ) - lines_recursive_group.add_argument( - '-l', - '--lines', - metavar = 'START-END', - action = 'append', - default = None, - help = 'range of lines to reformat, one-based' ) - - parser.add_argument( - '-e', - '--exclude', - metavar = 'PATTERN', - action = 'append', - default = None, - help = 'patterns for files to exclude from formatting' ) - parser.add_argument( - '--style', - action = 'store', - help = ( - 'specify formatting style: either a style name (for example "pep8" ' - 'or "google"), or the name of a file with style settings. The ' - 'default is pep8 unless a %s or %s or %s file located in the same ' - 'directory as the source or one of its parent directories ' - '(for stdin, the current directory is used).' % - ( style.LOCAL_STYLE, style.SETUP_CONFIG, style.PYPROJECT_TOML ) ) ) - parser.add_argument( - '--style-help', - action = 'store_true', - help = ( - 'show style settings and exit; this output can be ' - 'saved to .style.yapf to make your settings ' - 'permanent' ) ) - parser.add_argument( - '--no-local-style', - action = 'store_true', - help = "don't search for local style definition" ) - parser.add_argument( '--verify', action = 'store_true', help = argparse.SUPPRESS ) - parser.add_argument( - '-p', - '--parallel', - action = 'store_true', - help = ( - 'run YAPF in parallel when formatting multiple files. Requires ' - 'concurrent.futures in Python 2.X' ) ) - parser.add_argument( - '-vv', - '--verbose', - action = 'store_true', - help = 'print out file names while processing' ) - - parser.add_argument( - 'files', nargs = '*', help = 'reads from stdin when no files are specified.' ) - return parser - - -def run_main(): # pylint: disable=invalid-name - try: - sys.exit( main( sys.argv ) ) - except errors.YapfError as e: - sys.stderr.write( 'yapf: ' + str( e ) + '\n' ) - sys.exit( 1 ) + parser = argparse.ArgumentParser( + prog='yapf', description='Formatter for Python code.') + parser.add_argument( + '-v', + '--version', + action='version', + version='%(prog)s {}'.format(__version__)) + + diff_inplace_quiet_group = parser.add_mutually_exclusive_group() + diff_inplace_quiet_group.add_argument( + '-d', + '--diff', + action='store_true', + help='print the diff for the fixed source') + diff_inplace_quiet_group.add_argument( + '-i', + '--in-place', + action='store_true', + help='make changes to files in place') + diff_inplace_quiet_group.add_argument( + '-q', + '--quiet', + action='store_true', + help='output nothing and set return value') + + lines_recursive_group = parser.add_mutually_exclusive_group() + lines_recursive_group.add_argument( + '-r', + '--recursive', + action='store_true', + help='run recursively over directories') + lines_recursive_group.add_argument( + '-l', + '--lines', + metavar='START-END', + action='append', + default=None, + help='range of lines to reformat, one-based') + + parser.add_argument( + '-e', + '--exclude', + metavar='PATTERN', + action='append', + default=None, + help='patterns for files to exclude from formatting') + parser.add_argument( + '--style', + action='store', + help=( + 'specify formatting style: either a style name (for example "pep8" ' + 'or "google"), or the name of a file with style settings. The ' + 'default is pep8 unless a %s or %s or %s file located in the same ' + 'directory as the source or one of its parent directories ' + '(for stdin, the current directory is used).' % + (style.LOCAL_STYLE, style.SETUP_CONFIG, style.PYPROJECT_TOML))) + parser.add_argument( + '--style-help', + action='store_true', + help=( + 'show style settings and exit; this output can be ' + 'saved to .style.yapf to make your settings ' + 'permanent')) + parser.add_argument( + '--no-local-style', + action='store_true', + help="don't search for local style definition") + parser.add_argument('--verify', action='store_true', help=argparse.SUPPRESS) + parser.add_argument( + '-p', + '--parallel', + action='store_true', + help=( + 'run YAPF in parallel when formatting multiple files. Requires ' + 'concurrent.futures in Python 2.X')) + parser.add_argument( + '-vv', + '--verbose', + action='store_true', + help='print out file names while processing') + + parser.add_argument( + 'files', nargs='*', help='reads from stdin when no files are specified.') + return parser + + +def run_main(): # pylint: disable=invalid-name + try: + sys.exit(main(sys.argv)) + except errors.YapfError as e: + sys.stderr.write('yapf: ' + str(e) + '\n') + sys.exit(1) if __name__ == '__main__': - run_main() + run_main() diff --git a/yapf/pyparser/pyparser.py b/yapf/pyparser/pyparser.py index b6b7c50d7..b2bffa283 100644 --- a/yapf/pyparser/pyparser.py +++ b/yapf/pyparser/pyparser.py @@ -46,8 +46,8 @@ CONTINUATION = token.N_TOKENS -def ParseCode( unformatted_source, filename = '' ): - """Parse a string of Python code into logical lines. +def ParseCode(unformatted_source, filename=''): + """Parse a string of Python code into logical lines. This provides an alternative entry point to YAPF. @@ -61,27 +61,27 @@ def ParseCode( unformatted_source, filename = '' ): Raises: An exception is raised if there's an error during AST parsing. """ - if not unformatted_source.endswith( os.linesep ): - unformatted_source += os.linesep + if not unformatted_source.endswith(os.linesep): + unformatted_source += os.linesep - try: - ast_tree = ast.parse( unformatted_source, filename ) - ast.fix_missing_locations( ast_tree ) - readline = py3compat.StringIO( unformatted_source ).readline - tokens = tokenize.generate_tokens( readline ) - except Exception: - raise + try: + ast_tree = ast.parse(unformatted_source, filename) + ast.fix_missing_locations(ast_tree) + readline = py3compat.StringIO(unformatted_source).readline + tokens = tokenize.generate_tokens(readline) + except Exception: + raise - logical_lines = _CreateLogicalLines( tokens ) + logical_lines = _CreateLogicalLines(tokens) - # Process the logical lines. - split_penalty_visitor.SplitPenalty( logical_lines ).visit( ast_tree ) + # Process the logical lines. + split_penalty_visitor.SplitPenalty(logical_lines).visit(ast_tree) - return logical_lines + return logical_lines -def _CreateLogicalLines( tokens ): - """Separate tokens into logical lines. +def _CreateLogicalLines(tokens): + """Separate tokens into logical lines. Arguments: tokens: (list of tokenizer.TokenInfo) Tokens generated by tokenizer. @@ -89,58 +89,57 @@ def _CreateLogicalLines( tokens ): Returns: A list of LogicalLines. """ - logical_lines = [] - cur_logical_line = [] - prev_tok = None - depth = 0 - - for tok in tokens: - tok = py3compat.TokenInfo( *tok ) - if tok.type == tokenize.NEWLINE: - # End of a logical line. - logical_lines.append( logical_line.LogicalLine( depth, cur_logical_line ) ) - cur_logical_line = [] - prev_tok = None - elif tok.type == tokenize.INDENT: - depth += 1 - elif tok.type == tokenize.DEDENT: - depth -= 1 - elif tok.type not in { tokenize.NL, tokenize.ENDMARKER }: - if ( prev_tok and prev_tok.line.rstrip().endswith( '\\' ) and - prev_tok.start[ 0 ] < tok.start[ 0 ] ): - # Insert a token for a line continuation. - ctok = py3compat.TokenInfo( - type = CONTINUATION, - string = '\\', - start = ( prev_tok.start[ 0 ], prev_tok.start[ 1 ] + 1 ), - end = ( prev_tok.end[ 0 ], prev_tok.end[ 0 ] + 2 ), - line = prev_tok.line ) - ctok.lineno = ctok.start[ 0 ] - ctok.column = ctok.start[ 1 ] - ctok.value = '\\' - cur_logical_line.append( - format_token.FormatToken( ctok, 'CONTINUATION' ) ) - tok.lineno = tok.start[ 0 ] - tok.column = tok.start[ 1 ] - tok.value = tok.string - cur_logical_line.append( - format_token.FormatToken( tok, token.tok_name[ tok.type ] ) ) - prev_tok = tok - - # Link the FormatTokens in each line together to for a doubly linked list. - for line in logical_lines: - previous = line.first - bracket_stack = [ previous ] if previous.OpensScope() else [] - for tok in line.tokens[ 1 : ]: - tok.previous_token = previous - previous.next_token = tok - previous = tok - - # Set up the "matching_bracket" attribute. - if tok.OpensScope(): - bracket_stack.append( tok ) - elif tok.ClosesScope(): - bracket_stack[ -1 ].matching_bracket = tok - tok.matching_bracket = bracket_stack.pop() - - return logical_lines + logical_lines = [] + cur_logical_line = [] + prev_tok = None + depth = 0 + + for tok in tokens: + tok = py3compat.TokenInfo(*tok) + if tok.type == tokenize.NEWLINE: + # End of a logical line. + logical_lines.append(logical_line.LogicalLine(depth, cur_logical_line)) + cur_logical_line = [] + prev_tok = None + elif tok.type == tokenize.INDENT: + depth += 1 + elif tok.type == tokenize.DEDENT: + depth -= 1 + elif tok.type not in {tokenize.NL, tokenize.ENDMARKER}: + if (prev_tok and prev_tok.line.rstrip().endswith('\\') and + prev_tok.start[0] < tok.start[0]): + # Insert a token for a line continuation. + ctok = py3compat.TokenInfo( + type=CONTINUATION, + string='\\', + start=(prev_tok.start[0], prev_tok.start[1] + 1), + end=(prev_tok.end[0], prev_tok.end[0] + 2), + line=prev_tok.line) + ctok.lineno = ctok.start[0] + ctok.column = ctok.start[1] + ctok.value = '\\' + cur_logical_line.append(format_token.FormatToken(ctok, 'CONTINUATION')) + tok.lineno = tok.start[0] + tok.column = tok.start[1] + tok.value = tok.string + cur_logical_line.append( + format_token.FormatToken(tok, token.tok_name[tok.type])) + prev_tok = tok + + # Link the FormatTokens in each line together to for a doubly linked list. + for line in logical_lines: + previous = line.first + bracket_stack = [previous] if previous.OpensScope() else [] + for tok in line.tokens[1:]: + tok.previous_token = previous + previous.next_token = tok + previous = tok + + # Set up the "matching_bracket" attribute. + if tok.OpensScope(): + bracket_stack.append(tok) + elif tok.ClosesScope(): + bracket_stack[-1].matching_bracket = tok + tok.matching_bracket = bracket_stack.pop() + + return logical_lines diff --git a/yapf/pyparser/pyparser_utils.py b/yapf/pyparser/pyparser_utils.py index 4a37b89a9..149e0a280 100644 --- a/yapf/pyparser/pyparser_utils.py +++ b/yapf/pyparser/pyparser_utils.py @@ -29,68 +29,68 @@ """ -def GetTokens( logical_lines, node ): - """Get a list of tokens within the node's range from the logical lines.""" - start = TokenStart( node ) - end = TokenEnd( node ) - tokens = [] +def GetTokens(logical_lines, node): + """Get a list of tokens within the node's range from the logical lines.""" + start = TokenStart(node) + end = TokenEnd(node) + tokens = [] - for line in logical_lines: - if line.start > end: - break - if line.start <= start or line.end >= end: - tokens.extend( GetTokensInSubRange( line.tokens, node ) ) + for line in logical_lines: + if line.start > end: + break + if line.start <= start or line.end >= end: + tokens.extend(GetTokensInSubRange(line.tokens, node)) - return tokens + return tokens -def GetTokensInSubRange( tokens, node ): - """Get a subset of tokens representing the node.""" - start = TokenStart( node ) - end = TokenEnd( node ) - tokens_in_range = [] +def GetTokensInSubRange(tokens, node): + """Get a subset of tokens representing the node.""" + start = TokenStart(node) + end = TokenEnd(node) + tokens_in_range = [] - for tok in tokens: - tok_range = ( tok.lineno, tok.column ) - if tok_range >= start and tok_range < end: - tokens_in_range.append( tok ) + for tok in tokens: + tok_range = (tok.lineno, tok.column) + if tok_range >= start and tok_range < end: + tokens_in_range.append(tok) - return tokens_in_range + return tokens_in_range -def GetTokenIndex( tokens, pos ): - """Get the index of the token at pos.""" - for index, token in enumerate( tokens ): - if ( token.lineno, token.column ) == pos: - return index +def GetTokenIndex(tokens, pos): + """Get the index of the token at pos.""" + for index, token in enumerate(tokens): + if (token.lineno, token.column) == pos: + return index - return None + return None -def GetNextTokenIndex( tokens, pos ): - """Get the index of the next token after pos.""" - for index, token in enumerate( tokens ): - if ( token.lineno, token.column ) >= pos: - return index +def GetNextTokenIndex(tokens, pos): + """Get the index of the next token after pos.""" + for index, token in enumerate(tokens): + if (token.lineno, token.column) >= pos: + return index - return None + return None -def GetPrevTokenIndex( tokens, pos ): - """Get the index of the previous token before pos.""" - for index, token in enumerate( tokens ): - if index > 0 and ( token.lineno, token.column ) >= pos: - return index - 1 +def GetPrevTokenIndex(tokens, pos): + """Get the index of the previous token before pos.""" + for index, token in enumerate(tokens): + if index > 0 and (token.lineno, token.column) >= pos: + return index - 1 - return None + return None -def TokenStart( node ): - return ( node.lineno, node.col_offset ) +def TokenStart(node): + return (node.lineno, node.col_offset) -def TokenEnd( node ): - return ( node.end_lineno, node.end_col_offset ) +def TokenEnd(node): + return (node.end_lineno, node.end_col_offset) ############################################################################# @@ -98,6 +98,6 @@ def TokenEnd( node ): ############################################################################# -def AstDump( node ): - import ast - print( ast.dump( node, include_attributes = True, indent = 4 ) ) +def AstDump(node): + import ast + print(ast.dump(node, include_attributes=True, indent=4)) diff --git a/yapf/pyparser/split_penalty_visitor.py b/yapf/pyparser/split_penalty_visitor.py index 4d05558ba..946bd949f 100644 --- a/yapf/pyparser/split_penalty_visitor.py +++ b/yapf/pyparser/split_penalty_visitor.py @@ -21,896 +21,893 @@ # This is a skeleton of an AST visitor. -class SplitPenalty( ast.NodeVisitor ): - """Compute split penalties between tokens.""" - - def __init__( self, logical_lines ): - super( SplitPenalty, self ).__init__() - self.logical_lines = logical_lines - - # We never want to split before a colon or comma. - for logical_line in logical_lines: - for token in logical_line.tokens: - if token.value in frozenset( { ',', ':' } ): - token.split_penalty = split_penalty.UNBREAKABLE - - def _GetTokens( self, node ): - return pyutils.GetTokens( self.logical_lines, node ) - - ############################################################################ - # Statements # - ############################################################################ - - def visit_FunctionDef( self, node ): - # FunctionDef(name=Name, - # args=arguments( - # posonlyargs=[], - # args=[], - # vararg=[], - # kwonlyargs=[], - # kw_defaults=[], - # defaults=[]), - # body=[...], - # decorator_list=[Call_1, Call_2, ..., Call_n], - # keywords=[]) - tokens = self._GetTokens( node ) - for decorator in node.decorator_list: - # The decorator token list begins after the '@'. The body of the decorator - # is formatted like a normal "call." - decorator_range = self._GetTokens( decorator ) - # Don't split after the '@'. - decorator_range[ 0 ].split_penalty = split_penalty.UNBREAKABLE - - for token in tokens[ 1 : ]: - if token.value == '(': - break - _SetPenalty( token, split_penalty.UNBREAKABLE ) - - if node.returns: - start_index = pyutils.GetTokenIndex( - tokens, pyutils.TokenStart( node.returns ) ) - _IncreasePenalty( - tokens[ start_index - 1 : start_index + 1 ], - split_penalty.VERY_STRONGLY_CONNECTED ) - end_index = pyutils.GetTokenIndex( - tokens, pyutils.TokenEnd( node.returns ) ) - _IncreasePenalty( - tokens[ start_index + 1 : end_index ], - split_penalty.STRONGLY_CONNECTED ) - - return self.generic_visit( node ) - - def visit_AsyncFunctionDef( self, node ): - # AsyncFunctionDef(name=Name, - # args=arguments( - # posonlyargs=[], - # args=[], - # vararg=[], - # kwonlyargs=[], - # kw_defaults=[], - # defaults=[]), - # body=[...], - # decorator_list=[Expr_1, Expr_2, ..., Expr_n], - # keywords=[]) - return self.visit_FunctionDef( node ) - - def visit_ClassDef( self, node ): - # ClassDef(name=Name, - # bases=[Expr_1, Expr_2, ..., Expr_n], - # keywords=[], - # body=[], - # decorator_list=[Expr_1, Expr_2, ..., Expr_m]) - for base in node.bases: - tokens = self._GetTokens( base ) - _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) - - for decorator in node.decorator_list: - # Don't split after the '@'. - decorator_range = self._GetTokens( decorator ) - decorator_range[ 0 ].split_penalty = split_penalty.UNBREAKABLE - - return self.generic_visit( node ) - - def visit_Return( self, node ): - # Return(value=Expr) - tokens = self._GetTokens( node ) - _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) - - return self.generic_visit( node ) - - def visit_Delete( self, node ): - # Delete(targets=[Expr_1, Expr_2, ..., Expr_n]) - for target in node.targets: - tokens = self._GetTokens( target ) - _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) - - return self.generic_visit( node ) - - def visit_Assign( self, node ): - # Assign(targets=[Expr_1, Expr_2, ..., Expr_n], - # value=Expr) - tokens = self._GetTokens( node ) - _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) - - return self.generic_visit( node ) - - def visit_AugAssign( self, node ): - # AugAssign(target=Name, - # op=Add(), - # value=Expr) - return self.generic_visit( node ) - - def visit_AnnAssign( self, node ): - # AnnAssign(target=Expr, - # annotation=TypeName, - # value=Expr, - # simple=number) - return self.generic_visit( node ) - - def visit_For( self, node ): - # For(target=Expr, - # iter=Expr, - # body=[...], - # orelse=[...]) - return self.generic_visit( node ) - - def visit_AsyncFor( self, node ): - # AsyncFor(target=Expr, - # iter=Expr, - # body=[...], - # orelse=[...]) - return self.generic_visit( node ) - - def visit_While( self, node ): - # While(test=Expr, - # body=[...], - # orelse=[...]) - return self.generic_visit( node ) - - def visit_If( self, node ): - # If(test=Expr, - # body=[...], - # orelse=[...]) - return self.generic_visit( node ) - - def visit_With( self, node ): - # With(items=[withitem_1, withitem_2, ..., withitem_n], - # body=[...]) - return self.generic_visit( node ) - - def visit_AsyncWith( self, node ): - # AsyncWith(items=[withitem_1, withitem_2, ..., withitem_n], - # body=[...]) - return self.generic_visit( node ) - - def visit_Match( self, node ): - # Match(subject=Expr, - # cases=[ - # match_case( - # pattern=pattern, - # guard=Expr, - # body=[...]), - # ... - # ]) - return self.generic_visit( node ) - - def visit_Raise( self, node ): - # Raise(exc=Expr) - return self.generic_visit( node ) - - def visit_Try( self, node ): - # Try(body=[...], - # handlers=[ExceptHandler_1, ExceptHandler_2, ..., ExceptHandler_b], - # orelse=[...], - # finalbody=[...]) - return self.generic_visit( node ) - - def visit_Assert( self, node ): - # Assert(test=Expr) - return self.generic_visit( node ) - - def visit_Import( self, node ): - # Import(names=[ - # alias( - # name=Identifier, - # asname=Identifier), - # ... - # ]) - return self.generic_visit( node ) - - def visit_ImportFrom( self, node ): - # ImportFrom(module=Identifier, - # names=[ - # alias( - # name=Identifier, - # asname=Identifier), - # ... - # ], - # level=num - return self.generic_visit( node ) - - def visit_Global( self, node ): - # Global(names=[Identifier_1, Identifier_2, ..., Identifier_n]) - return self.generic_visit( node ) - - def visit_Nonlocal( self, node ): - # Nonlocal(names=[Identifier_1, Identifier_2, ..., Identifier_n]) - return self.generic_visit( node ) - - def visit_Expr( self, node ): - # Expr(value=Expr) - return self.generic_visit( node ) - - def visit_Pass( self, node ): - # Pass() - return self.generic_visit( node ) - - def visit_Break( self, node ): - # Break() - return self.generic_visit( node ) - - def visit_Continue( self, node ): - # Continue() - return self.generic_visit( node ) - - ############################################################################ - # Expressions # - ############################################################################ - - def visit_BoolOp( self, node ): - # BoolOp(op=And | Or, - # values=[Expr_1, Expr_2, ..., Expr_n]) - tokens = self._GetTokens( node ) - _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) - - # Lower the split penalty to allow splitting before or after the logical - # operator. - split_before_operator = style.Get( 'SPLIT_BEFORE_LOGICAL_OPERATOR' ) - operator_indices = [ - pyutils.GetNextTokenIndex( tokens, pyutils.TokenEnd( value ) ) - for value in node.values[ :-1 ] - ] - for operator_index in operator_indices: - if not split_before_operator: - operator_index += 1 - _DecreasePenalty( tokens[ operator_index ], split_penalty.EXPR * 2 ) - - return self.generic_visit( node ) - - def visit_NamedExpr( self, node ): - # NamedExpr(target=Name, - # value=Expr) - tokens = self._GetTokens( node ) - _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) - - return self.generic_visit( node ) - - def visit_BinOp( self, node ): - # BinOp(left=LExpr - # op=Add | Sub | Mult | MatMult | Div | Mod | Pow | LShift | - # RShift | BitOr | BitXor | BitAnd | FloorDiv - # right=RExpr) - tokens = self._GetTokens( node ) - _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) - - # Lower the split penalty to allow splitting before or after the arithmetic - # operator. - operator_index = pyutils.GetNextTokenIndex( - tokens, pyutils.TokenEnd( node.left ) ) - if not style.Get( 'SPLIT_BEFORE_ARITHMETIC_OPERATOR' ): - operator_index += 1 - - _DecreasePenalty( tokens[ operator_index ], split_penalty.EXPR * 2 ) - - return self.generic_visit( node ) - - def visit_UnaryOp( self, node ): - # UnaryOp(op=Not | USub | UAdd | Invert, - # operand=Expr) - tokens = self._GetTokens( node ) - _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) - _IncreasePenalty( - tokens[ 1 ], style.Get( 'SPLIT_PENALTY_AFTER_UNARY_OPERATOR' ) ) - - return self.generic_visit( node ) - - def visit_Lambda( self, node ): - # Lambda(args=arguments( - # posonlyargs=[arg(...), arg(...), ..., arg(...)], - # args=[arg(...), arg(...), ..., arg(...)], - # kwonlyargs=[arg(...), arg(...), ..., arg(...)], - # kw_defaults=[arg(...), arg(...), ..., arg(...)], - # defaults=[arg(...), arg(...), ..., arg(...)]), - # body=Expr) - tokens = self._GetTokens( node ) - _IncreasePenalty( tokens[ 1 : ], split_penalty.LAMBDA ) - - if style.Get( 'ALLOW_MULTILINE_LAMBDAS' ): - _SetPenalty( self._GetTokens( node.body ), split_penalty.MULTIPLINE_LAMBDA ) - - return self.generic_visit( node ) - - def visit_IfExp( self, node ): - # IfExp(test=TestExpr, - # body=BodyExpr, - # orelse=OrElseExpr) - tokens = self._GetTokens( node ) - _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) - - return self.generic_visit( node ) - - def visit_Dict( self, node ): - # Dict(keys=[Expr_1, Expr_2, ..., Expr_n], - # values=[Expr_1, Expr_2, ..., Expr_n]) - tokens = self._GetTokens( node ) - - # The keys should be on a single line if at all possible. - for key in node.keys: - subrange = pyutils.GetTokensInSubRange( tokens, key ) - _IncreasePenalty( subrange[ 1 : ], split_penalty.DICT_KEY_EXPR ) - - for value in node.values: - subrange = pyutils.GetTokensInSubRange( tokens, value ) - _IncreasePenalty( subrange[ 1 : ], split_penalty.DICT_VALUE_EXPR ) - - return self.generic_visit( node ) - - def visit_Set( self, node ): - # Set(elts=[Expr_1, Expr_2, ..., Expr_n]) - tokens = self._GetTokens( node ) - for element in node.elts: - subrange = pyutils.GetTokensInSubRange( tokens, element ) - _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) - - return self.generic_visit( node ) - - def visit_ListComp( self, node ): - # ListComp(elt=Expr, - # generators=[ - # comprehension( - # target=Expr, - # iter=Expr, - # ifs=[Expr_1, Expr_2, ..., Expr_n], - # is_async=0), - # ... - # ]) - tokens = self._GetTokens( node ) - element = pyutils.GetTokensInSubRange( tokens, node.elt ) - _IncreasePenalty( element[ 1 : ], split_penalty.EXPR ) - - for comp in node.generators: - subrange = pyutils.GetTokensInSubRange( tokens, comp.iter ) - _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) - - for if_expr in comp.ifs: - subrange = pyutils.GetTokensInSubRange( tokens, if_expr ) - _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) - - return self.generic_visit( node ) - - def visit_SetComp( self, node ): - # SetComp(elt=Expr, - # generators=[ - # comprehension( - # target=Expr, - # iter=Expr, - # ifs=[Expr_1, Expr_2, ..., Expr_n], - # is_async=0), - # ... - # ]) - tokens = self._GetTokens( node ) - element = pyutils.GetTokensInSubRange( tokens, node.elt ) - _IncreasePenalty( element[ 1 : ], split_penalty.EXPR ) - - for comp in node.generators: - subrange = pyutils.GetTokensInSubRange( tokens, comp.iter ) - _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) - - for if_expr in comp.ifs: - subrange = pyutils.GetTokensInSubRange( tokens, if_expr ) - _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) - - return self.generic_visit( node ) - - def visit_DictComp( self, node ): - # DictComp(key=KeyExpr, - # value=ValExpr, - # generators=[ - # comprehension( - # target=TargetExpr - # iter=IterExpr, - # ifs=[Expr_1, Expr_2, ..., Expr_n]), - # is_async=0)], - # ... - # ]) - tokens = self._GetTokens( node ) - key = pyutils.GetTokensInSubRange( tokens, node.key ) - _IncreasePenalty( key[ 1 : ], split_penalty.EXPR ) - - value = pyutils.GetTokensInSubRange( tokens, node.value ) - _IncreasePenalty( value[ 1 : ], split_penalty.EXPR ) - - for comp in node.generators: - subrange = pyutils.GetTokensInSubRange( tokens, comp.iter ) - _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) - - for if_expr in comp.ifs: - subrange = pyutils.GetTokensInSubRange( tokens, if_expr ) - _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) - - return self.generic_visit( node ) - - def visit_GeneratorExp( self, node ): - # GeneratorExp(elt=Expr, - # generators=[ - # comprehension( - # target=Expr, - # iter=Expr, - # ifs=[Expr_1, Expr_2, ..., Expr_n], - # is_async=0), - # ... - # ]) - tokens = self._GetTokens( node ) - element = pyutils.GetTokensInSubRange( tokens, node.elt ) - _IncreasePenalty( element[ 1 : ], split_penalty.EXPR ) - - for comp in node.generators: - subrange = pyutils.GetTokensInSubRange( tokens, comp.iter ) - _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) - - for if_expr in comp.ifs: - subrange = pyutils.GetTokensInSubRange( tokens, if_expr ) - _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) - - return self.generic_visit( node ) - - def visit_Await( self, node ): - # Await(value=Expr) - tokens = self._GetTokens( node ) - _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) - - return self.generic_visit( node ) - - def visit_Yield( self, node ): - # Yield(value=Expr) - tokens = self._GetTokens( node ) - _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) - - return self.generic_visit( node ) - - def visit_YieldFrom( self, node ): - # YieldFrom(value=Expr) - tokens = self._GetTokens( node ) - _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) - tokens[ 2 ].split_penalty = split_penalty.UNBREAKABLE - - return self.generic_visit( node ) - - def visit_Compare( self, node ): - # Compare(left=LExpr, - # ops=[Op_1, Op_2, ..., Op_n], - # comparators=[Expr_1, Expr_2, ..., Expr_n]) - tokens = self._GetTokens( node ) - _IncreasePenalty( tokens[ 1 : ], split_penalty.EXPR ) - - operator_indices = [ - pyutils.GetNextTokenIndex( tokens, pyutils.TokenEnd( node.left ) ) - ] + [ - pyutils.GetNextTokenIndex( tokens, pyutils.TokenEnd( comparator ) ) - for comparator in node.comparators[ :-1 ] - ] - split_before = style.Get( 'SPLIT_BEFORE_ARITHMETIC_OPERATOR' ) - - for operator_index in operator_indices: - if not split_before: - operator_index += 1 - _DecreasePenalty( tokens[ operator_index ], split_penalty.EXPR * 2 ) - - return self.generic_visit( node ) - - def visit_Call( self, node ): - # Call(func=Expr, - # args=[Expr_1, Expr_2, ..., Expr_n], - # keywords=[ - # keyword( - # arg='d', - # value=Expr), - # ... - # ]) - tokens = self._GetTokens( node ) - - # Don't never split before the opening parenthesis. - paren_index = pyutils.GetNextTokenIndex( tokens, pyutils.TokenEnd( node.func ) ) - _IncreasePenalty( tokens[ paren_index ], split_penalty.UNBREAKABLE ) - - for arg in node.args: - subrange = pyutils.GetTokensInSubRange( tokens, arg ) - _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) - - return self.generic_visit( node ) - - def visit_FormattedValue( self, node ): - # FormattedValue(value=Expr, - # conversion=-1) - return node # Ignore formatted values. - - def visit_JoinedStr( self, node ): - # JoinedStr(values=[Expr_1, Expr_2, ..., Expr_n]) - return self.generic_visit( node ) - - def visit_Constant( self, node ): - # Constant(value=Expr) - return self.generic_visit( node ) - - def visit_Attribute( self, node ): - # Attribute(value=Expr, - # attr=Identifier) - tokens = self._GetTokens( node ) - split_before = style.Get( 'SPLIT_BEFORE_DOT' ) - dot_indices = pyutils.GetNextTokenIndex( - tokens, pyutils.TokenEnd( node.value ) ) - - if not split_before: - dot_indices += 1 - _IncreasePenalty( tokens[ dot_indices ], split_penalty.VERY_STRONGLY_CONNECTED ) - - return self.generic_visit( node ) - - def visit_Subscript( self, node ): - # Subscript(value=ValueExpr, - # slice=SliceExpr) - tokens = self._GetTokens( node ) - - # Don't split before the opening bracket of a subscript. - bracket_index = pyutils.GetNextTokenIndex( - tokens, pyutils.TokenEnd( node.value ) ) - _IncreasePenalty( tokens[ bracket_index ], split_penalty.UNBREAKABLE ) - - return self.generic_visit( node ) - - def visit_Starred( self, node ): - # Starred(value=Expr) - return self.generic_visit( node ) - - def visit_Name( self, node ): - # Name(id=Identifier) - tokens = self._GetTokens( node ) - _IncreasePenalty( tokens[ 1 : ], split_penalty.UNBREAKABLE ) - - return self.generic_visit( node ) - - def visit_List( self, node ): - # List(elts=[Expr_1, Expr_2, ..., Expr_n]) - tokens = self._GetTokens( node ) - - for element in node.elts: - subrange = pyutils.GetTokensInSubRange( tokens, element ) - _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) - _DecreasePenalty( subrange[ 0 ], split_penalty.EXPR // 2 ) - - return self.generic_visit( node ) - - def visit_Tuple( self, node ): - # Tuple(elts=[Expr_1, Expr_2, ..., Expr_n]) - tokens = self._GetTokens( node ) - - for element in node.elts: - subrange = pyutils.GetTokensInSubRange( tokens, element ) - _IncreasePenalty( subrange[ 1 : ], split_penalty.EXPR ) - _DecreasePenalty( subrange[ 0 ], split_penalty.EXPR // 2 ) - - return self.generic_visit( node ) - - def visit_Slice( self, node ): - # Slice(lower=Expr, - # upper=Expr, - # step=Expr) - tokens = self._GetTokens( node ) - - if hasattr( node, 'lower' ) and node.lower: - subrange = pyutils.GetTokensInSubRange( tokens, node.lower ) - _IncreasePenalty( subrange, split_penalty.EXPR ) - _DecreasePenalty( subrange[ 0 ], split_penalty.EXPR // 2 ) - - if hasattr( node, 'upper' ) and node.upper: - colon_index = pyutils.GetPrevTokenIndex( - tokens, pyutils.TokenStart( node.upper ) ) - _IncreasePenalty( tokens[ colon_index ], split_penalty.UNBREAKABLE ) - subrange = pyutils.GetTokensInSubRange( tokens, node.upper ) - _IncreasePenalty( subrange, split_penalty.EXPR ) - _DecreasePenalty( subrange[ 0 ], split_penalty.EXPR // 2 ) - - if hasattr( node, 'step' ) and node.step: - colon_index = pyutils.GetPrevTokenIndex( - tokens, pyutils.TokenStart( node.step ) ) - _IncreasePenalty( tokens[ colon_index ], split_penalty.UNBREAKABLE ) - subrange = pyutils.GetTokensInSubRange( tokens, node.step ) - _IncreasePenalty( subrange, split_penalty.EXPR ) - _DecreasePenalty( subrange[ 0 ], split_penalty.EXPR // 2 ) - - return self.generic_visit( node ) - - ############################################################################ - # Expression Context # - ############################################################################ - - def visit_Load( self, node ): - # Load() - return self.generic_visit( node ) - - def visit_Store( self, node ): - # Store() - return self.generic_visit( node ) - - def visit_Del( self, node ): - # Del() - return self.generic_visit( node ) - - ############################################################################ - # Boolean Operators # - ############################################################################ +class SplitPenalty(ast.NodeVisitor): + """Compute split penalties between tokens.""" + + def __init__(self, logical_lines): + super(SplitPenalty, self).__init__() + self.logical_lines = logical_lines + + # We never want to split before a colon or comma. + for logical_line in logical_lines: + for token in logical_line.tokens: + if token.value in frozenset({',', ':'}): + token.split_penalty = split_penalty.UNBREAKABLE + + def _GetTokens(self, node): + return pyutils.GetTokens(self.logical_lines, node) + + ############################################################################ + # Statements # + ############################################################################ + + def visit_FunctionDef(self, node): + # FunctionDef(name=Name, + # args=arguments( + # posonlyargs=[], + # args=[], + # vararg=[], + # kwonlyargs=[], + # kw_defaults=[], + # defaults=[]), + # body=[...], + # decorator_list=[Call_1, Call_2, ..., Call_n], + # keywords=[]) + tokens = self._GetTokens(node) + for decorator in node.decorator_list: + # The decorator token list begins after the '@'. The body of the decorator + # is formatted like a normal "call." + decorator_range = self._GetTokens(decorator) + # Don't split after the '@'. + decorator_range[0].split_penalty = split_penalty.UNBREAKABLE + + for token in tokens[1:]: + if token.value == '(': + break + _SetPenalty(token, split_penalty.UNBREAKABLE) + + if node.returns: + start_index = pyutils.GetTokenIndex( + tokens, pyutils.TokenStart(node.returns)) + _IncreasePenalty( + tokens[start_index - 1:start_index + 1], + split_penalty.VERY_STRONGLY_CONNECTED) + end_index = pyutils.GetTokenIndex(tokens, pyutils.TokenEnd(node.returns)) + _IncreasePenalty( + tokens[start_index + 1:end_index], split_penalty.STRONGLY_CONNECTED) + + return self.generic_visit(node) + + def visit_AsyncFunctionDef(self, node): + # AsyncFunctionDef(name=Name, + # args=arguments( + # posonlyargs=[], + # args=[], + # vararg=[], + # kwonlyargs=[], + # kw_defaults=[], + # defaults=[]), + # body=[...], + # decorator_list=[Expr_1, Expr_2, ..., Expr_n], + # keywords=[]) + return self.visit_FunctionDef(node) + + def visit_ClassDef(self, node): + # ClassDef(name=Name, + # bases=[Expr_1, Expr_2, ..., Expr_n], + # keywords=[], + # body=[], + # decorator_list=[Expr_1, Expr_2, ..., Expr_m]) + for base in node.bases: + tokens = self._GetTokens(base) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + + for decorator in node.decorator_list: + # Don't split after the '@'. + decorator_range = self._GetTokens(decorator) + decorator_range[0].split_penalty = split_penalty.UNBREAKABLE + + return self.generic_visit(node) + + def visit_Return(self, node): + # Return(value=Expr) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + + return self.generic_visit(node) + + def visit_Delete(self, node): + # Delete(targets=[Expr_1, Expr_2, ..., Expr_n]) + for target in node.targets: + tokens = self._GetTokens(target) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + + return self.generic_visit(node) + + def visit_Assign(self, node): + # Assign(targets=[Expr_1, Expr_2, ..., Expr_n], + # value=Expr) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + + return self.generic_visit(node) + + def visit_AugAssign(self, node): + # AugAssign(target=Name, + # op=Add(), + # value=Expr) + return self.generic_visit(node) + + def visit_AnnAssign(self, node): + # AnnAssign(target=Expr, + # annotation=TypeName, + # value=Expr, + # simple=number) + return self.generic_visit(node) + + def visit_For(self, node): + # For(target=Expr, + # iter=Expr, + # body=[...], + # orelse=[...]) + return self.generic_visit(node) + + def visit_AsyncFor(self, node): + # AsyncFor(target=Expr, + # iter=Expr, + # body=[...], + # orelse=[...]) + return self.generic_visit(node) + + def visit_While(self, node): + # While(test=Expr, + # body=[...], + # orelse=[...]) + return self.generic_visit(node) + + def visit_If(self, node): + # If(test=Expr, + # body=[...], + # orelse=[...]) + return self.generic_visit(node) + + def visit_With(self, node): + # With(items=[withitem_1, withitem_2, ..., withitem_n], + # body=[...]) + return self.generic_visit(node) + + def visit_AsyncWith(self, node): + # AsyncWith(items=[withitem_1, withitem_2, ..., withitem_n], + # body=[...]) + return self.generic_visit(node) + + def visit_Match(self, node): + # Match(subject=Expr, + # cases=[ + # match_case( + # pattern=pattern, + # guard=Expr, + # body=[...]), + # ... + # ]) + return self.generic_visit(node) + + def visit_Raise(self, node): + # Raise(exc=Expr) + return self.generic_visit(node) + + def visit_Try(self, node): + # Try(body=[...], + # handlers=[ExceptHandler_1, ExceptHandler_2, ..., ExceptHandler_b], + # orelse=[...], + # finalbody=[...]) + return self.generic_visit(node) + + def visit_Assert(self, node): + # Assert(test=Expr) + return self.generic_visit(node) + + def visit_Import(self, node): + # Import(names=[ + # alias( + # name=Identifier, + # asname=Identifier), + # ... + # ]) + return self.generic_visit(node) + + def visit_ImportFrom(self, node): + # ImportFrom(module=Identifier, + # names=[ + # alias( + # name=Identifier, + # asname=Identifier), + # ... + # ], + # level=num + return self.generic_visit(node) + + def visit_Global(self, node): + # Global(names=[Identifier_1, Identifier_2, ..., Identifier_n]) + return self.generic_visit(node) + + def visit_Nonlocal(self, node): + # Nonlocal(names=[Identifier_1, Identifier_2, ..., Identifier_n]) + return self.generic_visit(node) + + def visit_Expr(self, node): + # Expr(value=Expr) + return self.generic_visit(node) + + def visit_Pass(self, node): + # Pass() + return self.generic_visit(node) + + def visit_Break(self, node): + # Break() + return self.generic_visit(node) + + def visit_Continue(self, node): + # Continue() + return self.generic_visit(node) + + ############################################################################ + # Expressions # + ############################################################################ + + def visit_BoolOp(self, node): + # BoolOp(op=And | Or, + # values=[Expr_1, Expr_2, ..., Expr_n]) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + + # Lower the split penalty to allow splitting before or after the logical + # operator. + split_before_operator = style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR') + operator_indices = [ + pyutils.GetNextTokenIndex(tokens, pyutils.TokenEnd(value)) + for value in node.values[:-1] + ] + for operator_index in operator_indices: + if not split_before_operator: + operator_index += 1 + _DecreasePenalty(tokens[operator_index], split_penalty.EXPR * 2) + + return self.generic_visit(node) + + def visit_NamedExpr(self, node): + # NamedExpr(target=Name, + # value=Expr) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + + return self.generic_visit(node) + + def visit_BinOp(self, node): + # BinOp(left=LExpr + # op=Add | Sub | Mult | MatMult | Div | Mod | Pow | LShift | + # RShift | BitOr | BitXor | BitAnd | FloorDiv + # right=RExpr) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + + # Lower the split penalty to allow splitting before or after the arithmetic + # operator. + operator_index = pyutils.GetNextTokenIndex( + tokens, pyutils.TokenEnd(node.left)) + if not style.Get('SPLIT_BEFORE_ARITHMETIC_OPERATOR'): + operator_index += 1 + + _DecreasePenalty(tokens[operator_index], split_penalty.EXPR * 2) + + return self.generic_visit(node) + + def visit_UnaryOp(self, node): + # UnaryOp(op=Not | USub | UAdd | Invert, + # operand=Expr) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + _IncreasePenalty(tokens[1], style.Get('SPLIT_PENALTY_AFTER_UNARY_OPERATOR')) + + return self.generic_visit(node) + + def visit_Lambda(self, node): + # Lambda(args=arguments( + # posonlyargs=[arg(...), arg(...), ..., arg(...)], + # args=[arg(...), arg(...), ..., arg(...)], + # kwonlyargs=[arg(...), arg(...), ..., arg(...)], + # kw_defaults=[arg(...), arg(...), ..., arg(...)], + # defaults=[arg(...), arg(...), ..., arg(...)]), + # body=Expr) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.LAMBDA) + + if style.Get('ALLOW_MULTILINE_LAMBDAS'): + _SetPenalty(self._GetTokens(node.body), split_penalty.MULTIPLINE_LAMBDA) + + return self.generic_visit(node) + + def visit_IfExp(self, node): + # IfExp(test=TestExpr, + # body=BodyExpr, + # orelse=OrElseExpr) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + + return self.generic_visit(node) + + def visit_Dict(self, node): + # Dict(keys=[Expr_1, Expr_2, ..., Expr_n], + # values=[Expr_1, Expr_2, ..., Expr_n]) + tokens = self._GetTokens(node) + + # The keys should be on a single line if at all possible. + for key in node.keys: + subrange = pyutils.GetTokensInSubRange(tokens, key) + _IncreasePenalty(subrange[1:], split_penalty.DICT_KEY_EXPR) + + for value in node.values: + subrange = pyutils.GetTokensInSubRange(tokens, value) + _IncreasePenalty(subrange[1:], split_penalty.DICT_VALUE_EXPR) + + return self.generic_visit(node) + + def visit_Set(self, node): + # Set(elts=[Expr_1, Expr_2, ..., Expr_n]) + tokens = self._GetTokens(node) + for element in node.elts: + subrange = pyutils.GetTokensInSubRange(tokens, element) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + + return self.generic_visit(node) + + def visit_ListComp(self, node): + # ListComp(elt=Expr, + # generators=[ + # comprehension( + # target=Expr, + # iter=Expr, + # ifs=[Expr_1, Expr_2, ..., Expr_n], + # is_async=0), + # ... + # ]) + tokens = self._GetTokens(node) + element = pyutils.GetTokensInSubRange(tokens, node.elt) + _IncreasePenalty(element[1:], split_penalty.EXPR) + + for comp in node.generators: + subrange = pyutils.GetTokensInSubRange(tokens, comp.iter) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + + for if_expr in comp.ifs: + subrange = pyutils.GetTokensInSubRange(tokens, if_expr) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + + return self.generic_visit(node) + + def visit_SetComp(self, node): + # SetComp(elt=Expr, + # generators=[ + # comprehension( + # target=Expr, + # iter=Expr, + # ifs=[Expr_1, Expr_2, ..., Expr_n], + # is_async=0), + # ... + # ]) + tokens = self._GetTokens(node) + element = pyutils.GetTokensInSubRange(tokens, node.elt) + _IncreasePenalty(element[1:], split_penalty.EXPR) + + for comp in node.generators: + subrange = pyutils.GetTokensInSubRange(tokens, comp.iter) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + + for if_expr in comp.ifs: + subrange = pyutils.GetTokensInSubRange(tokens, if_expr) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + + return self.generic_visit(node) + + def visit_DictComp(self, node): + # DictComp(key=KeyExpr, + # value=ValExpr, + # generators=[ + # comprehension( + # target=TargetExpr + # iter=IterExpr, + # ifs=[Expr_1, Expr_2, ..., Expr_n]), + # is_async=0)], + # ... + # ]) + tokens = self._GetTokens(node) + key = pyutils.GetTokensInSubRange(tokens, node.key) + _IncreasePenalty(key[1:], split_penalty.EXPR) + + value = pyutils.GetTokensInSubRange(tokens, node.value) + _IncreasePenalty(value[1:], split_penalty.EXPR) + + for comp in node.generators: + subrange = pyutils.GetTokensInSubRange(tokens, comp.iter) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + + for if_expr in comp.ifs: + subrange = pyutils.GetTokensInSubRange(tokens, if_expr) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + + return self.generic_visit(node) + + def visit_GeneratorExp(self, node): + # GeneratorExp(elt=Expr, + # generators=[ + # comprehension( + # target=Expr, + # iter=Expr, + # ifs=[Expr_1, Expr_2, ..., Expr_n], + # is_async=0), + # ... + # ]) + tokens = self._GetTokens(node) + element = pyutils.GetTokensInSubRange(tokens, node.elt) + _IncreasePenalty(element[1:], split_penalty.EXPR) + + for comp in node.generators: + subrange = pyutils.GetTokensInSubRange(tokens, comp.iter) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + + for if_expr in comp.ifs: + subrange = pyutils.GetTokensInSubRange(tokens, if_expr) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + + return self.generic_visit(node) + + def visit_Await(self, node): + # Await(value=Expr) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + + return self.generic_visit(node) + + def visit_Yield(self, node): + # Yield(value=Expr) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + + return self.generic_visit(node) + + def visit_YieldFrom(self, node): + # YieldFrom(value=Expr) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + tokens[2].split_penalty = split_penalty.UNBREAKABLE + + return self.generic_visit(node) + + def visit_Compare(self, node): + # Compare(left=LExpr, + # ops=[Op_1, Op_2, ..., Op_n], + # comparators=[Expr_1, Expr_2, ..., Expr_n]) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) + + operator_indices = [ + pyutils.GetNextTokenIndex(tokens, pyutils.TokenEnd(node.left)) + ] + [ + pyutils.GetNextTokenIndex(tokens, pyutils.TokenEnd(comparator)) + for comparator in node.comparators[:-1] + ] + split_before = style.Get('SPLIT_BEFORE_ARITHMETIC_OPERATOR') + + for operator_index in operator_indices: + if not split_before: + operator_index += 1 + _DecreasePenalty(tokens[operator_index], split_penalty.EXPR * 2) + + return self.generic_visit(node) + + def visit_Call(self, node): + # Call(func=Expr, + # args=[Expr_1, Expr_2, ..., Expr_n], + # keywords=[ + # keyword( + # arg='d', + # value=Expr), + # ... + # ]) + tokens = self._GetTokens(node) + + # Don't never split before the opening parenthesis. + paren_index = pyutils.GetNextTokenIndex(tokens, pyutils.TokenEnd(node.func)) + _IncreasePenalty(tokens[paren_index], split_penalty.UNBREAKABLE) + + for arg in node.args: + subrange = pyutils.GetTokensInSubRange(tokens, arg) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + + return self.generic_visit(node) + + def visit_FormattedValue(self, node): + # FormattedValue(value=Expr, + # conversion=-1) + return node # Ignore formatted values. + + def visit_JoinedStr(self, node): + # JoinedStr(values=[Expr_1, Expr_2, ..., Expr_n]) + return self.generic_visit(node) + + def visit_Constant(self, node): + # Constant(value=Expr) + return self.generic_visit(node) + + def visit_Attribute(self, node): + # Attribute(value=Expr, + # attr=Identifier) + tokens = self._GetTokens(node) + split_before = style.Get('SPLIT_BEFORE_DOT') + dot_indices = pyutils.GetNextTokenIndex( + tokens, pyutils.TokenEnd(node.value)) + + if not split_before: + dot_indices += 1 + _IncreasePenalty(tokens[dot_indices], split_penalty.VERY_STRONGLY_CONNECTED) + + return self.generic_visit(node) + + def visit_Subscript(self, node): + # Subscript(value=ValueExpr, + # slice=SliceExpr) + tokens = self._GetTokens(node) + + # Don't split before the opening bracket of a subscript. + bracket_index = pyutils.GetNextTokenIndex( + tokens, pyutils.TokenEnd(node.value)) + _IncreasePenalty(tokens[bracket_index], split_penalty.UNBREAKABLE) + + return self.generic_visit(node) + + def visit_Starred(self, node): + # Starred(value=Expr) + return self.generic_visit(node) + + def visit_Name(self, node): + # Name(id=Identifier) + tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.UNBREAKABLE) + + return self.generic_visit(node) + + def visit_List(self, node): + # List(elts=[Expr_1, Expr_2, ..., Expr_n]) + tokens = self._GetTokens(node) + + for element in node.elts: + subrange = pyutils.GetTokensInSubRange(tokens, element) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) + + return self.generic_visit(node) + + def visit_Tuple(self, node): + # Tuple(elts=[Expr_1, Expr_2, ..., Expr_n]) + tokens = self._GetTokens(node) + + for element in node.elts: + subrange = pyutils.GetTokensInSubRange(tokens, element) + _IncreasePenalty(subrange[1:], split_penalty.EXPR) + _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) + + return self.generic_visit(node) + + def visit_Slice(self, node): + # Slice(lower=Expr, + # upper=Expr, + # step=Expr) + tokens = self._GetTokens(node) + + if hasattr(node, 'lower') and node.lower: + subrange = pyutils.GetTokensInSubRange(tokens, node.lower) + _IncreasePenalty(subrange, split_penalty.EXPR) + _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) + + if hasattr(node, 'upper') and node.upper: + colon_index = pyutils.GetPrevTokenIndex( + tokens, pyutils.TokenStart(node.upper)) + _IncreasePenalty(tokens[colon_index], split_penalty.UNBREAKABLE) + subrange = pyutils.GetTokensInSubRange(tokens, node.upper) + _IncreasePenalty(subrange, split_penalty.EXPR) + _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) + + if hasattr(node, 'step') and node.step: + colon_index = pyutils.GetPrevTokenIndex( + tokens, pyutils.TokenStart(node.step)) + _IncreasePenalty(tokens[colon_index], split_penalty.UNBREAKABLE) + subrange = pyutils.GetTokensInSubRange(tokens, node.step) + _IncreasePenalty(subrange, split_penalty.EXPR) + _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) + + return self.generic_visit(node) + + ############################################################################ + # Expression Context # + ############################################################################ + + def visit_Load(self, node): + # Load() + return self.generic_visit(node) + + def visit_Store(self, node): + # Store() + return self.generic_visit(node) + + def visit_Del(self, node): + # Del() + return self.generic_visit(node) + + ############################################################################ + # Boolean Operators # + ############################################################################ - def visit_And( self, node ): - # And() - return self.generic_visit( node ) + def visit_And(self, node): + # And() + return self.generic_visit(node) - def visit_Or( self, node ): - # Or() - return self.generic_visit( node ) - - ############################################################################ - # Binary Operators # - ############################################################################ - - def visit_Add( self, node ): - # Add() - return self.generic_visit( node ) + def visit_Or(self, node): + # Or() + return self.generic_visit(node) + + ############################################################################ + # Binary Operators # + ############################################################################ + + def visit_Add(self, node): + # Add() + return self.generic_visit(node) - def visit_Sub( self, node ): - # Sub() - return self.generic_visit( node ) - - def visit_Mult( self, node ): - # Mult() - return self.generic_visit( node ) - - def visit_MatMult( self, node ): - # MatMult() - return self.generic_visit( node ) - - def visit_Div( self, node ): - # Div() - return self.generic_visit( node ) - - def visit_Mod( self, node ): - # Mod() - return self.generic_visit( node ) - - def visit_Pow( self, node ): - # Pow() - return self.generic_visit( node ) - - def visit_LShift( self, node ): - # LShift() - return self.generic_visit( node ) - - def visit_RShift( self, node ): - # RShift() - return self.generic_visit( node ) - - def visit_BitOr( self, node ): - # BitOr() - return self.generic_visit( node ) - - def visit_BitXor( self, node ): - # BitXor() - return self.generic_visit( node ) - - def visit_BitAnd( self, node ): - # BitAnd() - return self.generic_visit( node ) - - def visit_FloorDiv( self, node ): - # FloorDiv() - return self.generic_visit( node ) - - ############################################################################ - # Unary Operators # - ############################################################################ - - def visit_Invert( self, node ): - # Invert() - return self.generic_visit( node ) - - def visit_Not( self, node ): - # Not() - return self.generic_visit( node ) - - def visit_UAdd( self, node ): - # UAdd() - return self.generic_visit( node ) - - def visit_USub( self, node ): - # USub() - return self.generic_visit( node ) - - ############################################################################ - # Comparison Operators # - ############################################################################ - - def visit_Eq( self, node ): - # Eq() - return self.generic_visit( node ) - - def visit_NotEq( self, node ): - # NotEq() - return self.generic_visit( node ) - - def visit_Lt( self, node ): - # Lt() - return self.generic_visit( node ) - - def visit_LtE( self, node ): - # LtE() - return self.generic_visit( node ) - - def visit_Gt( self, node ): - # Gt() - return self.generic_visit( node ) - - def visit_GtE( self, node ): - # GtE() - return self.generic_visit( node ) - - def visit_Is( self, node ): - # Is() - return self.generic_visit( node ) - - def visit_IsNot( self, node ): - # IsNot() - return self.generic_visit( node ) - - def visit_In( self, node ): - # In() - return self.generic_visit( node ) - - def visit_NotIn( self, node ): - # NotIn() - return self.generic_visit( node ) - - ############################################################################ - # Exception Handler # - ############################################################################ - - def visit_ExceptionHandler( self, node ): - # ExceptHandler(type=Expr, - # name=Identifier, - # body=[...]) - return self.generic_visit( node ) - - ############################################################################ - # Matching Patterns # - ############################################################################ - - def visit_MatchValue( self, node ): - # MatchValue(value=Expr) - return self.generic_visit( node ) - - def visit_MatchSingleton( self, node ): - # MatchSingleton(value=Constant) - return self.generic_visit( node ) - - def visit_MatchSequence( self, node ): - # MatchSequence(patterns=[pattern_1, pattern_2, ..., pattern_n]) - return self.generic_visit( node ) - - def visit_MatchMapping( self, node ): - # MatchMapping(keys=[Expr_1, Expr_2, ..., Expr_n], - # patterns=[pattern_1, pattern_2, ..., pattern_m], - # rest=Identifier) - return self.generic_visit( node ) - - def visit_MatchClass( self, node ): - # MatchClass(cls=Expr, - # patterns=[pattern_1, pattern_2, ...], - # kwd_attrs=[Identifier_1, Identifier_2, ...], - # kwd_patterns=[pattern_1, pattern_2, ...]) - return self.generic_visit( node ) - - def visit_MatchStar( self, node ): - # MatchStar(name=Identifier) - return self.generic_visit( node ) - - def visit_MatchAs( self, node ): - # MatchAs(pattern=pattern, - # name=Identifier) - return self.generic_visit( node ) - - def visit_MatchOr( self, node ): - # MatchOr(patterns=[pattern_1, pattern_2, ...]) - return self.generic_visit( node ) - - ############################################################################ - # Type Ignore # - ############################################################################ - - def visit_TypeIgnore( self, node ): - # TypeIgnore(tag=string) - return self.generic_visit( node ) - - ############################################################################ - # Miscellaneous # - ############################################################################ - - def visit_comprehension( self, node ): - # comprehension(target=Expr, - # iter=Expr, - # ifs=[Expr_1, Expr_2, ..., Expr_n], - # is_async=0) - return self.generic_visit( node ) - - def visit_arguments( self, node ): - # arguments(posonlyargs=[arg_1, arg_2, ..., arg_a], - # args=[arg_1, arg_2, ..., arg_b], - # vararg=arg, - # kwonlyargs=[arg_1, arg_2, ..., arg_c], - # kw_defaults=[arg_1, arg_2, ..., arg_d], - # kwarg=arg, - # defaults=[Expr_1, Expr_2, ..., Expr_n]) - return self.generic_visit( node ) - - def visit_arg( self, node ): - # arg(arg=Identifier, - # annotation=Expr, - # type_comment='') - tokens = self._GetTokens( node ) - - # Process any annotations. - if hasattr( node, 'annotation' ) and node.annotation: - annotation = node.annotation - subrange = pyutils.GetTokensInSubRange( tokens, annotation ) - _IncreasePenalty( subrange, split_penalty.ANNOTATION ) - - return self.generic_visit( node ) - - def visit_keyword( self, node ): - # keyword(arg=Identifier, - # value=Expr) - return self.generic_visit( node ) - - def visit_alias( self, node ): - # alias(name=Identifier, - # asname=Identifier) - return self.generic_visit( node ) - - def visit_withitem( self, node ): - # withitem(context_expr=Expr, - # optional_vars=Expr) - return self.generic_visit( node ) - - def visit_match_case( self, node ): - # match_case(pattern=pattern, - # guard=Expr, - # body=[...]) - return self.generic_visit( node ) - - -def _IncreasePenalty( tokens, amt ): - if not isinstance( tokens, list ): - tokens = [ tokens ] - for token in tokens: - token.split_penalty += amt - - -def _DecreasePenalty( tokens, amt ): - if not isinstance( tokens, list ): - tokens = [ tokens ] - for token in tokens: - token.split_penalty -= amt - - -def _SetPenalty( tokens, amt ): - if not isinstance( tokens, list ): - tokens = [ tokens ] - for token in tokens: - token.split_penalty = amt + def visit_Sub(self, node): + # Sub() + return self.generic_visit(node) + + def visit_Mult(self, node): + # Mult() + return self.generic_visit(node) + + def visit_MatMult(self, node): + # MatMult() + return self.generic_visit(node) + + def visit_Div(self, node): + # Div() + return self.generic_visit(node) + + def visit_Mod(self, node): + # Mod() + return self.generic_visit(node) + + def visit_Pow(self, node): + # Pow() + return self.generic_visit(node) + + def visit_LShift(self, node): + # LShift() + return self.generic_visit(node) + + def visit_RShift(self, node): + # RShift() + return self.generic_visit(node) + + def visit_BitOr(self, node): + # BitOr() + return self.generic_visit(node) + + def visit_BitXor(self, node): + # BitXor() + return self.generic_visit(node) + + def visit_BitAnd(self, node): + # BitAnd() + return self.generic_visit(node) + + def visit_FloorDiv(self, node): + # FloorDiv() + return self.generic_visit(node) + + ############################################################################ + # Unary Operators # + ############################################################################ + + def visit_Invert(self, node): + # Invert() + return self.generic_visit(node) + + def visit_Not(self, node): + # Not() + return self.generic_visit(node) + + def visit_UAdd(self, node): + # UAdd() + return self.generic_visit(node) + + def visit_USub(self, node): + # USub() + return self.generic_visit(node) + + ############################################################################ + # Comparison Operators # + ############################################################################ + + def visit_Eq(self, node): + # Eq() + return self.generic_visit(node) + + def visit_NotEq(self, node): + # NotEq() + return self.generic_visit(node) + + def visit_Lt(self, node): + # Lt() + return self.generic_visit(node) + + def visit_LtE(self, node): + # LtE() + return self.generic_visit(node) + + def visit_Gt(self, node): + # Gt() + return self.generic_visit(node) + + def visit_GtE(self, node): + # GtE() + return self.generic_visit(node) + + def visit_Is(self, node): + # Is() + return self.generic_visit(node) + + def visit_IsNot(self, node): + # IsNot() + return self.generic_visit(node) + + def visit_In(self, node): + # In() + return self.generic_visit(node) + + def visit_NotIn(self, node): + # NotIn() + return self.generic_visit(node) + + ############################################################################ + # Exception Handler # + ############################################################################ + + def visit_ExceptionHandler(self, node): + # ExceptHandler(type=Expr, + # name=Identifier, + # body=[...]) + return self.generic_visit(node) + + ############################################################################ + # Matching Patterns # + ############################################################################ + + def visit_MatchValue(self, node): + # MatchValue(value=Expr) + return self.generic_visit(node) + + def visit_MatchSingleton(self, node): + # MatchSingleton(value=Constant) + return self.generic_visit(node) + + def visit_MatchSequence(self, node): + # MatchSequence(patterns=[pattern_1, pattern_2, ..., pattern_n]) + return self.generic_visit(node) + + def visit_MatchMapping(self, node): + # MatchMapping(keys=[Expr_1, Expr_2, ..., Expr_n], + # patterns=[pattern_1, pattern_2, ..., pattern_m], + # rest=Identifier) + return self.generic_visit(node) + + def visit_MatchClass(self, node): + # MatchClass(cls=Expr, + # patterns=[pattern_1, pattern_2, ...], + # kwd_attrs=[Identifier_1, Identifier_2, ...], + # kwd_patterns=[pattern_1, pattern_2, ...]) + return self.generic_visit(node) + + def visit_MatchStar(self, node): + # MatchStar(name=Identifier) + return self.generic_visit(node) + + def visit_MatchAs(self, node): + # MatchAs(pattern=pattern, + # name=Identifier) + return self.generic_visit(node) + + def visit_MatchOr(self, node): + # MatchOr(patterns=[pattern_1, pattern_2, ...]) + return self.generic_visit(node) + + ############################################################################ + # Type Ignore # + ############################################################################ + + def visit_TypeIgnore(self, node): + # TypeIgnore(tag=string) + return self.generic_visit(node) + + ############################################################################ + # Miscellaneous # + ############################################################################ + + def visit_comprehension(self, node): + # comprehension(target=Expr, + # iter=Expr, + # ifs=[Expr_1, Expr_2, ..., Expr_n], + # is_async=0) + return self.generic_visit(node) + + def visit_arguments(self, node): + # arguments(posonlyargs=[arg_1, arg_2, ..., arg_a], + # args=[arg_1, arg_2, ..., arg_b], + # vararg=arg, + # kwonlyargs=[arg_1, arg_2, ..., arg_c], + # kw_defaults=[arg_1, arg_2, ..., arg_d], + # kwarg=arg, + # defaults=[Expr_1, Expr_2, ..., Expr_n]) + return self.generic_visit(node) + + def visit_arg(self, node): + # arg(arg=Identifier, + # annotation=Expr, + # type_comment='') + tokens = self._GetTokens(node) + + # Process any annotations. + if hasattr(node, 'annotation') and node.annotation: + annotation = node.annotation + subrange = pyutils.GetTokensInSubRange(tokens, annotation) + _IncreasePenalty(subrange, split_penalty.ANNOTATION) + + return self.generic_visit(node) + + def visit_keyword(self, node): + # keyword(arg=Identifier, + # value=Expr) + return self.generic_visit(node) + + def visit_alias(self, node): + # alias(name=Identifier, + # asname=Identifier) + return self.generic_visit(node) + + def visit_withitem(self, node): + # withitem(context_expr=Expr, + # optional_vars=Expr) + return self.generic_visit(node) + + def visit_match_case(self, node): + # match_case(pattern=pattern, + # guard=Expr, + # body=[...]) + return self.generic_visit(node) + + +def _IncreasePenalty(tokens, amt): + if not isinstance(tokens, list): + tokens = [tokens] + for token in tokens: + token.split_penalty += amt + + +def _DecreasePenalty(tokens, amt): + if not isinstance(tokens, list): + tokens = [tokens] + for token in tokens: + token.split_penalty -= amt + + +def _SetPenalty(tokens, amt): + if not isinstance(tokens, list): + tokens = [tokens] + for token in tokens: + token.split_penalty = amt diff --git a/yapf/pytree/blank_line_calculator.py b/yapf/pytree/blank_line_calculator.py index 141306e07..8aa20ec0a 100644 --- a/yapf/pytree/blank_line_calculator.py +++ b/yapf/pytree/blank_line_calculator.py @@ -35,78 +35,79 @@ _PYTHON_STATEMENTS = frozenset( { - 'small_stmt', 'expr_stmt', 'print_stmt', 'del_stmt', 'pass_stmt', 'break_stmt', - 'continue_stmt', 'return_stmt', 'raise_stmt', 'yield_stmt', 'import_stmt', - 'global_stmt', 'exec_stmt', 'assert_stmt', 'if_stmt', 'while_stmt', 'for_stmt', - 'try_stmt', 'with_stmt', 'nonlocal_stmt', 'async_stmt', 'simple_stmt' - } ) + 'small_stmt', 'expr_stmt', 'print_stmt', 'del_stmt', 'pass_stmt', + 'break_stmt', 'continue_stmt', 'return_stmt', 'raise_stmt', + 'yield_stmt', 'import_stmt', 'global_stmt', 'exec_stmt', 'assert_stmt', + 'if_stmt', 'while_stmt', 'for_stmt', 'try_stmt', 'with_stmt', + 'nonlocal_stmt', 'async_stmt', 'simple_stmt' + }) -def CalculateBlankLines( tree ): - """Run the blank line calculator visitor over the tree. +def CalculateBlankLines(tree): + """Run the blank line calculator visitor over the tree. This modifies the tree in place. Arguments: tree: the top-level pytree node to annotate with subtypes. """ - blank_line_calculator = _BlankLineCalculator() - blank_line_calculator.Visit( tree ) - - -class _BlankLineCalculator( pytree_visitor.PyTreeVisitor ): - """_BlankLineCalculator - see file-level docstring for a description.""" - - def __init__( self ): - self.class_level = 0 - self.function_level = 0 - self.last_comment_lineno = 0 - self.last_was_decorator = False - self.last_was_class_or_function = False - - def Visit_simple_stmt( self, node ): # pylint: disable=invalid-name - self.DefaultNodeVisit( node ) - if node.children[ 0 ].type == grammar_token.COMMENT: - self.last_comment_lineno = node.children[ 0 ].lineno - - def Visit_decorator( self, node ): # pylint: disable=invalid-name - if ( self.last_comment_lineno and - self.last_comment_lineno == node.children[ 0 ].lineno - 1 ): - _SetNumNewlines( node.children[ 0 ], _NO_BLANK_LINES ) - else: - _SetNumNewlines( node.children[ 0 ], self._GetNumNewlines( node ) ) - for child in node.children: - self.Visit( child ) - self.last_was_decorator = True - - def Visit_classdef( self, node ): # pylint: disable=invalid-name - self.last_was_class_or_function = False - index = self._SetBlankLinesBetweenCommentAndClassFunc( node ) - self.last_was_decorator = False - self.class_level += 1 - for child in node.children[ index : ]: - self.Visit( child ) - self.class_level -= 1 - self.last_was_class_or_function = True - - def Visit_funcdef( self, node ): # pylint: disable=invalid-name - self.last_was_class_or_function = False - index = self._SetBlankLinesBetweenCommentAndClassFunc( node ) - if _AsyncFunction( node ): - index = self._SetBlankLinesBetweenCommentAndClassFunc( - node.prev_sibling.parent ) - _SetNumNewlines( node.children[ 0 ], None ) - else: - index = self._SetBlankLinesBetweenCommentAndClassFunc( node ) - self.last_was_decorator = False - self.function_level += 1 - for child in node.children[ index : ]: - self.Visit( child ) - self.function_level -= 1 - self.last_was_class_or_function = True - - def DefaultNodeVisit( self, node ): - """Override the default visitor for Node. + blank_line_calculator = _BlankLineCalculator() + blank_line_calculator.Visit(tree) + + +class _BlankLineCalculator(pytree_visitor.PyTreeVisitor): + """_BlankLineCalculator - see file-level docstring for a description.""" + + def __init__(self): + self.class_level = 0 + self.function_level = 0 + self.last_comment_lineno = 0 + self.last_was_decorator = False + self.last_was_class_or_function = False + + def Visit_simple_stmt(self, node): # pylint: disable=invalid-name + self.DefaultNodeVisit(node) + if node.children[0].type == grammar_token.COMMENT: + self.last_comment_lineno = node.children[0].lineno + + def Visit_decorator(self, node): # pylint: disable=invalid-name + if (self.last_comment_lineno and + self.last_comment_lineno == node.children[0].lineno - 1): + _SetNumNewlines(node.children[0], _NO_BLANK_LINES) + else: + _SetNumNewlines(node.children[0], self._GetNumNewlines(node)) + for child in node.children: + self.Visit(child) + self.last_was_decorator = True + + def Visit_classdef(self, node): # pylint: disable=invalid-name + self.last_was_class_or_function = False + index = self._SetBlankLinesBetweenCommentAndClassFunc(node) + self.last_was_decorator = False + self.class_level += 1 + for child in node.children[index:]: + self.Visit(child) + self.class_level -= 1 + self.last_was_class_or_function = True + + def Visit_funcdef(self, node): # pylint: disable=invalid-name + self.last_was_class_or_function = False + index = self._SetBlankLinesBetweenCommentAndClassFunc(node) + if _AsyncFunction(node): + index = self._SetBlankLinesBetweenCommentAndClassFunc( + node.prev_sibling.parent) + _SetNumNewlines(node.children[0], None) + else: + index = self._SetBlankLinesBetweenCommentAndClassFunc(node) + self.last_was_decorator = False + self.function_level += 1 + for child in node.children[index:]: + self.Visit(child) + self.function_level -= 1 + self.last_was_class_or_function = True + + def DefaultNodeVisit(self, node): + """Override the default visitor for Node. This will set the blank lines required if the last entity was a class or function. @@ -114,15 +115,15 @@ def DefaultNodeVisit( self, node ): Arguments: node: (pytree.Node) The node to visit. """ - if self.last_was_class_or_function: - if pytree_utils.NodeName( node ) in _PYTHON_STATEMENTS: - leaf = pytree_utils.FirstLeafNode( node ) - _SetNumNewlines( leaf, self._GetNumNewlines( leaf ) ) - self.last_was_class_or_function = False - super( _BlankLineCalculator, self ).DefaultNodeVisit( node ) + if self.last_was_class_or_function: + if pytree_utils.NodeName(node) in _PYTHON_STATEMENTS: + leaf = pytree_utils.FirstLeafNode(node) + _SetNumNewlines(leaf, self._GetNumNewlines(leaf)) + self.last_was_class_or_function = False + super(_BlankLineCalculator, self).DefaultNodeVisit(node) - def _SetBlankLinesBetweenCommentAndClassFunc( self, node ): - """Set the number of blanks between a comment and class or func definition. + def _SetBlankLinesBetweenCommentAndClassFunc(self, node): + """Set the number of blanks between a comment and class or func definition. Class and function definitions have leading comments as children of the classdef and functdef nodes. @@ -133,50 +134,50 @@ def _SetBlankLinesBetweenCommentAndClassFunc( self, node ): Returns: The index of the first child past the comment nodes. """ - index = 0 - while pytree_utils.IsCommentStatement( node.children[ index ] ): - # Standalone comments are wrapped in a simple_stmt node with the comment - # node as its only child. - self.Visit( node.children[ index ].children[ 0 ] ) - if not self.last_was_decorator: - _SetNumNewlines( node.children[ index ].children[ 0 ], _ONE_BLANK_LINE ) - index += 1 - if ( index and node.children[ index ].lineno - 1 - == node.children[ index - 1 ].children[ 0 ].lineno ): - _SetNumNewlines( node.children[ index ], _NO_BLANK_LINES ) - else: - if self.last_comment_lineno + 1 == node.children[ index ].lineno: - num_newlines = _NO_BLANK_LINES - else: - num_newlines = self._GetNumNewlines( node ) - _SetNumNewlines( node.children[ index ], num_newlines ) - return index - - def _GetNumNewlines( self, node ): - if self.last_was_decorator: - return _NO_BLANK_LINES - elif self._IsTopLevel( node ): - return 1 + style.Get( 'BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION' ) - return _ONE_BLANK_LINE - - def _IsTopLevel( self, node ): - return ( - not ( self.class_level or self.function_level ) and - _StartsInZerothColumn( node ) ) - - -def _SetNumNewlines( node, num_newlines ): - pytree_utils.SetNodeAnnotation( - node, pytree_utils.Annotation.NEWLINES, num_newlines ) - - -def _StartsInZerothColumn( node ): + index = 0 + while pytree_utils.IsCommentStatement(node.children[index]): + # Standalone comments are wrapped in a simple_stmt node with the comment + # node as its only child. + self.Visit(node.children[index].children[0]) + if not self.last_was_decorator: + _SetNumNewlines(node.children[index].children[0], _ONE_BLANK_LINE) + index += 1 + if (index and node.children[index].lineno - 1 + == node.children[index - 1].children[0].lineno): + _SetNumNewlines(node.children[index], _NO_BLANK_LINES) + else: + if self.last_comment_lineno + 1 == node.children[index].lineno: + num_newlines = _NO_BLANK_LINES + else: + num_newlines = self._GetNumNewlines(node) + _SetNumNewlines(node.children[index], num_newlines) + return index + + def _GetNumNewlines(self, node): + if self.last_was_decorator: + return _NO_BLANK_LINES + elif self._IsTopLevel(node): + return 1 + style.Get('BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION') + return _ONE_BLANK_LINE + + def _IsTopLevel(self, node): return ( - pytree_utils.FirstLeafNode( node ).column == 0 or - ( _AsyncFunction( node ) and node.prev_sibling.column == 0 ) ) + not (self.class_level or self.function_level) and + _StartsInZerothColumn(node)) -def _AsyncFunction( node ): - return ( - py3compat.PY3 and node.prev_sibling and - node.prev_sibling.type == grammar_token.ASYNC ) +def _SetNumNewlines(node, num_newlines): + pytree_utils.SetNodeAnnotation( + node, pytree_utils.Annotation.NEWLINES, num_newlines) + + +def _StartsInZerothColumn(node): + return ( + pytree_utils.FirstLeafNode(node).column == 0 or + (_AsyncFunction(node) and node.prev_sibling.column == 0)) + + +def _AsyncFunction(node): + return ( + py3compat.PY3 and node.prev_sibling and + node.prev_sibling.type == grammar_token.ASYNC) diff --git a/yapf/pytree/comment_splicer.py b/yapf/pytree/comment_splicer.py index 33706ae47..01911c896 100644 --- a/yapf/pytree/comment_splicer.py +++ b/yapf/pytree/comment_splicer.py @@ -28,8 +28,8 @@ from yapf.pytree import pytree_utils -def SpliceComments( tree ): - """Given a pytree, splice comments into nodes of their own right. +def SpliceComments(tree): + """Given a pytree, splice comments into nodes of their own right. Extract comments from the prefixes where they are housed after parsing. The prefixes that previously housed the comments become empty. @@ -38,189 +38,175 @@ def SpliceComments( tree ): tree: a pytree.Node - the tree to work on. The tree is modified by this function. """ - # The previous leaf node encountered in the traversal. - # This is a list because Python 2.x doesn't have 'nonlocal' :) - prev_leaf = [ None ] - _AnnotateIndents( tree ) - - def _VisitNodeRec( node ): - """Recursively visit each node to splice comments into the AST.""" - # This loop may insert into node.children, so we'll iterate over a copy. - for child in node.children[ : ]: - if isinstance( child, pytree.Node ): - # Nodes don't have prefixes. - _VisitNodeRec( child ) - else: - if child.prefix.lstrip().startswith( '#' ): - # We have a comment prefix in this child, so splicing is needed. - comment_prefix = child.prefix - comment_lineno = child.lineno - comment_prefix.count( '\n' ) - comment_column = child.column - - # Remember the leading indentation of this prefix and clear it. - # Mopping up the prefix is important because we may go over this same - # child in the next iteration... - child_prefix = child.prefix.lstrip( '\n' ) - prefix_indent = child_prefix[ : child_prefix.find( '#' ) ] - if '\n' in prefix_indent: - prefix_indent = prefix_indent[ prefix_indent.rfind( '\n' ) + - 1 : ] - child.prefix = '' - - if child.type == token.NEWLINE: - # If the prefix was on a NEWLINE leaf, it's part of the line so it - # will be inserted after the previously encountered leaf. - # We can't just insert it before the NEWLINE node, because as a - # result of the way pytrees are organized, this node can be under - # an inappropriate parent. - comment_column -= len( comment_prefix.lstrip() ) - pytree_utils.InsertNodesAfter( - _CreateCommentsFromPrefix( - comment_prefix, - comment_lineno, - comment_column, - standalone = False ), prev_leaf[ 0 ] ) - elif child.type == token.DEDENT: - # Comment prefixes on DEDENT nodes also deserve special treatment, - # because their final placement depends on their prefix. - # We'll look for an ancestor of this child with a matching - # indentation, and insert the comment before it if the ancestor is - # on a DEDENT node and after it otherwise. - # - # lib2to3 places comments that should be separated into the same - # DEDENT node. For example, "comment 1" and "comment 2" will be - # combined. - # - # def _(): - # for x in y: - # pass - # # comment 1 - # - # # comment 2 - # pass - # - # In this case, we need to split them up ourselves. - - # Split into groups of comments at decreasing levels of indentation - comment_groups = [] - comment_column = None - for cmt in comment_prefix.split( '\n' ): - col = cmt.find( '#' ) - if col < 0: - if comment_column is None: - # Skip empty lines at the top of the first comment group - comment_lineno += 1 - continue - elif comment_column is None or col < comment_column: - comment_column = col - comment_indent = cmt[ : comment_column ] - comment_groups.append( - ( comment_column, comment_indent, [] ) ) - comment_groups[ -1 ][ -1 ].append( cmt ) - - # Insert a node for each group - for comment_column, comment_indent, comment_group in comment_groups: - ancestor_at_indent = _FindAncestorAtIndent( - child, comment_indent ) - if ancestor_at_indent.type == token.DEDENT: - InsertNodes = pytree_utils.InsertNodesBefore # pylint: disable=invalid-name # noqa - else: - InsertNodes = pytree_utils.InsertNodesAfter # pylint: disable=invalid-name # noqa - InsertNodes( - _CreateCommentsFromPrefix( - '\n'.join( comment_group ) + '\n', - comment_lineno, - comment_column, - standalone = True ), ancestor_at_indent ) - comment_lineno += len( comment_group ) - else: - # Otherwise there are two cases. - # - # 1. The comment is on its own line - # 2. The comment is part of an expression. - # - # Unfortunately, it's fairly difficult to distinguish between the - # two in lib2to3 trees. The algorithm here is to determine whether - # child is the first leaf in the statement it belongs to. If it is, - # then the comment (which is a prefix) belongs on a separate line. - # If it is not, it means the comment is buried deep in the statement - # and is part of some expression. - stmt_parent = _FindStmtParent( child ) - - for leaf_in_parent in stmt_parent.leaves(): - if leaf_in_parent.type == token.NEWLINE: - continue - elif id( leaf_in_parent ) == id( child ): - # This comment stands on its own line, and it has to be inserted - # into the appropriate parent. We'll have to find a suitable - # parent to insert into. See comments above - # _STANDALONE_LINE_NODES for more details. - node_with_line_parent = _FindNodeWithStandaloneLineParent( - child ) - - if pytree_utils.NodeName( - node_with_line_parent.parent ) in { 'funcdef', - 'classdef' - }: - # Keep a comment that's not attached to a function or class - # next to the object it is attached to. - comment_end = ( - comment_lineno + - comment_prefix.rstrip( '\n' ).count( '\n' ) ) - if comment_end < node_with_line_parent.lineno - 1: - node_with_line_parent = node_with_line_parent.parent - - pytree_utils.InsertNodesBefore( - _CreateCommentsFromPrefix( - comment_prefix, - comment_lineno, - 0, - standalone = True ), node_with_line_parent ) - break - else: - if comment_lineno == prev_leaf[ 0 ].lineno: - comment_lines = comment_prefix.splitlines() - value = comment_lines[ 0 ].lstrip() - if value.rstrip( '\n' ): - comment_column = prev_leaf[ 0 ].column - comment_column += len( prev_leaf[ 0 ].value ) - comment_column += ( - len( comment_lines[ 0 ] ) - - len( comment_lines[ 0 ].lstrip() ) ) - comment_leaf = pytree.Leaf( - type = token.COMMENT, - value = value.rstrip( '\n' ), - context = ( - '', ( comment_lineno, - comment_column ) ) ) - pytree_utils.InsertNodesAfter( - [ comment_leaf ], prev_leaf[ 0 ] ) - comment_prefix = '\n'.join( - comment_lines[ 1 : ] ) - comment_lineno += 1 - - rindex = ( - 0 if '\n' not in comment_prefix.rstrip() else - comment_prefix.rstrip().rindex( '\n' ) + 1 ) - comment_column = ( - len( comment_prefix[ rindex : ] ) - - len( comment_prefix[ rindex : ].lstrip() ) ) - comments = _CreateCommentsFromPrefix( - comment_prefix, - comment_lineno, - comment_column, - standalone = False ) - pytree_utils.InsertNodesBefore( comments, child ) - break - - prev_leaf[ 0 ] = child - - _VisitNodeRec( tree ) + # The previous leaf node encountered in the traversal. + # This is a list because Python 2.x doesn't have 'nonlocal' :) + prev_leaf = [None] + _AnnotateIndents(tree) + + def _VisitNodeRec(node): + """Recursively visit each node to splice comments into the AST.""" + # This loop may insert into node.children, so we'll iterate over a copy. + for child in node.children[:]: + if isinstance(child, pytree.Node): + # Nodes don't have prefixes. + _VisitNodeRec(child) + else: + if child.prefix.lstrip().startswith('#'): + # We have a comment prefix in this child, so splicing is needed. + comment_prefix = child.prefix + comment_lineno = child.lineno - comment_prefix.count('\n') + comment_column = child.column + + # Remember the leading indentation of this prefix and clear it. + # Mopping up the prefix is important because we may go over this same + # child in the next iteration... + child_prefix = child.prefix.lstrip('\n') + prefix_indent = child_prefix[:child_prefix.find('#')] + if '\n' in prefix_indent: + prefix_indent = prefix_indent[prefix_indent.rfind('\n') + 1:] + child.prefix = '' + + if child.type == token.NEWLINE: + # If the prefix was on a NEWLINE leaf, it's part of the line so it + # will be inserted after the previously encountered leaf. + # We can't just insert it before the NEWLINE node, because as a + # result of the way pytrees are organized, this node can be under + # an inappropriate parent. + comment_column -= len(comment_prefix.lstrip()) + pytree_utils.InsertNodesAfter( + _CreateCommentsFromPrefix( + comment_prefix, + comment_lineno, + comment_column, + standalone=False), prev_leaf[0]) + elif child.type == token.DEDENT: + # Comment prefixes on DEDENT nodes also deserve special treatment, + # because their final placement depends on their prefix. + # We'll look for an ancestor of this child with a matching + # indentation, and insert the comment before it if the ancestor is + # on a DEDENT node and after it otherwise. + # + # lib2to3 places comments that should be separated into the same + # DEDENT node. For example, "comment 1" and "comment 2" will be + # combined. + # + # def _(): + # for x in y: + # pass + # # comment 1 + # + # # comment 2 + # pass + # + # In this case, we need to split them up ourselves. + + # Split into groups of comments at decreasing levels of indentation + comment_groups = [] + comment_column = None + for cmt in comment_prefix.split('\n'): + col = cmt.find('#') + if col < 0: + if comment_column is None: + # Skip empty lines at the top of the first comment group + comment_lineno += 1 + continue + elif comment_column is None or col < comment_column: + comment_column = col + comment_indent = cmt[:comment_column] + comment_groups.append((comment_column, comment_indent, [])) + comment_groups[-1][-1].append(cmt) + + # Insert a node for each group + for comment_column, comment_indent, comment_group in comment_groups: + ancestor_at_indent = _FindAncestorAtIndent(child, comment_indent) + if ancestor_at_indent.type == token.DEDENT: + InsertNodes = pytree_utils.InsertNodesBefore # pylint: disable=invalid-name # noqa + else: + InsertNodes = pytree_utils.InsertNodesAfter # pylint: disable=invalid-name # noqa + InsertNodes( + _CreateCommentsFromPrefix( + '\n'.join(comment_group) + '\n', + comment_lineno, + comment_column, + standalone=True), ancestor_at_indent) + comment_lineno += len(comment_group) + else: + # Otherwise there are two cases. + # + # 1. The comment is on its own line + # 2. The comment is part of an expression. + # + # Unfortunately, it's fairly difficult to distinguish between the + # two in lib2to3 trees. The algorithm here is to determine whether + # child is the first leaf in the statement it belongs to. If it is, + # then the comment (which is a prefix) belongs on a separate line. + # If it is not, it means the comment is buried deep in the statement + # and is part of some expression. + stmt_parent = _FindStmtParent(child) + + for leaf_in_parent in stmt_parent.leaves(): + if leaf_in_parent.type == token.NEWLINE: + continue + elif id(leaf_in_parent) == id(child): + # This comment stands on its own line, and it has to be inserted + # into the appropriate parent. We'll have to find a suitable + # parent to insert into. See comments above + # _STANDALONE_LINE_NODES for more details. + node_with_line_parent = _FindNodeWithStandaloneLineParent(child) + + if pytree_utils.NodeName( + node_with_line_parent.parent) in {'funcdef', 'classdef'}: + # Keep a comment that's not attached to a function or class + # next to the object it is attached to. + comment_end = ( + comment_lineno + comment_prefix.rstrip('\n').count('\n')) + if comment_end < node_with_line_parent.lineno - 1: + node_with_line_parent = node_with_line_parent.parent + + pytree_utils.InsertNodesBefore( + _CreateCommentsFromPrefix( + comment_prefix, comment_lineno, 0, standalone=True), + node_with_line_parent) + break + else: + if comment_lineno == prev_leaf[0].lineno: + comment_lines = comment_prefix.splitlines() + value = comment_lines[0].lstrip() + if value.rstrip('\n'): + comment_column = prev_leaf[0].column + comment_column += len(prev_leaf[0].value) + comment_column += ( + len(comment_lines[0]) - len(comment_lines[0].lstrip())) + comment_leaf = pytree.Leaf( + type=token.COMMENT, + value=value.rstrip('\n'), + context=('', (comment_lineno, comment_column))) + pytree_utils.InsertNodesAfter([comment_leaf], prev_leaf[0]) + comment_prefix = '\n'.join(comment_lines[1:]) + comment_lineno += 1 + + rindex = ( + 0 if '\n' not in comment_prefix.rstrip() else + comment_prefix.rstrip().rindex('\n') + 1) + comment_column = ( + len(comment_prefix[rindex:]) - + len(comment_prefix[rindex:].lstrip())) + comments = _CreateCommentsFromPrefix( + comment_prefix, + comment_lineno, + comment_column, + standalone=False) + pytree_utils.InsertNodesBefore(comments, child) + break + + prev_leaf[0] = child + + _VisitNodeRec(tree) def _CreateCommentsFromPrefix( - comment_prefix, comment_lineno, comment_column, standalone = False ): - """Create pytree nodes to represent the given comment prefix. + comment_prefix, comment_lineno, comment_column, standalone=False): + """Create pytree nodes to represent the given comment prefix. Args: comment_prefix: (unicode) the text of the comment from the node's prefix. @@ -233,35 +219,35 @@ def _CreateCommentsFromPrefix( new COMMENT leafs. The prefix may consist of multiple comment blocks, separated by blank lines. Each block gets its own leaf. """ - # The comment is stored in the prefix attribute, with no lineno of its - # own. So we only know at which line it ends. To find out at which line it - # starts, look at how many newlines the comment itself contains. - comments = [] - - lines = comment_prefix.split( '\n' ) - index = 0 - while index < len( lines ): - comment_block = [] - while index < len( lines ) and lines[ index ].lstrip().startswith( '#' ): - comment_block.append( lines[ index ].strip() ) - index += 1 - - if comment_block: - new_lineno = comment_lineno + index - 1 - comment_block[ 0 ] = comment_block[ 0 ].strip() - comment_block[ -1 ] = comment_block[ -1 ].strip() - comment_leaf = pytree.Leaf( - type = token.COMMENT, - value = '\n'.join( comment_block ), - context = ( '', ( new_lineno, comment_column ) ) ) - comment_node = comment_leaf if not standalone else pytree.Node( - pygram.python_symbols.simple_stmt, [ comment_leaf ] ) - comments.append( comment_node ) - - while index < len( lines ) and not lines[ index ].lstrip(): - index += 1 - - return comments + # The comment is stored in the prefix attribute, with no lineno of its + # own. So we only know at which line it ends. To find out at which line it + # starts, look at how many newlines the comment itself contains. + comments = [] + + lines = comment_prefix.split('\n') + index = 0 + while index < len(lines): + comment_block = [] + while index < len(lines) and lines[index].lstrip().startswith('#'): + comment_block.append(lines[index].strip()) + index += 1 + + if comment_block: + new_lineno = comment_lineno + index - 1 + comment_block[0] = comment_block[0].strip() + comment_block[-1] = comment_block[-1].strip() + comment_leaf = pytree.Leaf( + type=token.COMMENT, + value='\n'.join(comment_block), + context=('', (new_lineno, comment_column))) + comment_node = comment_leaf if not standalone else pytree.Node( + pygram.python_symbols.simple_stmt, [comment_leaf]) + comments.append(comment_node) + + while index < len(lines) and not lines[index].lstrip(): + index += 1 + + return comments # "Standalone line nodes" are tree nodes that have to start a new line in Python @@ -279,11 +265,11 @@ def _CreateCommentsFromPrefix( [ 'suite', 'if_stmt', 'while_stmt', 'for_stmt', 'try_stmt', 'with_stmt', 'funcdef', 'classdef', 'decorated', 'file_input' - ] ) + ]) -def _FindNodeWithStandaloneLineParent( node ): - """Find a node whose parent is a 'standalone line' node. +def _FindNodeWithStandaloneLineParent(node): + """Find a node whose parent is a 'standalone line' node. See the comment above _STANDALONE_LINE_NODES for more details. @@ -293,21 +279,21 @@ def _FindNodeWithStandaloneLineParent( node ): Returns: Suitable node that's either the node itself or one of its ancestors. """ - if pytree_utils.NodeName( node.parent ) in _STANDALONE_LINE_NODES: - return node - else: - # This is guaranteed to terminate because 'file_input' is the root node of - # any pytree. - return _FindNodeWithStandaloneLineParent( node.parent ) + if pytree_utils.NodeName(node.parent) in _STANDALONE_LINE_NODES: + return node + else: + # This is guaranteed to terminate because 'file_input' is the root node of + # any pytree. + return _FindNodeWithStandaloneLineParent(node.parent) # "Statement nodes" are standalone statements. The don't have to start a new # line. -_STATEMENT_NODES = frozenset( [ 'simple_stmt' ] ) | _STANDALONE_LINE_NODES +_STATEMENT_NODES = frozenset(['simple_stmt']) | _STANDALONE_LINE_NODES -def _FindStmtParent( node ): - """Find the nearest parent of node that is a statement node. +def _FindStmtParent(node): + """Find the nearest parent of node that is a statement node. Arguments: node: node to start from @@ -315,14 +301,14 @@ def _FindStmtParent( node ): Returns: Nearest parent (or node itself, if suitable). """ - if pytree_utils.NodeName( node ) in _STATEMENT_NODES: - return node - else: - return _FindStmtParent( node.parent ) + if pytree_utils.NodeName(node) in _STATEMENT_NODES: + return node + else: + return _FindStmtParent(node.parent) -def _FindAncestorAtIndent( node, indent ): - """Find an ancestor of node with the given indentation. +def _FindAncestorAtIndent(node, indent): + """Find an ancestor of node with the given indentation. Arguments: node: node to start from. This must not be the tree root. @@ -333,27 +319,27 @@ def _FindAncestorAtIndent( node, indent ): An ancestor node with suitable indentation. If no suitable ancestor is found, the closest ancestor to the tree root is returned. """ - if node.parent.parent is None: - # Our parent is the tree root, so there's nowhere else to go. - return node - - # If the parent has an indent annotation, and it's shorter than node's - # indent, this is a suitable ancestor. - # The reason for "shorter" rather than "equal" is that comments may be - # improperly indented (i.e. by three spaces, where surrounding statements - # have either zero or two or four), and we don't want to propagate them all - # the way to the root. - parent_indent = pytree_utils.GetNodeAnnotation( - node.parent, pytree_utils.Annotation.CHILD_INDENT ) - if parent_indent is not None and indent.startswith( parent_indent ): - return node - else: - # Keep looking up the tree. - return _FindAncestorAtIndent( node.parent, indent ) - - -def _AnnotateIndents( tree ): - """Annotate the tree with child_indent annotations. + if node.parent.parent is None: + # Our parent is the tree root, so there's nowhere else to go. + return node + + # If the parent has an indent annotation, and it's shorter than node's + # indent, this is a suitable ancestor. + # The reason for "shorter" rather than "equal" is that comments may be + # improperly indented (i.e. by three spaces, where surrounding statements + # have either zero or two or four), and we don't want to propagate them all + # the way to the root. + parent_indent = pytree_utils.GetNodeAnnotation( + node.parent, pytree_utils.Annotation.CHILD_INDENT) + if parent_indent is not None and indent.startswith(parent_indent): + return node + else: + # Keep looking up the tree. + return _FindAncestorAtIndent(node.parent, indent) + + +def _AnnotateIndents(tree): + """Annotate the tree with child_indent annotations. A child_indent annotation on a node specifies the indentation (as a string, like " ") of its children. It is inferred from the INDENT child of a node. @@ -364,16 +350,16 @@ def _AnnotateIndents( tree ): Raises: RuntimeError: if the tree is malformed. """ - # Annotate the root of the tree with zero indent. - if tree.parent is None: - pytree_utils.SetNodeAnnotation( tree, pytree_utils.Annotation.CHILD_INDENT, '' ) - for child in tree.children: - if child.type == token.INDENT: - child_indent = pytree_utils.GetNodeAnnotation( - tree, pytree_utils.Annotation.CHILD_INDENT ) - if child_indent is not None and child_indent != child.value: - raise RuntimeError( - 'inconsistent indentation for child', ( tree, child ) ) - pytree_utils.SetNodeAnnotation( - tree, pytree_utils.Annotation.CHILD_INDENT, child.value ) - _AnnotateIndents( child ) + # Annotate the root of the tree with zero indent. + if tree.parent is None: + pytree_utils.SetNodeAnnotation( + tree, pytree_utils.Annotation.CHILD_INDENT, '') + for child in tree.children: + if child.type == token.INDENT: + child_indent = pytree_utils.GetNodeAnnotation( + tree, pytree_utils.Annotation.CHILD_INDENT) + if child_indent is not None and child_indent != child.value: + raise RuntimeError('inconsistent indentation for child', (tree, child)) + pytree_utils.SetNodeAnnotation( + tree, pytree_utils.Annotation.CHILD_INDENT, child.value) + _AnnotateIndents(child) diff --git a/yapf/pytree/continuation_splicer.py b/yapf/pytree/continuation_splicer.py index dea4de29f..b86188cb5 100644 --- a/yapf/pytree/continuation_splicer.py +++ b/yapf/pytree/continuation_splicer.py @@ -24,29 +24,29 @@ from yapf.yapflib import format_token -def SpliceContinuations( tree ): - """Given a pytree, splice the continuation marker into nodes. +def SpliceContinuations(tree): + """Given a pytree, splice the continuation marker into nodes. Arguments: tree: (pytree.Node) The tree to work on. The tree is modified by this function. """ - def RecSplicer( node ): - """Inserts a continuation marker into the node.""" - if isinstance( node, pytree.Leaf ): - if node.prefix.lstrip().startswith( '\\\n' ): - new_lineno = node.lineno - node.prefix.count( '\n' ) - return pytree.Leaf( - type = format_token.CONTINUATION, - value = node.prefix, - context = ( '', ( new_lineno, 0 ) ) ) - return None - num_inserted = 0 - for index, child in enumerate( node.children[ : ] ): - continuation_node = RecSplicer( child ) - if continuation_node: - node.children.insert( index + num_inserted, continuation_node ) - num_inserted += 1 - - RecSplicer( tree ) + def RecSplicer(node): + """Inserts a continuation marker into the node.""" + if isinstance(node, pytree.Leaf): + if node.prefix.lstrip().startswith('\\\n'): + new_lineno = node.lineno - node.prefix.count('\n') + return pytree.Leaf( + type=format_token.CONTINUATION, + value=node.prefix, + context=('', (new_lineno, 0))) + return None + num_inserted = 0 + for index, child in enumerate(node.children[:]): + continuation_node = RecSplicer(child) + if continuation_node: + node.children.insert(index + num_inserted, continuation_node) + num_inserted += 1 + + RecSplicer(tree) diff --git a/yapf/pytree/pytree_unwrapper.py b/yapf/pytree/pytree_unwrapper.py index 89618066b..835ca60a1 100644 --- a/yapf/pytree/pytree_unwrapper.py +++ b/yapf/pytree/pytree_unwrapper.py @@ -40,12 +40,12 @@ from yapf.yapflib import style from yapf.yapflib import subtypes -_OPENING_BRACKETS = frozenset( { '(', '[', '{' } ) -_CLOSING_BRACKETS = frozenset( { ')', ']', '}' } ) +_OPENING_BRACKETS = frozenset({'(', '[', '{'}) +_CLOSING_BRACKETS = frozenset({')', ']', '}'}) -def UnwrapPyTree( tree ): - """Create and return a list of logical lines from the given pytree. +def UnwrapPyTree(tree): + """Create and return a list of logical lines from the given pytree. Arguments: tree: the top-level pytree node to unwrap.. @@ -53,11 +53,11 @@ def UnwrapPyTree( tree ): Returns: A list of LogicalLine objects. """ - unwrapper = PyTreeUnwrapper() - unwrapper.Visit( tree ) - llines = unwrapper.GetLogicalLines() - llines.sort( key = lambda x: x.lineno ) - return llines + unwrapper = PyTreeUnwrapper() + unwrapper.Visit(tree) + llines = unwrapper.GetLogicalLines() + llines.sort(key=lambda x: x.lineno) + return llines # Grammar tokens considered as whitespace for the purpose of unwrapping. @@ -65,11 +65,11 @@ def UnwrapPyTree( tree ): [ grammar_token.NEWLINE, grammar_token.DEDENT, grammar_token.INDENT, grammar_token.ENDMARKER - ] ) + ]) -class PyTreeUnwrapper( pytree_visitor.PyTreeVisitor ): - """PyTreeUnwrapper - see file-level docstring for detailed description. +class PyTreeUnwrapper(pytree_visitor.PyTreeVisitor): + """PyTreeUnwrapper - see file-level docstring for detailed description. Note: since this implements PyTreeVisitor and node names in lib2to3 are underscore_separated, the visiting methods of this class are named as @@ -83,78 +83,78 @@ class PyTreeUnwrapper( pytree_visitor.PyTreeVisitor ): familiarity with the Python grammar is required. """ - def __init__( self ): - # A list of all logical lines finished visiting so far. - self._logical_lines = [] + def __init__(self): + # A list of all logical lines finished visiting so far. + self._logical_lines = [] - # Builds up a "current" logical line while visiting pytree nodes. Some nodes - # will finish a line and start a new one. - self._cur_logical_line = logical_line.LogicalLine( 0 ) + # Builds up a "current" logical line while visiting pytree nodes. Some nodes + # will finish a line and start a new one. + self._cur_logical_line = logical_line.LogicalLine(0) - # Current indentation depth. - self._cur_depth = 0 + # Current indentation depth. + self._cur_depth = 0 - def GetLogicalLines( self ): - """Fetch the result of the tree walk. + def GetLogicalLines(self): + """Fetch the result of the tree walk. Note: only call this after visiting the whole tree. Returns: A list of LogicalLine objects. """ - # Make sure the last line that was being populated is flushed. - self._StartNewLine() - return self._logical_lines + # Make sure the last line that was being populated is flushed. + self._StartNewLine() + return self._logical_lines - def _StartNewLine( self ): - """Finish current line and start a new one. + def _StartNewLine(self): + """Finish current line and start a new one. Place the currently accumulated line into the _logical_lines list and start a new one. """ - if self._cur_logical_line.tokens: - self._logical_lines.append( self._cur_logical_line ) - _MatchBrackets( self._cur_logical_line ) - _IdentifyParameterLists( self._cur_logical_line ) - _AdjustSplitPenalty( self._cur_logical_line ) - self._cur_logical_line = logical_line.LogicalLine( self._cur_depth ) - - _STMT_TYPES = frozenset( - { - 'if_stmt', - 'while_stmt', - 'for_stmt', - 'try_stmt', - 'expect_clause', - 'with_stmt', - 'funcdef', - 'classdef', - } ) - - # pylint: disable=invalid-name,missing-docstring - def Visit_simple_stmt( self, node ): - # A 'simple_stmt' conveniently represents a non-compound Python statement, - # i.e. a statement that does not contain other statements. - - # When compound nodes have a single statement as their suite, the parser - # can leave it in the tree directly without creating a suite. But we have - # to increase depth in these cases as well. However, don't increase the - # depth of we have a simple_stmt that's a comment node. This represents a - # standalone comment and in the case of it coming directly after the - # funcdef, it is a "top" comment for the whole function. - # TODO(eliben): add more relevant compound statements here. - single_stmt_suite = ( - node.parent and pytree_utils.NodeName( node.parent ) in self._STMT_TYPES ) - is_comment_stmt = pytree_utils.IsCommentStatement( node ) - if single_stmt_suite and not is_comment_stmt: - self._cur_depth += 1 - self._StartNewLine() - self.DefaultNodeVisit( node ) - if single_stmt_suite and not is_comment_stmt: - self._cur_depth -= 1 - - def _VisitCompoundStatement( self, node, substatement_names ): - """Helper for visiting compound statements. + if self._cur_logical_line.tokens: + self._logical_lines.append(self._cur_logical_line) + _MatchBrackets(self._cur_logical_line) + _IdentifyParameterLists(self._cur_logical_line) + _AdjustSplitPenalty(self._cur_logical_line) + self._cur_logical_line = logical_line.LogicalLine(self._cur_depth) + + _STMT_TYPES = frozenset( + { + 'if_stmt', + 'while_stmt', + 'for_stmt', + 'try_stmt', + 'expect_clause', + 'with_stmt', + 'funcdef', + 'classdef', + }) + + # pylint: disable=invalid-name,missing-docstring + def Visit_simple_stmt(self, node): + # A 'simple_stmt' conveniently represents a non-compound Python statement, + # i.e. a statement that does not contain other statements. + + # When compound nodes have a single statement as their suite, the parser + # can leave it in the tree directly without creating a suite. But we have + # to increase depth in these cases as well. However, don't increase the + # depth of we have a simple_stmt that's a comment node. This represents a + # standalone comment and in the case of it coming directly after the + # funcdef, it is a "top" comment for the whole function. + # TODO(eliben): add more relevant compound statements here. + single_stmt_suite = ( + node.parent and pytree_utils.NodeName(node.parent) in self._STMT_TYPES) + is_comment_stmt = pytree_utils.IsCommentStatement(node) + if single_stmt_suite and not is_comment_stmt: + self._cur_depth += 1 + self._StartNewLine() + self.DefaultNodeVisit(node) + if single_stmt_suite and not is_comment_stmt: + self._cur_depth -= 1 + + def _VisitCompoundStatement(self, node, substatement_names): + """Helper for visiting compound statements. Python compound statements serve as containers for other statements. Thus, when we encounter a new compound statement, we start a new logical line. @@ -164,150 +164,150 @@ def _VisitCompoundStatement( self, node, substatement_names ): substatement_names: set of node names. A compound statement will be recognized as a NAME node with a name in this set. """ - for child in node.children: - # A pytree is structured in such a way that a single 'if_stmt' node will - # contain all the 'if', 'elif' and 'else' nodes as children (similar - # structure applies to 'while' statements, 'try' blocks, etc). Therefore, - # we visit all children here and create a new line before the requested - # set of nodes. - if ( child.type == grammar_token.NAME and - child.value in substatement_names ): - self._StartNewLine() - self.Visit( child ) + for child in node.children: + # A pytree is structured in such a way that a single 'if_stmt' node will + # contain all the 'if', 'elif' and 'else' nodes as children (similar + # structure applies to 'while' statements, 'try' blocks, etc). Therefore, + # we visit all children here and create a new line before the requested + # set of nodes. + if (child.type == grammar_token.NAME and + child.value in substatement_names): + self._StartNewLine() + self.Visit(child) - _IF_STMT_ELEMS = frozenset( { 'if', 'else', 'elif' } ) + _IF_STMT_ELEMS = frozenset({'if', 'else', 'elif'}) - def Visit_if_stmt( self, node ): # pylint: disable=invalid-name - self._VisitCompoundStatement( node, self._IF_STMT_ELEMS ) + def Visit_if_stmt(self, node): # pylint: disable=invalid-name + self._VisitCompoundStatement(node, self._IF_STMT_ELEMS) - _WHILE_STMT_ELEMS = frozenset( { 'while', 'else' } ) + _WHILE_STMT_ELEMS = frozenset({'while', 'else'}) - def Visit_while_stmt( self, node ): # pylint: disable=invalid-name - self._VisitCompoundStatement( node, self._WHILE_STMT_ELEMS ) + def Visit_while_stmt(self, node): # pylint: disable=invalid-name + self._VisitCompoundStatement(node, self._WHILE_STMT_ELEMS) - _FOR_STMT_ELEMS = frozenset( { 'for', 'else' } ) + _FOR_STMT_ELEMS = frozenset({'for', 'else'}) - def Visit_for_stmt( self, node ): # pylint: disable=invalid-name - self._VisitCompoundStatement( node, self._FOR_STMT_ELEMS ) + def Visit_for_stmt(self, node): # pylint: disable=invalid-name + self._VisitCompoundStatement(node, self._FOR_STMT_ELEMS) - _TRY_STMT_ELEMS = frozenset( { 'try', 'except', 'else', 'finally' } ) + _TRY_STMT_ELEMS = frozenset({'try', 'except', 'else', 'finally'}) - def Visit_try_stmt( self, node ): # pylint: disable=invalid-name - self._VisitCompoundStatement( node, self._TRY_STMT_ELEMS ) + def Visit_try_stmt(self, node): # pylint: disable=invalid-name + self._VisitCompoundStatement(node, self._TRY_STMT_ELEMS) - _EXCEPT_STMT_ELEMS = frozenset( { 'except' } ) + _EXCEPT_STMT_ELEMS = frozenset({'except'}) - def Visit_except_clause( self, node ): # pylint: disable=invalid-name - self._VisitCompoundStatement( node, self._EXCEPT_STMT_ELEMS ) + def Visit_except_clause(self, node): # pylint: disable=invalid-name + self._VisitCompoundStatement(node, self._EXCEPT_STMT_ELEMS) - _FUNC_DEF_ELEMS = frozenset( { 'def' } ) + _FUNC_DEF_ELEMS = frozenset({'def'}) - def Visit_funcdef( self, node ): # pylint: disable=invalid-name - self._VisitCompoundStatement( node, self._FUNC_DEF_ELEMS ) + def Visit_funcdef(self, node): # pylint: disable=invalid-name + self._VisitCompoundStatement(node, self._FUNC_DEF_ELEMS) - def Visit_async_funcdef( self, node ): # pylint: disable=invalid-name - self._StartNewLine() - index = 0 - for child in node.children: - index += 1 - self.Visit( child ) - if child.type == grammar_token.ASYNC: - break - for child in node.children[ index ].children: - self.Visit( child ) + def Visit_async_funcdef(self, node): # pylint: disable=invalid-name + self._StartNewLine() + index = 0 + for child in node.children: + index += 1 + self.Visit(child) + if child.type == grammar_token.ASYNC: + break + for child in node.children[index].children: + self.Visit(child) - _CLASS_DEF_ELEMS = frozenset( { 'class' } ) + _CLASS_DEF_ELEMS = frozenset({'class'}) - def Visit_classdef( self, node ): # pylint: disable=invalid-name - self._VisitCompoundStatement( node, self._CLASS_DEF_ELEMS ) + def Visit_classdef(self, node): # pylint: disable=invalid-name + self._VisitCompoundStatement(node, self._CLASS_DEF_ELEMS) - def Visit_async_stmt( self, node ): # pylint: disable=invalid-name + def Visit_async_stmt(self, node): # pylint: disable=invalid-name + self._StartNewLine() + index = 0 + for child in node.children: + index += 1 + self.Visit(child) + if child.type == grammar_token.ASYNC: + break + for child in node.children[index].children: + if child.type == grammar_token.NAME and child.value == 'else': self._StartNewLine() - index = 0 - for child in node.children: - index += 1 - self.Visit( child ) - if child.type == grammar_token.ASYNC: - break - for child in node.children[ index ].children: - if child.type == grammar_token.NAME and child.value == 'else': - self._StartNewLine() - self.Visit( child ) - - def Visit_decorator( self, node ): # pylint: disable=invalid-name - for child in node.children: - self.Visit( child ) - if child.type == grammar_token.COMMENT and child == node.children[ 0 ]: - self._StartNewLine() - - def Visit_decorators( self, node ): # pylint: disable=invalid-name - for child in node.children: - self._StartNewLine() - self.Visit( child ) - - def Visit_decorated( self, node ): # pylint: disable=invalid-name - for child in node.children: - self._StartNewLine() - self.Visit( child ) - - _WITH_STMT_ELEMS = frozenset( { 'with' } ) - - def Visit_with_stmt( self, node ): # pylint: disable=invalid-name - self._VisitCompoundStatement( node, self._WITH_STMT_ELEMS ) - - def Visit_suite( self, node ): # pylint: disable=invalid-name - # A 'suite' starts a new indentation level in Python. - self._cur_depth += 1 + self.Visit(child) + + def Visit_decorator(self, node): # pylint: disable=invalid-name + for child in node.children: + self.Visit(child) + if child.type == grammar_token.COMMENT and child == node.children[0]: self._StartNewLine() - self.DefaultNodeVisit( node ) - self._cur_depth -= 1 - def Visit_listmaker( self, node ): # pylint: disable=invalid-name - _DetermineMustSplitAnnotation( node ) - self.DefaultNodeVisit( node ) + def Visit_decorators(self, node): # pylint: disable=invalid-name + for child in node.children: + self._StartNewLine() + self.Visit(child) + + def Visit_decorated(self, node): # pylint: disable=invalid-name + for child in node.children: + self._StartNewLine() + self.Visit(child) + + _WITH_STMT_ELEMS = frozenset({'with'}) + + def Visit_with_stmt(self, node): # pylint: disable=invalid-name + self._VisitCompoundStatement(node, self._WITH_STMT_ELEMS) + + def Visit_suite(self, node): # pylint: disable=invalid-name + # A 'suite' starts a new indentation level in Python. + self._cur_depth += 1 + self._StartNewLine() + self.DefaultNodeVisit(node) + self._cur_depth -= 1 + + def Visit_listmaker(self, node): # pylint: disable=invalid-name + _DetermineMustSplitAnnotation(node) + self.DefaultNodeVisit(node) - def Visit_dictsetmaker( self, node ): # pylint: disable=invalid-name - _DetermineMustSplitAnnotation( node ) - self.DefaultNodeVisit( node ) + def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name + _DetermineMustSplitAnnotation(node) + self.DefaultNodeVisit(node) - def Visit_import_as_names( self, node ): # pylint: disable=invalid-name - if node.prev_sibling.value == '(': - _DetermineMustSplitAnnotation( node ) - self.DefaultNodeVisit( node ) + def Visit_import_as_names(self, node): # pylint: disable=invalid-name + if node.prev_sibling.value == '(': + _DetermineMustSplitAnnotation(node) + self.DefaultNodeVisit(node) - def Visit_testlist_gexp( self, node ): # pylint: disable=invalid-name - _DetermineMustSplitAnnotation( node ) - self.DefaultNodeVisit( node ) + def Visit_testlist_gexp(self, node): # pylint: disable=invalid-name + _DetermineMustSplitAnnotation(node) + self.DefaultNodeVisit(node) - def Visit_arglist( self, node ): # pylint: disable=invalid-name - _DetermineMustSplitAnnotation( node ) - self.DefaultNodeVisit( node ) + def Visit_arglist(self, node): # pylint: disable=invalid-name + _DetermineMustSplitAnnotation(node) + self.DefaultNodeVisit(node) - def Visit_typedargslist( self, node ): # pylint: disable=invalid-name - _DetermineMustSplitAnnotation( node ) - self.DefaultNodeVisit( node ) + def Visit_typedargslist(self, node): # pylint: disable=invalid-name + _DetermineMustSplitAnnotation(node) + self.DefaultNodeVisit(node) - def DefaultLeafVisit( self, leaf ): - """Default visitor for tree leaves. + def DefaultLeafVisit(self, leaf): + """Default visitor for tree leaves. A tree leaf is always just gets appended to the current logical line. Arguments: leaf: the leaf to visit. """ - if leaf.type in _WHITESPACE_TOKENS: - self._StartNewLine() - elif leaf.type != grammar_token.COMMENT or leaf.value.strip(): - # Add non-whitespace tokens and comments that aren't empty. - self._cur_logical_line.AppendToken( - format_token.FormatToken( leaf, pytree_utils.NodeName( leaf ) ) ) + if leaf.type in _WHITESPACE_TOKENS: + self._StartNewLine() + elif leaf.type != grammar_token.COMMENT or leaf.value.strip(): + # Add non-whitespace tokens and comments that aren't empty. + self._cur_logical_line.AppendToken( + format_token.FormatToken(leaf, pytree_utils.NodeName(leaf))) -_BRACKET_MATCH = { ')': '(', '}': '{', ']': '['} +_BRACKET_MATCH = {')': '(', '}': '{', ']': '['} -def _MatchBrackets( line ): - """Visit the node and match the brackets. +def _MatchBrackets(line): + """Visit the node and match the brackets. For every open bracket ('[', '{', or '('), find the associated closing bracket and "match" them up. I.e., save in the token a pointer to its associated open @@ -316,23 +316,23 @@ def _MatchBrackets( line ): Arguments: line: (LogicalLine) A logical line. """ - bracket_stack = [] - for token in line.tokens: - if token.value in _OPENING_BRACKETS: - bracket_stack.append( token ) - elif token.value in _CLOSING_BRACKETS: - bracket_stack[ -1 ].matching_bracket = token - token.matching_bracket = bracket_stack[ -1 ] - bracket_stack.pop() + bracket_stack = [] + for token in line.tokens: + if token.value in _OPENING_BRACKETS: + bracket_stack.append(token) + elif token.value in _CLOSING_BRACKETS: + bracket_stack[-1].matching_bracket = token + token.matching_bracket = bracket_stack[-1] + bracket_stack.pop() - for bracket in bracket_stack: - if id( pytree_utils.GetOpeningBracket( token.node ) ) == id( bracket.node ): - bracket.container_elements.append( token ) - token.container_opening = bracket + for bracket in bracket_stack: + if id(pytree_utils.GetOpeningBracket(token.node)) == id(bracket.node): + bracket.container_elements.append(token) + token.container_opening = bracket -def _IdentifyParameterLists( line ): - """Visit the node to create a state for parameter lists. +def _IdentifyParameterLists(line): + """Visit the node to create a state for parameter lists. For instance, a parameter is considered an "object" with its first and last token uniquely identifying the object. @@ -340,32 +340,32 @@ def _IdentifyParameterLists( line ): Arguments: line: (LogicalLine) A logical line. """ - func_stack = [] - param_stack = [] - for tok in line.tokens: - # Identify parameter list objects. - if subtypes.FUNC_DEF in tok.subtypes: - assert tok.next_token.value == '(' - func_stack.append( tok.next_token ) - continue + func_stack = [] + param_stack = [] + for tok in line.tokens: + # Identify parameter list objects. + if subtypes.FUNC_DEF in tok.subtypes: + assert tok.next_token.value == '(' + func_stack.append(tok.next_token) + continue - if func_stack and tok.value == ')': - if tok == func_stack[ -1 ].matching_bracket: - func_stack.pop() - continue + if func_stack and tok.value == ')': + if tok == func_stack[-1].matching_bracket: + func_stack.pop() + continue - # Identify parameter objects. - if subtypes.PARAMETER_START in tok.subtypes: - param_stack.append( tok ) + # Identify parameter objects. + if subtypes.PARAMETER_START in tok.subtypes: + param_stack.append(tok) - # Not "elif", a parameter could be a single token. - if param_stack and subtypes.PARAMETER_STOP in tok.subtypes: - start = param_stack.pop() - func_stack[ -1 ].parameters.append( object_state.Parameter( start, tok ) ) + # Not "elif", a parameter could be a single token. + if param_stack and subtypes.PARAMETER_STOP in tok.subtypes: + start = param_stack.pop() + func_stack[-1].parameters.append(object_state.Parameter(start, tok)) -def _AdjustSplitPenalty( line ): - """Visit the node and adjust the split penalties if needed. +def _AdjustSplitPenalty(line): + """Visit the node and adjust the split penalties if needed. A token shouldn't be split if it's not within a bracket pair. Mark any token that's not within a bracket pair as "unbreakable". @@ -373,56 +373,57 @@ def _AdjustSplitPenalty( line ): Arguments: line: (LogicalLine) An logical line. """ - bracket_level = 0 - for index, token in enumerate( line.tokens ): - if index and not bracket_level: - pytree_utils.SetNodeAnnotation( - token.node, pytree_utils.Annotation.SPLIT_PENALTY, - split_penalty.UNBREAKABLE ) - if token.value in _OPENING_BRACKETS: - bracket_level += 1 - elif token.value in _CLOSING_BRACKETS: - bracket_level -= 1 - - -def _DetermineMustSplitAnnotation( node ): - """Enforce a split in the list if the list ends with a comma.""" - if style.Get( 'DISABLE_ENDING_COMMA_HEURISTIC' ): + bracket_level = 0 + for index, token in enumerate(line.tokens): + if index and not bracket_level: + pytree_utils.SetNodeAnnotation( + token.node, pytree_utils.Annotation.SPLIT_PENALTY, + split_penalty.UNBREAKABLE) + if token.value in _OPENING_BRACKETS: + bracket_level += 1 + elif token.value in _CLOSING_BRACKETS: + bracket_level -= 1 + + +def _DetermineMustSplitAnnotation(node): + """Enforce a split in the list if the list ends with a comma.""" + if style.Get('DISABLE_ENDING_COMMA_HEURISTIC'): + return + if not _ContainsComments(node): + token = next(node.parent.leaves()) + if token.value == '(': + if sum(1 for ch in node.children if ch.type == grammar_token.COMMA) < 2: return - if not _ContainsComments( node ): - token = next( node.parent.leaves() ) - if token.value == '(': - if sum( 1 for ch in node.children if ch.type == grammar_token.COMMA ) < 2: - return - if ( not isinstance( node.children[ -1 ], pytree.Leaf ) or - node.children[ -1 ].value != ',' ): - return - num_children = len( node.children ) - index = 0 - _SetMustSplitOnFirstLeaf( node.children[ 0 ] ) - while index < num_children - 1: - child = node.children[ index ] - if isinstance( child, pytree.Leaf ) and child.value == ',': - next_child = node.children[ index + 1 ] - if next_child.type == grammar_token.COMMENT: - index += 1 - if index >= num_children - 1: - break - _SetMustSplitOnFirstLeaf( node.children[ index + 1 ] ) + if (not isinstance(node.children[-1], pytree.Leaf) or + node.children[-1].value != ','): + return + num_children = len(node.children) + index = 0 + _SetMustSplitOnFirstLeaf(node.children[0]) + while index < num_children - 1: + child = node.children[index] + if isinstance(child, pytree.Leaf) and child.value == ',': + next_child = node.children[index + 1] + if next_child.type == grammar_token.COMMENT: index += 1 - - -def _ContainsComments( node ): - """Return True if the list has a comment in it.""" - if isinstance( node, pytree.Leaf ): - return node.type == grammar_token.COMMENT - for child in node.children: - if _ContainsComments( child ): - return True - return False - - -def _SetMustSplitOnFirstLeaf( node ): - """Set the "must split" annotation on the first leaf node.""" - pytree_utils.SetNodeAnnotation( - pytree_utils.FirstLeafNode( node ), pytree_utils.Annotation.MUST_SPLIT, True ) + if index >= num_children - 1: + break + _SetMustSplitOnFirstLeaf(node.children[index + 1]) + index += 1 + + +def _ContainsComments(node): + """Return True if the list has a comment in it.""" + if isinstance(node, pytree.Leaf): + return node.type == grammar_token.COMMENT + for child in node.children: + if _ContainsComments(child): + return True + return False + + +def _SetMustSplitOnFirstLeaf(node): + """Set the "must split" annotation on the first leaf node.""" + pytree_utils.SetNodeAnnotation( + pytree_utils.FirstLeafNode(node), pytree_utils.Annotation.MUST_SPLIT, + True) diff --git a/yapf/pytree/pytree_utils.py b/yapf/pytree/pytree_utils.py index 710e0082d..415011806 100644 --- a/yapf/pytree/pytree_utils.py +++ b/yapf/pytree/pytree_utils.py @@ -37,20 +37,20 @@ # have a better understanding of what information we need from the tree. Then, # these tokens may be filtered out from the tree before the tree gets to the # unwrapper. -NONSEMANTIC_TOKENS = frozenset( [ 'DEDENT', 'INDENT', 'NEWLINE', 'ENDMARKER' ] ) +NONSEMANTIC_TOKENS = frozenset(['DEDENT', 'INDENT', 'NEWLINE', 'ENDMARKER']) -class Annotation( object ): - """Annotation names associated with pytrees.""" - CHILD_INDENT = 'child_indent' - NEWLINES = 'newlines' - MUST_SPLIT = 'must_split' - SPLIT_PENALTY = 'split_penalty' - SUBTYPE = 'subtype' +class Annotation(object): + """Annotation names associated with pytrees.""" + CHILD_INDENT = 'child_indent' + NEWLINES = 'newlines' + MUST_SPLIT = 'must_split' + SPLIT_PENALTY = 'split_penalty' + SUBTYPE = 'subtype' -def NodeName( node ): - """Produce a string name for a given node. +def NodeName(node): + """Produce a string name for a given node. For a Leaf this is the token name, and for a Node this is the type. @@ -60,23 +60,23 @@ def NodeName( node ): Returns: Name as a string. """ - # Nodes with values < 256 are tokens. Values >= 256 are grammar symbols. - if node.type < 256: - return token.tok_name[ node.type ] - else: - return pygram.python_grammar.number2symbol[ node.type ] + # Nodes with values < 256 are tokens. Values >= 256 are grammar symbols. + if node.type < 256: + return token.tok_name[node.type] + else: + return pygram.python_grammar.number2symbol[node.type] -def FirstLeafNode( node ): - if isinstance( node, pytree.Leaf ): - return node - return FirstLeafNode( node.children[ 0 ] ) +def FirstLeafNode(node): + if isinstance(node, pytree.Leaf): + return node + return FirstLeafNode(node.children[0]) -def LastLeafNode( node ): - if isinstance( node, pytree.Leaf ): - return node - return LastLeafNode( node.children[ -1 ] ) +def LastLeafNode(node): + if isinstance(node, pytree.Leaf): + return node + return LastLeafNode(node.children[-1]) # lib2to3 thoughtfully provides pygram.python_grammar_no_print_statement for @@ -85,14 +85,14 @@ def LastLeafNode( node ): # It forgets to do the same for 'exec' though. Luckily, Python is amenable to # monkey-patching. _GRAMMAR_FOR_PY3 = pygram.python_grammar_no_print_statement.copy() -del _GRAMMAR_FOR_PY3.keywords[ 'exec' ] +del _GRAMMAR_FOR_PY3.keywords['exec'] _GRAMMAR_FOR_PY2 = pygram.python_grammar.copy() -del _GRAMMAR_FOR_PY2.keywords[ 'nonlocal' ] +del _GRAMMAR_FOR_PY2.keywords['nonlocal'] -def ParseCodeToTree( code ): - """Parse the given code to a lib2to3 pytree. +def ParseCodeToTree(code): + """Parse the given code to a lib2to3 pytree. Arguments: code: a string with the code to parse. @@ -104,35 +104,35 @@ def ParseCodeToTree( code ): Returns: The root node of the parsed tree. """ - # This function is tiny, but the incantation for invoking the parser correctly - # is sufficiently magical to be worth abstracting away. - if not code.endswith( os.linesep ): - code += os.linesep - + # This function is tiny, but the incantation for invoking the parser correctly + # is sufficiently magical to be worth abstracting away. + if not code.endswith(os.linesep): + code += os.linesep + + try: + # Try to parse using a Python 3 grammar, which is more permissive (print and + # exec are not keywords). + parser_driver = driver.Driver(_GRAMMAR_FOR_PY3, convert=pytree.convert) + tree = parser_driver.parse_string(code, debug=False) + except parse.ParseError: + # Now try to parse using a Python 2 grammar; If this fails, then + # there's something else wrong with the code. try: - # Try to parse using a Python 3 grammar, which is more permissive (print and - # exec are not keywords). - parser_driver = driver.Driver( _GRAMMAR_FOR_PY3, convert = pytree.convert ) - tree = parser_driver.parse_string( code, debug = False ) + parser_driver = driver.Driver(_GRAMMAR_FOR_PY2, convert=pytree.convert) + tree = parser_driver.parse_string(code, debug=False) except parse.ParseError: - # Now try to parse using a Python 2 grammar; If this fails, then - # there's something else wrong with the code. - try: - parser_driver = driver.Driver( _GRAMMAR_FOR_PY2, convert = pytree.convert ) - tree = parser_driver.parse_string( code, debug = False ) - except parse.ParseError: - # Raise a syntax error if the code is invalid python syntax. - try: - ast.parse( code ) - except SyntaxError as e: - raise e - else: - raise - return _WrapEndMarker( tree ) - - -def _WrapEndMarker( tree ): - """Wrap a single ENDMARKER token in a "file_input" node. + # Raise a syntax error if the code is invalid python syntax. + try: + ast.parse(code) + except SyntaxError as e: + raise e + else: + raise + return _WrapEndMarker(tree) + + +def _WrapEndMarker(tree): + """Wrap a single ENDMARKER token in a "file_input" node. Arguments: tree: (pytree.Node) The root node of the parsed tree. @@ -142,13 +142,13 @@ def _WrapEndMarker( tree ): then that node is wrapped in a "file_input" node. That will ensure we don't skip comments attached to that node. """ - if isinstance( tree, pytree.Leaf ) and tree.type == token.ENDMARKER: - return pytree.Node( pygram.python_symbols.file_input, [ tree ] ) - return tree + if isinstance(tree, pytree.Leaf) and tree.type == token.ENDMARKER: + return pytree.Node(pygram.python_symbols.file_input, [tree]) + return tree -def InsertNodesBefore( new_nodes, target ): - """Insert new_nodes before the given target location in the tree. +def InsertNodesBefore(new_nodes, target): + """Insert new_nodes before the given target location in the tree. Arguments: new_nodes: a sequence of new nodes to insert (the nodes should not be in the @@ -158,12 +158,12 @@ def InsertNodesBefore( new_nodes, target ): Raises: RuntimeError: if the tree is corrupted, or the insertion would corrupt it. """ - for node in new_nodes: - _InsertNodeAt( node, target, after = False ) + for node in new_nodes: + _InsertNodeAt(node, target, after=False) -def InsertNodesAfter( new_nodes, target ): - """Insert new_nodes after the given target location in the tree. +def InsertNodesAfter(new_nodes, target): + """Insert new_nodes after the given target location in the tree. Arguments: new_nodes: a sequence of new nodes to insert (the nodes should not be in the @@ -173,12 +173,12 @@ def InsertNodesAfter( new_nodes, target ): Raises: RuntimeError: if the tree is corrupted, or the insertion would corrupt it. """ - for node in reversed( new_nodes ): - _InsertNodeAt( node, target, after = True ) + for node in reversed(new_nodes): + _InsertNodeAt(node, target, after=True) -def _InsertNodeAt( new_node, target, after = False ): - """Underlying implementation for node insertion. +def _InsertNodeAt(new_node, target, after=False): + """Underlying implementation for node insertion. Arguments: new_node: a new node to insert (this node should not be in the tree). @@ -193,23 +193,25 @@ def _InsertNodeAt( new_node, target, after = False ): RuntimeError: if the tree is corrupted, or the insertion would corrupt it. """ - # Protect against attempts to insert nodes which already belong to some tree. - if new_node.parent is not None: - raise RuntimeError( - 'inserting node which already has a parent', ( new_node, new_node.parent ) ) + # Protect against attempts to insert nodes which already belong to some tree. + if new_node.parent is not None: + raise RuntimeError( + 'inserting node which already has a parent', + (new_node, new_node.parent)) - # The code here is based on pytree.Base.next_sibling - parent_of_target = target.parent - if parent_of_target is None: - raise RuntimeError( 'expected target node to have a parent', ( target,) ) + # The code here is based on pytree.Base.next_sibling + parent_of_target = target.parent + if parent_of_target is None: + raise RuntimeError('expected target node to have a parent', (target,)) - for i, child in enumerate( parent_of_target.children ): - if child is target: - insertion_index = i + 1 if after else i - parent_of_target.insert_child( insertion_index, new_node ) - return + for i, child in enumerate(parent_of_target.children): + if child is target: + insertion_index = i + 1 if after else i + parent_of_target.insert_child(insertion_index, new_node) + return - raise RuntimeError( 'unable to find insertion point for target node', ( target,) ) + raise RuntimeError( + 'unable to find insertion point for target node', (target,)) # The following constant and functions implement a simple custom annotation @@ -219,20 +221,20 @@ def _InsertNodeAt( new_node, target, after = False ): _NODE_ANNOTATION_PREFIX = '_yapf_annotation_' -def CopyYapfAnnotations( src, dst ): - """Copy all YAPF annotations from the source node to the destination node. +def CopyYapfAnnotations(src, dst): + """Copy all YAPF annotations from the source node to the destination node. Arguments: src: the source node. dst: the destination node. """ - for annotation in dir( src ): - if annotation.startswith( _NODE_ANNOTATION_PREFIX ): - setattr( dst, annotation, getattr( src, annotation, None ) ) + for annotation in dir(src): + if annotation.startswith(_NODE_ANNOTATION_PREFIX): + setattr(dst, annotation, getattr(src, annotation, None)) -def GetNodeAnnotation( node, annotation, default = None ): - """Get annotation value from a node. +def GetNodeAnnotation(node, annotation, default=None): + """Get annotation value from a node. Arguments: node: the node. @@ -243,48 +245,48 @@ def GetNodeAnnotation( node, annotation, default = None ): Value of the annotation in the given node. If the node doesn't have this particular annotation name yet, returns default. """ - return getattr( node, _NODE_ANNOTATION_PREFIX + annotation, default ) + return getattr(node, _NODE_ANNOTATION_PREFIX + annotation, default) -def SetNodeAnnotation( node, annotation, value ): - """Set annotation value on a node. +def SetNodeAnnotation(node, annotation, value): + """Set annotation value on a node. Arguments: node: the node. annotation: annotation name - a string. value: annotation value to set. """ - setattr( node, _NODE_ANNOTATION_PREFIX + annotation, value ) + setattr(node, _NODE_ANNOTATION_PREFIX + annotation, value) -def AppendNodeAnnotation( node, annotation, value ): - """Appends an annotation value to a list of annotations on the node. +def AppendNodeAnnotation(node, annotation, value): + """Appends an annotation value to a list of annotations on the node. Arguments: node: the node. annotation: annotation name - a string. value: annotation value to set. """ - attr = GetNodeAnnotation( node, annotation, set() ) - attr.add( value ) - SetNodeAnnotation( node, annotation, attr ) + attr = GetNodeAnnotation(node, annotation, set()) + attr.add(value) + SetNodeAnnotation(node, annotation, attr) -def RemoveSubtypeAnnotation( node, value ): - """Removes an annotation value from the subtype annotations on the node. +def RemoveSubtypeAnnotation(node, value): + """Removes an annotation value from the subtype annotations on the node. Arguments: node: the node. value: annotation value to remove. """ - attr = GetNodeAnnotation( node, Annotation.SUBTYPE ) - if attr and value in attr: - attr.remove( value ) - SetNodeAnnotation( node, Annotation.SUBTYPE, attr ) + attr = GetNodeAnnotation(node, Annotation.SUBTYPE) + if attr and value in attr: + attr.remove(value) + SetNodeAnnotation(node, Annotation.SUBTYPE, attr) -def GetOpeningBracket( node ): - """Get opening bracket value from a node. +def GetOpeningBracket(node): + """Get opening bracket value from a node. Arguments: node: the node. @@ -292,21 +294,21 @@ def GetOpeningBracket( node ): Returns: The opening bracket node or None if it couldn't find one. """ - return getattr( node, _NODE_ANNOTATION_PREFIX + 'container_bracket', None ) + return getattr(node, _NODE_ANNOTATION_PREFIX + 'container_bracket', None) -def SetOpeningBracket( node, bracket ): - """Set opening bracket value for a node. +def SetOpeningBracket(node, bracket): + """Set opening bracket value for a node. Arguments: node: the node. bracket: opening bracket to set. """ - setattr( node, _NODE_ANNOTATION_PREFIX + 'container_bracket', bracket ) + setattr(node, _NODE_ANNOTATION_PREFIX + 'container_bracket', bracket) -def DumpNodeToString( node ): - """Dump a string representation of the given node. For debugging. +def DumpNodeToString(node): + """Dump a string representation of the given node. For debugging. Arguments: node: the node. @@ -314,35 +316,36 @@ def DumpNodeToString( node ): Returns: The string representation. """ - if isinstance( node, pytree.Leaf ): - fmt = ( - '{name}({value}) [lineno={lineno}, column={column}, ' - 'prefix={prefix}, penalty={penalty}]' ) - return fmt.format( - name = NodeName( node ), - value = _PytreeNodeRepr( node ), - lineno = node.lineno, - column = node.column, - prefix = repr( node.prefix ), - penalty = GetNodeAnnotation( node, Annotation.SPLIT_PENALTY, None ) ) - else: - fmt = '{node} [{len} children] [child_indent="{indent}"]' - return fmt.format( - node = NodeName( node ), - len = len( node.children ), - indent = GetNodeAnnotation( node, Annotation.CHILD_INDENT ) ) - - -def _PytreeNodeRepr( node ): - """Like pytree.Node.__repr__, but names instead of numbers for tokens.""" - if isinstance( node, pytree.Node ): - return '%s(%s, %r)' % ( - node.__class__.__name__, NodeName( node ), - [ _PytreeNodeRepr( c ) for c in node.children ] ) - if isinstance( node, pytree.Leaf ): - return '%s(%s, %r)' % ( node.__class__.__name__, NodeName( node ), node.value ) - - -def IsCommentStatement( node ): - return ( - NodeName( node ) == 'simple_stmt' and node.children[ 0 ].type == token.COMMENT ) + if isinstance(node, pytree.Leaf): + fmt = ( + '{name}({value}) [lineno={lineno}, column={column}, ' + 'prefix={prefix}, penalty={penalty}]') + return fmt.format( + name=NodeName(node), + value=_PytreeNodeRepr(node), + lineno=node.lineno, + column=node.column, + prefix=repr(node.prefix), + penalty=GetNodeAnnotation(node, Annotation.SPLIT_PENALTY, None)) + else: + fmt = '{node} [{len} children] [child_indent="{indent}"]' + return fmt.format( + node=NodeName(node), + len=len(node.children), + indent=GetNodeAnnotation(node, Annotation.CHILD_INDENT)) + + +def _PytreeNodeRepr(node): + """Like pytree.Node.__repr__, but names instead of numbers for tokens.""" + if isinstance(node, pytree.Node): + return '%s(%s, %r)' % ( + node.__class__.__name__, NodeName(node), + [_PytreeNodeRepr(c) for c in node.children]) + if isinstance(node, pytree.Leaf): + return '%s(%s, %r)' % (node.__class__.__name__, NodeName(node), node.value) + + +def IsCommentStatement(node): + return ( + NodeName(node) == 'simple_stmt' and + node.children[0].type == token.COMMENT) diff --git a/yapf/pytree/pytree_visitor.py b/yapf/pytree/pytree_visitor.py index 5b816f3e4..1cc2819f6 100644 --- a/yapf/pytree/pytree_visitor.py +++ b/yapf/pytree/pytree_visitor.py @@ -31,8 +31,8 @@ from yapf.pytree import pytree_utils -class PyTreeVisitor( object ): - """Visitor pattern for pytree trees. +class PyTreeVisitor(object): + """Visitor pattern for pytree trees. Methods named Visit_XXX will be invoked when a node with type XXX is encountered in the tree. The type is either a token type (for Leaf nodes) or @@ -54,42 +54,42 @@ class PyTreeVisitor( object ): that may have children - otherwise the children will not be visited. """ - def Visit( self, node ): - """Visit a node.""" - method = 'Visit_{0}'.format( pytree_utils.NodeName( node ) ) - if hasattr( self, method ): - # Found a specific visitor for this node - getattr( self, method )( node ) - else: - if isinstance( node, pytree.Leaf ): - self.DefaultLeafVisit( node ) - else: - self.DefaultNodeVisit( node ) - - def DefaultNodeVisit( self, node ): - """Default visitor for Node: visits the node's children depth-first. + def Visit(self, node): + """Visit a node.""" + method = 'Visit_{0}'.format(pytree_utils.NodeName(node)) + if hasattr(self, method): + # Found a specific visitor for this node + getattr(self, method)(node) + else: + if isinstance(node, pytree.Leaf): + self.DefaultLeafVisit(node) + else: + self.DefaultNodeVisit(node) + + def DefaultNodeVisit(self, node): + """Default visitor for Node: visits the node's children depth-first. This method is invoked when no specific visitor for the node is defined. Arguments: node: the node to visit """ - for child in node.children: - self.Visit( child ) + for child in node.children: + self.Visit(child) - def DefaultLeafVisit( self, leaf ): - """Default visitor for Leaf: no-op. + def DefaultLeafVisit(self, leaf): + """Default visitor for Leaf: no-op. This method is invoked when no specific visitor for the leaf is defined. Arguments: leaf: the leaf to visit """ - pass + pass -def DumpPyTree( tree, target_stream = sys.stdout ): - """Convenience function for dumping a given pytree. +def DumpPyTree(tree, target_stream=sys.stdout): + """Convenience function for dumping a given pytree. This function presents a very minimal interface. For more configurability (for example, controlling how specific node types are displayed), use PyTreeDumper @@ -100,36 +100,36 @@ def DumpPyTree( tree, target_stream = sys.stdout ): target_stream: the stream to dump the tree to. A file-like object. By default will dump into stdout. """ - dumper = PyTreeDumper( target_stream ) - dumper.Visit( tree ) + dumper = PyTreeDumper(target_stream) + dumper.Visit(tree) -class PyTreeDumper( PyTreeVisitor ): - """Visitor that dumps the tree to a stream. +class PyTreeDumper(PyTreeVisitor): + """Visitor that dumps the tree to a stream. Implements the PyTreeVisitor interface. """ - def __init__( self, target_stream = sys.stdout ): - """Create a tree dumper. + def __init__(self, target_stream=sys.stdout): + """Create a tree dumper. Arguments: target_stream: the stream to dump the tree to. A file-like object. By default will dump into stdout. """ - self._target_stream = target_stream - self._current_indent = 0 - - def _DumpString( self, s ): - self._target_stream.write( '{0}{1}\n'.format( ' ' * self._current_indent, s ) ) - - def DefaultNodeVisit( self, node ): - # Dump information about the current node, and then use the generic - # DefaultNodeVisit visitor to dump each of its children. - self._DumpString( pytree_utils.DumpNodeToString( node ) ) - self._current_indent += 2 - super( PyTreeDumper, self ).DefaultNodeVisit( node ) - self._current_indent -= 2 - - def DefaultLeafVisit( self, leaf ): - self._DumpString( pytree_utils.DumpNodeToString( leaf ) ) + self._target_stream = target_stream + self._current_indent = 0 + + def _DumpString(self, s): + self._target_stream.write('{0}{1}\n'.format(' ' * self._current_indent, s)) + + def DefaultNodeVisit(self, node): + # Dump information about the current node, and then use the generic + # DefaultNodeVisit visitor to dump each of its children. + self._DumpString(pytree_utils.DumpNodeToString(node)) + self._current_indent += 2 + super(PyTreeDumper, self).DefaultNodeVisit(node) + self._current_indent -= 2 + + def DefaultLeafVisit(self, leaf): + self._DumpString(pytree_utils.DumpNodeToString(leaf)) diff --git a/yapf/pytree/split_penalty.py b/yapf/pytree/split_penalty.py index 8b5598390..8dc8056d3 100644 --- a/yapf/pytree/split_penalty.py +++ b/yapf/pytree/split_penalty.py @@ -52,548 +52,540 @@ SUBSCRIPT = 6000 -def ComputeSplitPenalties( tree ): - """Compute split penalties on tokens in the given parse tree. +def ComputeSplitPenalties(tree): + """Compute split penalties on tokens in the given parse tree. Arguments: tree: the top-level pytree node to annotate with penalties. """ - _SplitPenaltyAssigner().Visit( tree ) + _SplitPenaltyAssigner().Visit(tree) -class _SplitPenaltyAssigner( pytree_visitor.PyTreeVisitor ): - """Assigns split penalties to tokens, based on parse tree structure. +class _SplitPenaltyAssigner(pytree_visitor.PyTreeVisitor): + """Assigns split penalties to tokens, based on parse tree structure. Split penalties are attached as annotations to tokens. """ - def Visit( self, node ): - if not hasattr( node, 'is_pseudo' ): # Ignore pseudo tokens. - super( _SplitPenaltyAssigner, self ).Visit( node ) - - def Visit_import_as_names( self, node ): # pyline: disable=invalid-name - # import_as_names ::= import_as_name (',' import_as_name)* [','] - self.DefaultNodeVisit( node ) - prev_child = None - for child in node.children: - if ( prev_child and isinstance( prev_child, pytree.Leaf ) and - prev_child.value == ',' ): - _SetSplitPenalty( child, style.Get( 'SPLIT_PENALTY_IMPORT_NAMES' ) ) - prev_child = child - - def Visit_classdef( self, node ): # pylint: disable=invalid-name - # classdef ::= 'class' NAME ['(' [arglist] ')'] ':' suite - # - # NAME - _SetUnbreakable( node.children[ 1 ] ) - if len( node.children ) > 4: - # opening '(' - _SetUnbreakable( node.children[ 2 ] ) - # ':' - _SetUnbreakable( node.children[ -2 ] ) - self.DefaultNodeVisit( node ) - - def Visit_funcdef( self, node ): # pylint: disable=invalid-name - # funcdef ::= 'def' NAME parameters ['->' test] ':' suite - # - # Can't break before the function name and before the colon. The parameters - # are handled by child iteration. - colon_idx = 1 - while pytree_utils.NodeName( node.children[ colon_idx ] ) == 'simple_stmt': - colon_idx += 1 - _SetUnbreakable( node.children[ colon_idx ] ) - arrow_idx = -1 - while colon_idx < len( node.children ): - if isinstance( node.children[ colon_idx ], pytree.Leaf ): - if node.children[ colon_idx ].value == ':': - break - if node.children[ colon_idx ].value == '->': - arrow_idx = colon_idx - colon_idx += 1 - _SetUnbreakable( node.children[ colon_idx ] ) - self.DefaultNodeVisit( node ) - if arrow_idx > 0: - _SetSplitPenalty( - pytree_utils.LastLeafNode( node.children[ arrow_idx - 1 ] ), 0 ) - _SetUnbreakable( node.children[ arrow_idx ] ) - _SetStronglyConnected( node.children[ arrow_idx + 1 ] ) - - def Visit_lambdef( self, node ): # pylint: disable=invalid-name - # lambdef ::= 'lambda' [varargslist] ':' test - # Loop over the lambda up to and including the colon. - allow_multiline_lambdas = style.Get( 'ALLOW_MULTILINE_LAMBDAS' ) - if not allow_multiline_lambdas: - for child in node.children: - if child.type == grammar_token.COMMENT: - if re.search( r'pylint:.*disable=.*\bg-long-lambda', child.value ): - allow_multiline_lambdas = True - break - - if allow_multiline_lambdas: - _SetExpressionPenalty( node, STRONGLY_CONNECTED ) - else: - _SetExpressionPenalty( node, VERY_STRONGLY_CONNECTED ) - - def Visit_parameters( self, node ): # pylint: disable=invalid-name - # parameters ::= '(' [typedargslist] ')' - self.DefaultNodeVisit( node ) - - # Can't break before the opening paren of a parameter list. - _SetUnbreakable( node.children[ 0 ] ) - if not ( style.Get( 'INDENT_CLOSING_BRACKETS' ) or - style.Get( 'DEDENT_CLOSING_BRACKETS' ) ): - _SetStronglyConnected( node.children[ -1 ] ) - - def Visit_arglist( self, node ): # pylint: disable=invalid-name - # arglist ::= argument (',' argument)* [','] - if node.children[ 0 ].type == grammar_token.STAR: - # Python 3 treats a star expression as a specific expression type. - # Process it in that method. - self.Visit_star_expr( node ) - return - - self.DefaultNodeVisit( node ) - - for index in py3compat.range( 1, len( node.children ) ): - child = node.children[ index ] - if isinstance( child, pytree.Leaf ) and child.value == ',': - _SetUnbreakable( child ) - - for child in node.children: - if pytree_utils.NodeName( child ) == 'atom': - _IncreasePenalty( child, CONNECTED ) - - def Visit_argument( self, node ): # pylint: disable=invalid-name - # argument ::= test [comp_for] | test '=' test # Really [keyword '='] test - self.DefaultNodeVisit( node ) - - for index in py3compat.range( 1, len( node.children ) - 1 ): - child = node.children[ index ] - if isinstance( child, pytree.Leaf ) and child.value == '=': - _SetSplitPenalty( - pytree_utils.FirstLeafNode( node.children[ index ] ), NAMED_ASSIGN ) - _SetSplitPenalty( - pytree_utils.FirstLeafNode( node.children[ index + 1 ] ), - NAMED_ASSIGN ) - - def Visit_tname( self, node ): # pylint: disable=invalid-name - # tname ::= NAME [':' test] - self.DefaultNodeVisit( node ) - - for index in py3compat.range( 1, len( node.children ) - 1 ): - child = node.children[ index ] - if isinstance( child, pytree.Leaf ) and child.value == ':': - _SetSplitPenalty( - pytree_utils.FirstLeafNode( node.children[ index ] ), NAMED_ASSIGN ) - _SetSplitPenalty( - pytree_utils.FirstLeafNode( node.children[ index + 1 ] ), - NAMED_ASSIGN ) - - def Visit_dotted_name( self, node ): # pylint: disable=invalid-name - # dotted_name ::= NAME ('.' NAME)* - for child in node.children: - self.Visit( child ) - start = 2 if hasattr( node.children[ 0 ], 'is_pseudo' ) else 1 - for i in py3compat.range( start, len( node.children ) ): - _SetUnbreakable( node.children[ i ] ) - - def Visit_dictsetmaker( self, node ): # pylint: disable=invalid-name - # dictsetmaker ::= ( (test ':' test - # (comp_for | (',' test ':' test)* [','])) | - # (test (comp_for | (',' test)* [','])) ) - for child in node.children: - self.Visit( child ) - if child.type == grammar_token.COLON: - # This is a key to a dictionary. We don't want to split the key if at - # all possible. - _SetStronglyConnected( child ) - - def Visit_trailer( self, node ): # pylint: disable=invalid-name - # trailer ::= '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME - if node.children[ 0 ].value == '.': - before = style.Get( 'SPLIT_BEFORE_DOT' ) - _SetSplitPenalty( - node.children[ 0 ], VERY_STRONGLY_CONNECTED if before else DOTTED_NAME ) - _SetSplitPenalty( - node.children[ 1 ], DOTTED_NAME if before else VERY_STRONGLY_CONNECTED ) - elif len( node.children ) == 2: - # Don't split an empty argument list if at all possible. - _SetSplitPenalty( node.children[ 1 ], VERY_STRONGLY_CONNECTED ) - elif len( node.children ) == 3: - name = pytree_utils.NodeName( node.children[ 1 ] ) - if name in { 'argument', 'comparison' }: - # Don't split an argument list with one element if at all possible. - _SetStronglyConnected( node.children[ 1 ] ) - if ( len( node.children[ 1 ].children ) > 1 and pytree_utils.NodeName( - node.children[ 1 ].children[ 1 ] ) == 'comp_for' ): - # Don't penalize splitting before a comp_for expression. - _SetSplitPenalty( - pytree_utils.FirstLeafNode( node.children[ 1 ] ), 0 ) - else: - _SetSplitPenalty( - pytree_utils.FirstLeafNode( node.children[ 1 ] ), - ONE_ELEMENT_ARGUMENT ) - elif ( node.children[ 0 ].type == grammar_token.LSQB and - len( node.children[ 1 ].children ) > 2 and - ( name.endswith( '_test' ) or name.endswith( '_expr' ) ) ): - _SetStronglyConnected( node.children[ 1 ].children[ 0 ] ) - _SetStronglyConnected( node.children[ 1 ].children[ 2 ] ) - - # Still allow splitting around the operator. - split_before = ( - ( - name.endswith( '_test' ) and - style.Get( 'SPLIT_BEFORE_LOGICAL_OPERATOR' ) ) or ( - name.endswith( '_expr' ) and - style.Get( 'SPLIT_BEFORE_BITWISE_OPERATOR' ) ) ) - if split_before: - _SetSplitPenalty( - pytree_utils.LastLeafNode( node.children[ 1 ].children[ 1 ] ), - 0 ) - else: - _SetSplitPenalty( - pytree_utils.FirstLeafNode( node.children[ 1 ].children[ 2 ] ), - 0 ) - - # Don't split the ending bracket of a subscript list. - _RecAnnotate( - node.children[ -1 ], pytree_utils.Annotation.SPLIT_PENALTY, - VERY_STRONGLY_CONNECTED ) - elif name not in { 'arglist', 'argument', 'term', 'or_test', 'and_test', - 'comparison', 'atom', 'power' }: - # Don't split an argument list with one element if at all possible. - stypes = pytree_utils.GetNodeAnnotation( - pytree_utils.FirstLeafNode( node ), - pytree_utils.Annotation.SUBTYPE ) - if stypes and subtypes.SUBSCRIPT_BRACKET in stypes: - _IncreasePenalty( node, SUBSCRIPT ) - - # Bump up the split penalty for the first part of a subscript. We - # would rather not split there. - _IncreasePenalty( node.children[ 1 ], CONNECTED ) - else: - _SetStronglyConnected( node.children[ 1 ], node.children[ 2 ] ) - - if name == 'arglist': - _SetStronglyConnected( node.children[ -1 ] ) - - self.DefaultNodeVisit( node ) - - def Visit_power( self, node ): # pylint: disable=invalid-name,missing-docstring - # power ::= atom trailer* ['**' factor] - self.DefaultNodeVisit( node ) - - # When atom is followed by a trailer, we can not break between them. - # E.g. arr[idx] - no break allowed between 'arr' and '['. - if ( len( node.children ) > 1 and - pytree_utils.NodeName( node.children[ 1 ] ) == 'trailer' ): - # children[1] itself is a whole trailer: we don't want to - # mark all of it as unbreakable, only its first token: (, [ or . - first = pytree_utils.FirstLeafNode( node.children[ 1 ] ) - if first.value != '.': - _SetUnbreakable( node.children[ 1 ].children[ 0 ] ) - - # A special case when there are more trailers in the sequence. Given: - # atom tr1 tr2 - # The last token of tr1 and the first token of tr2 comprise an unbreakable - # region. For example: foo.bar.baz(1) - # We can't put breaks between either of the '.', '(', or '[' and the names - # *preceding* them. - prev_trailer_idx = 1 - while prev_trailer_idx < len( node.children ) - 1: - cur_trailer_idx = prev_trailer_idx + 1 - cur_trailer = node.children[ cur_trailer_idx ] - if pytree_utils.NodeName( cur_trailer ) != 'trailer': - break - - # Now we know we have two trailers one after the other - prev_trailer = node.children[ prev_trailer_idx ] - if prev_trailer.children[ -1 ].value != ')': - # Set the previous node unbreakable if it's not a function call: - # atom tr1() tr2 - # It may be necessary (though undesirable) to split up a previous - # function call's parentheses to the next line. - _SetStronglyConnected( prev_trailer.children[ -1 ] ) - _SetStronglyConnected( cur_trailer.children[ 0 ] ) - prev_trailer_idx = cur_trailer_idx - - # We don't want to split before the last ')' of a function call. This also - # takes care of the special case of: - # atom tr1 tr2 ... trn - # where the 'tr#' are trailers that may end in a ')'. - for trailer in node.children[ 1 : ]: - if pytree_utils.NodeName( trailer ) != 'trailer': - break - if trailer.children[ 0 ].value in '([': - if len( trailer.children ) > 2: - stypes = pytree_utils.GetNodeAnnotation( - trailer.children[ 0 ], pytree_utils.Annotation.SUBTYPE ) - if stypes and subtypes.SUBSCRIPT_BRACKET in stypes: - _SetStronglyConnected( - pytree_utils.FirstLeafNode( trailer.children[ 1 ] ) ) - - last_child_node = pytree_utils.LastLeafNode( trailer ) - if last_child_node.value.strip().startswith( '#' ): - last_child_node = last_child_node.prev_sibling - if not ( style.Get( 'INDENT_CLOSING_BRACKETS' ) or - style.Get( 'DEDENT_CLOSING_BRACKETS' ) ): - last = pytree_utils.LastLeafNode( last_child_node.prev_sibling ) - if last.value != ',': - if last_child_node.value == ']': - _SetUnbreakable( last_child_node ) - else: - _SetSplitPenalty( - last_child_node, VERY_STRONGLY_CONNECTED ) - else: - # If the trailer's children are '()', then make it a strongly - # connected region. It's sometimes necessary, though undesirable, to - # split the two. - _SetStronglyConnected( trailer.children[ -1 ] ) - - def Visit_subscriptlist( self, node ): # pylint: disable=invalid-name - # subscriptlist ::= subscript (',' subscript)* [','] - self.DefaultNodeVisit( node ) - _SetSplitPenalty( pytree_utils.FirstLeafNode( node ), 0 ) - prev_child = None - for child in node.children: - if prev_child and prev_child.type == grammar_token.COMMA: - _SetSplitPenalty( pytree_utils.FirstLeafNode( child ), 0 ) - prev_child = child - - def Visit_subscript( self, node ): # pylint: disable=invalid-name - # subscript ::= test | [test] ':' [test] [sliceop] - _SetStronglyConnected( *node.children ) - self.DefaultNodeVisit( node ) - - def Visit_comp_for( self, node ): # pylint: disable=invalid-name - # comp_for ::= 'for' exprlist 'in' testlist_safe [comp_iter] - _SetSplitPenalty( pytree_utils.FirstLeafNode( node ), 0 ) - _SetStronglyConnected( *node.children[ 1 : ] ) - self.DefaultNodeVisit( node ) - - def Visit_old_comp_for( self, node ): # pylint: disable=invalid-name - # Python 3.7 - self.Visit_comp_for( node ) - - def Visit_comp_if( self, node ): # pylint: disable=invalid-name - # comp_if ::= 'if' old_test [comp_iter] + def Visit(self, node): + if not hasattr(node, 'is_pseudo'): # Ignore pseudo tokens. + super(_SplitPenaltyAssigner, self).Visit(node) + + def Visit_import_as_names(self, node): # pyline: disable=invalid-name + # import_as_names ::= import_as_name (',' import_as_name)* [','] + self.DefaultNodeVisit(node) + prev_child = None + for child in node.children: + if (prev_child and isinstance(prev_child, pytree.Leaf) and + prev_child.value == ','): + _SetSplitPenalty(child, style.Get('SPLIT_PENALTY_IMPORT_NAMES')) + prev_child = child + + def Visit_classdef(self, node): # pylint: disable=invalid-name + # classdef ::= 'class' NAME ['(' [arglist] ')'] ':' suite + # + # NAME + _SetUnbreakable(node.children[1]) + if len(node.children) > 4: + # opening '(' + _SetUnbreakable(node.children[2]) + # ':' + _SetUnbreakable(node.children[-2]) + self.DefaultNodeVisit(node) + + def Visit_funcdef(self, node): # pylint: disable=invalid-name + # funcdef ::= 'def' NAME parameters ['->' test] ':' suite + # + # Can't break before the function name and before the colon. The parameters + # are handled by child iteration. + colon_idx = 1 + while pytree_utils.NodeName(node.children[colon_idx]) == 'simple_stmt': + colon_idx += 1 + _SetUnbreakable(node.children[colon_idx]) + arrow_idx = -1 + while colon_idx < len(node.children): + if isinstance(node.children[colon_idx], pytree.Leaf): + if node.children[colon_idx].value == ':': + break + if node.children[colon_idx].value == '->': + arrow_idx = colon_idx + colon_idx += 1 + _SetUnbreakable(node.children[colon_idx]) + self.DefaultNodeVisit(node) + if arrow_idx > 0: + _SetSplitPenalty( + pytree_utils.LastLeafNode(node.children[arrow_idx - 1]), 0) + _SetUnbreakable(node.children[arrow_idx]) + _SetStronglyConnected(node.children[arrow_idx + 1]) + + def Visit_lambdef(self, node): # pylint: disable=invalid-name + # lambdef ::= 'lambda' [varargslist] ':' test + # Loop over the lambda up to and including the colon. + allow_multiline_lambdas = style.Get('ALLOW_MULTILINE_LAMBDAS') + if not allow_multiline_lambdas: + for child in node.children: + if child.type == grammar_token.COMMENT: + if re.search(r'pylint:.*disable=.*\bg-long-lambda', child.value): + allow_multiline_lambdas = True + break + + if allow_multiline_lambdas: + _SetExpressionPenalty(node, STRONGLY_CONNECTED) + else: + _SetExpressionPenalty(node, VERY_STRONGLY_CONNECTED) + + def Visit_parameters(self, node): # pylint: disable=invalid-name + # parameters ::= '(' [typedargslist] ')' + self.DefaultNodeVisit(node) + + # Can't break before the opening paren of a parameter list. + _SetUnbreakable(node.children[0]) + if not (style.Get('INDENT_CLOSING_BRACKETS') or + style.Get('DEDENT_CLOSING_BRACKETS')): + _SetStronglyConnected(node.children[-1]) + + def Visit_arglist(self, node): # pylint: disable=invalid-name + # arglist ::= argument (',' argument)* [','] + if node.children[0].type == grammar_token.STAR: + # Python 3 treats a star expression as a specific expression type. + # Process it in that method. + self.Visit_star_expr(node) + return + + self.DefaultNodeVisit(node) + + for index in py3compat.range(1, len(node.children)): + child = node.children[index] + if isinstance(child, pytree.Leaf) and child.value == ',': + _SetUnbreakable(child) + + for child in node.children: + if pytree_utils.NodeName(child) == 'atom': + _IncreasePenalty(child, CONNECTED) + + def Visit_argument(self, node): # pylint: disable=invalid-name + # argument ::= test [comp_for] | test '=' test # Really [keyword '='] test + self.DefaultNodeVisit(node) + + for index in py3compat.range(1, len(node.children) - 1): + child = node.children[index] + if isinstance(child, pytree.Leaf) and child.value == '=': + _SetSplitPenalty( + pytree_utils.FirstLeafNode(node.children[index]), NAMED_ASSIGN) + _SetSplitPenalty( + pytree_utils.FirstLeafNode(node.children[index + 1]), NAMED_ASSIGN) + + def Visit_tname(self, node): # pylint: disable=invalid-name + # tname ::= NAME [':' test] + self.DefaultNodeVisit(node) + + for index in py3compat.range(1, len(node.children) - 1): + child = node.children[index] + if isinstance(child, pytree.Leaf) and child.value == ':': + _SetSplitPenalty( + pytree_utils.FirstLeafNode(node.children[index]), NAMED_ASSIGN) _SetSplitPenalty( - node.children[ 0 ], style.Get( 'SPLIT_PENALTY_BEFORE_IF_EXPR' ) ) - _SetStronglyConnected( *node.children[ 1 : ] ) - self.DefaultNodeVisit( node ) - - def Visit_old_comp_if( self, node ): # pylint: disable=invalid-name - # Python 3.7 - self.Visit_comp_if( node ) - - def Visit_test( self, node ): # pylint: disable=invalid-name - # test ::= or_test ['if' or_test 'else' test] | lambdef - _IncreasePenalty( node, OR_TEST ) - self.DefaultNodeVisit( node ) - - def Visit_or_test( self, node ): # pylint: disable=invalid-name - # or_test ::= and_test ('or' and_test)* - self.DefaultNodeVisit( node ) - _IncreasePenalty( node, OR_TEST ) - index = 1 - while index + 1 < len( node.children ): - if style.Get( 'SPLIT_BEFORE_LOGICAL_OPERATOR' ): - _DecrementSplitPenalty( - pytree_utils.FirstLeafNode( node.children[ index ] ), OR_TEST ) - else: - _DecrementSplitPenalty( - pytree_utils.FirstLeafNode( node.children[ index + 1 ] ), OR_TEST ) - index += 2 - - def Visit_and_test( self, node ): # pylint: disable=invalid-name - # and_test ::= not_test ('and' not_test)* - self.DefaultNodeVisit( node ) - _IncreasePenalty( node, AND_TEST ) - index = 1 - while index + 1 < len( node.children ): - if style.Get( 'SPLIT_BEFORE_LOGICAL_OPERATOR' ): - _DecrementSplitPenalty( - pytree_utils.FirstLeafNode( node.children[ index ] ), AND_TEST ) - else: - _DecrementSplitPenalty( - pytree_utils.FirstLeafNode( node.children[ index + 1 ] ), AND_TEST ) - index += 2 - - def Visit_not_test( self, node ): # pylint: disable=invalid-name - # not_test ::= 'not' not_test | comparison - self.DefaultNodeVisit( node ) - _IncreasePenalty( node, NOT_TEST ) - - def Visit_comparison( self, node ): # pylint: disable=invalid-name - # comparison ::= expr (comp_op expr)* - self.DefaultNodeVisit( node ) - if len( node.children ) == 3 and _StronglyConnectedCompOp( node ): - _IncreasePenalty( node.children[ 1 ], VERY_STRONGLY_CONNECTED ) - _SetSplitPenalty( - pytree_utils.FirstLeafNode( node.children[ 2 ] ), STRONGLY_CONNECTED ) + pytree_utils.FirstLeafNode(node.children[index + 1]), NAMED_ASSIGN) + + def Visit_dotted_name(self, node): # pylint: disable=invalid-name + # dotted_name ::= NAME ('.' NAME)* + for child in node.children: + self.Visit(child) + start = 2 if hasattr(node.children[0], 'is_pseudo') else 1 + for i in py3compat.range(start, len(node.children)): + _SetUnbreakable(node.children[i]) + + def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name + # dictsetmaker ::= ( (test ':' test + # (comp_for | (',' test ':' test)* [','])) | + # (test (comp_for | (',' test)* [','])) ) + for child in node.children: + self.Visit(child) + if child.type == grammar_token.COLON: + # This is a key to a dictionary. We don't want to split the key if at + # all possible. + _SetStronglyConnected(child) + + def Visit_trailer(self, node): # pylint: disable=invalid-name + # trailer ::= '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME + if node.children[0].value == '.': + before = style.Get('SPLIT_BEFORE_DOT') + _SetSplitPenalty( + node.children[0], VERY_STRONGLY_CONNECTED if before else DOTTED_NAME) + _SetSplitPenalty( + node.children[1], DOTTED_NAME if before else VERY_STRONGLY_CONNECTED) + elif len(node.children) == 2: + # Don't split an empty argument list if at all possible. + _SetSplitPenalty(node.children[1], VERY_STRONGLY_CONNECTED) + elif len(node.children) == 3: + name = pytree_utils.NodeName(node.children[1]) + if name in {'argument', 'comparison'}: + # Don't split an argument list with one element if at all possible. + _SetStronglyConnected(node.children[1]) + if (len(node.children[1].children) > 1 and + pytree_utils.NodeName(node.children[1].children[1]) == 'comp_for'): + # Don't penalize splitting before a comp_for expression. + _SetSplitPenalty(pytree_utils.FirstLeafNode(node.children[1]), 0) else: - _IncreasePenalty( node, COMPARISON ) - - def Visit_star_expr( self, node ): # pylint: disable=invalid-name - # star_expr ::= '*' expr - self.DefaultNodeVisit( node ) - _IncreasePenalty( node, STAR_EXPR ) - - def Visit_expr( self, node ): # pylint: disable=invalid-name - # expr ::= xor_expr ('|' xor_expr)* - self.DefaultNodeVisit( node ) - _IncreasePenalty( node, EXPR ) - _SetBitwiseOperandPenalty( node, '|' ) - - def Visit_xor_expr( self, node ): # pylint: disable=invalid-name - # xor_expr ::= and_expr ('^' and_expr)* - self.DefaultNodeVisit( node ) - _IncreasePenalty( node, XOR_EXPR ) - _SetBitwiseOperandPenalty( node, '^' ) - - def Visit_and_expr( self, node ): # pylint: disable=invalid-name - # and_expr ::= shift_expr ('&' shift_expr)* - self.DefaultNodeVisit( node ) - _IncreasePenalty( node, AND_EXPR ) - _SetBitwiseOperandPenalty( node, '&' ) - - def Visit_shift_expr( self, node ): # pylint: disable=invalid-name - # shift_expr ::= arith_expr (('<<'|'>>') arith_expr)* - self.DefaultNodeVisit( node ) - _IncreasePenalty( node, SHIFT_EXPR ) - - _ARITH_OPS = frozenset( { 'PLUS', 'MINUS' } ) - - def Visit_arith_expr( self, node ): # pylint: disable=invalid-name - # arith_expr ::= term (('+'|'-') term)* - self.DefaultNodeVisit( node ) - _IncreasePenalty( node, ARITH_EXPR ) - _SetExpressionOperandPenalty( node, self._ARITH_OPS ) - - _TERM_OPS = frozenset( { 'STAR', 'AT', 'SLASH', 'PERCENT', 'DOUBLESLASH' } ) - - def Visit_term( self, node ): # pylint: disable=invalid-name - # term ::= factor (('*'|'@'|'/'|'%'|'//') factor)* - self.DefaultNodeVisit( node ) - _IncreasePenalty( node, TERM ) - _SetExpressionOperandPenalty( node, self._TERM_OPS ) - - def Visit_factor( self, node ): # pyline: disable=invalid-name - # factor ::= ('+'|'-'|'~') factor | power - self.DefaultNodeVisit( node ) - _IncreasePenalty( node, FACTOR ) - - def Visit_atom( self, node ): # pylint: disable=invalid-name - # atom ::= ('(' [yield_expr|testlist_gexp] ')' - # '[' [listmaker] ']' | - # '{' [dictsetmaker] '}') - self.DefaultNodeVisit( node ) - if ( node.children[ 0 ].value == '(' and - not hasattr( node.children[ 0 ], 'is_pseudo' ) ): - if node.children[ -1 ].value == ')': - if pytree_utils.NodeName( node.parent ) == 'if_stmt': - _SetSplitPenalty( node.children[ -1 ], STRONGLY_CONNECTED ) - else: - if len( node.children ) > 2: - _SetSplitPenalty( - pytree_utils.FirstLeafNode( node.children[ 1 ] ), EXPR ) - _SetSplitPenalty( node.children[ -1 ], ATOM ) - elif node.children[ 0 ].value in '[{' and len( node.children ) == 2: - # Keep empty containers together if we can. - _SetUnbreakable( node.children[ -1 ] ) - - def Visit_testlist_gexp( self, node ): # pylint: disable=invalid-name - self.DefaultNodeVisit( node ) + _SetSplitPenalty( + pytree_utils.FirstLeafNode(node.children[1]), + ONE_ELEMENT_ARGUMENT) + elif (node.children[0].type == grammar_token.LSQB and + len(node.children[1].children) > 2 and + (name.endswith('_test') or name.endswith('_expr'))): + _SetStronglyConnected(node.children[1].children[0]) + _SetStronglyConnected(node.children[1].children[2]) + + # Still allow splitting around the operator. + split_before = ( + ( + name.endswith('_test') and + style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR')) or ( + name.endswith('_expr') and + style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'))) + if split_before: + _SetSplitPenalty( + pytree_utils.LastLeafNode(node.children[1].children[1]), 0) + else: + _SetSplitPenalty( + pytree_utils.FirstLeafNode(node.children[1].children[2]), 0) + + # Don't split the ending bracket of a subscript list. + _RecAnnotate( + node.children[-1], pytree_utils.Annotation.SPLIT_PENALTY, + VERY_STRONGLY_CONNECTED) + elif name not in {'arglist', 'argument', 'term', 'or_test', 'and_test', + 'comparison', 'atom', 'power'}: + # Don't split an argument list with one element if at all possible. + stypes = pytree_utils.GetNodeAnnotation( + pytree_utils.FirstLeafNode(node), pytree_utils.Annotation.SUBTYPE) + if stypes and subtypes.SUBSCRIPT_BRACKET in stypes: + _IncreasePenalty(node, SUBSCRIPT) + + # Bump up the split penalty for the first part of a subscript. We + # would rather not split there. + _IncreasePenalty(node.children[1], CONNECTED) + else: + _SetStronglyConnected(node.children[1], node.children[2]) + + if name == 'arglist': + _SetStronglyConnected(node.children[-1]) + + self.DefaultNodeVisit(node) + + def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring + # power ::= atom trailer* ['**' factor] + self.DefaultNodeVisit(node) + + # When atom is followed by a trailer, we can not break between them. + # E.g. arr[idx] - no break allowed between 'arr' and '['. + if (len(node.children) > 1 and + pytree_utils.NodeName(node.children[1]) == 'trailer'): + # children[1] itself is a whole trailer: we don't want to + # mark all of it as unbreakable, only its first token: (, [ or . + first = pytree_utils.FirstLeafNode(node.children[1]) + if first.value != '.': + _SetUnbreakable(node.children[1].children[0]) + + # A special case when there are more trailers in the sequence. Given: + # atom tr1 tr2 + # The last token of tr1 and the first token of tr2 comprise an unbreakable + # region. For example: foo.bar.baz(1) + # We can't put breaks between either of the '.', '(', or '[' and the names + # *preceding* them. + prev_trailer_idx = 1 + while prev_trailer_idx < len(node.children) - 1: + cur_trailer_idx = prev_trailer_idx + 1 + cur_trailer = node.children[cur_trailer_idx] + if pytree_utils.NodeName(cur_trailer) != 'trailer': + break + + # Now we know we have two trailers one after the other + prev_trailer = node.children[prev_trailer_idx] + if prev_trailer.children[-1].value != ')': + # Set the previous node unbreakable if it's not a function call: + # atom tr1() tr2 + # It may be necessary (though undesirable) to split up a previous + # function call's parentheses to the next line. + _SetStronglyConnected(prev_trailer.children[-1]) + _SetStronglyConnected(cur_trailer.children[0]) + prev_trailer_idx = cur_trailer_idx + + # We don't want to split before the last ')' of a function call. This also + # takes care of the special case of: + # atom tr1 tr2 ... trn + # where the 'tr#' are trailers that may end in a ')'. + for trailer in node.children[1:]: + if pytree_utils.NodeName(trailer) != 'trailer': + break + if trailer.children[0].value in '([': + if len(trailer.children) > 2: + stypes = pytree_utils.GetNodeAnnotation( + trailer.children[0], pytree_utils.Annotation.SUBTYPE) + if stypes and subtypes.SUBSCRIPT_BRACKET in stypes: + _SetStronglyConnected( + pytree_utils.FirstLeafNode(trailer.children[1])) + + last_child_node = pytree_utils.LastLeafNode(trailer) + if last_child_node.value.strip().startswith('#'): + last_child_node = last_child_node.prev_sibling + if not (style.Get('INDENT_CLOSING_BRACKETS') or + style.Get('DEDENT_CLOSING_BRACKETS')): + last = pytree_utils.LastLeafNode(last_child_node.prev_sibling) + if last.value != ',': + if last_child_node.value == ']': + _SetUnbreakable(last_child_node) + else: + _SetSplitPenalty(last_child_node, VERY_STRONGLY_CONNECTED) + else: + # If the trailer's children are '()', then make it a strongly + # connected region. It's sometimes necessary, though undesirable, to + # split the two. + _SetStronglyConnected(trailer.children[-1]) + + def Visit_subscriptlist(self, node): # pylint: disable=invalid-name + # subscriptlist ::= subscript (',' subscript)* [','] + self.DefaultNodeVisit(node) + _SetSplitPenalty(pytree_utils.FirstLeafNode(node), 0) + prev_child = None + for child in node.children: + if prev_child and prev_child.type == grammar_token.COMMA: + _SetSplitPenalty(pytree_utils.FirstLeafNode(child), 0) + prev_child = child + + def Visit_subscript(self, node): # pylint: disable=invalid-name + # subscript ::= test | [test] ':' [test] [sliceop] + _SetStronglyConnected(*node.children) + self.DefaultNodeVisit(node) + + def Visit_comp_for(self, node): # pylint: disable=invalid-name + # comp_for ::= 'for' exprlist 'in' testlist_safe [comp_iter] + _SetSplitPenalty(pytree_utils.FirstLeafNode(node), 0) + _SetStronglyConnected(*node.children[1:]) + self.DefaultNodeVisit(node) + + def Visit_old_comp_for(self, node): # pylint: disable=invalid-name + # Python 3.7 + self.Visit_comp_for(node) + + def Visit_comp_if(self, node): # pylint: disable=invalid-name + # comp_if ::= 'if' old_test [comp_iter] + _SetSplitPenalty( + node.children[0], style.Get('SPLIT_PENALTY_BEFORE_IF_EXPR')) + _SetStronglyConnected(*node.children[1:]) + self.DefaultNodeVisit(node) + + def Visit_old_comp_if(self, node): # pylint: disable=invalid-name + # Python 3.7 + self.Visit_comp_if(node) + + def Visit_test(self, node): # pylint: disable=invalid-name + # test ::= or_test ['if' or_test 'else' test] | lambdef + _IncreasePenalty(node, OR_TEST) + self.DefaultNodeVisit(node) + + def Visit_or_test(self, node): # pylint: disable=invalid-name + # or_test ::= and_test ('or' and_test)* + self.DefaultNodeVisit(node) + _IncreasePenalty(node, OR_TEST) + index = 1 + while index + 1 < len(node.children): + if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'): + _DecrementSplitPenalty( + pytree_utils.FirstLeafNode(node.children[index]), OR_TEST) + else: + _DecrementSplitPenalty( + pytree_utils.FirstLeafNode(node.children[index + 1]), OR_TEST) + index += 2 + + def Visit_and_test(self, node): # pylint: disable=invalid-name + # and_test ::= not_test ('and' not_test)* + self.DefaultNodeVisit(node) + _IncreasePenalty(node, AND_TEST) + index = 1 + while index + 1 < len(node.children): + if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'): + _DecrementSplitPenalty( + pytree_utils.FirstLeafNode(node.children[index]), AND_TEST) + else: + _DecrementSplitPenalty( + pytree_utils.FirstLeafNode(node.children[index + 1]), AND_TEST) + index += 2 + + def Visit_not_test(self, node): # pylint: disable=invalid-name + # not_test ::= 'not' not_test | comparison + self.DefaultNodeVisit(node) + _IncreasePenalty(node, NOT_TEST) + + def Visit_comparison(self, node): # pylint: disable=invalid-name + # comparison ::= expr (comp_op expr)* + self.DefaultNodeVisit(node) + if len(node.children) == 3 and _StronglyConnectedCompOp(node): + _IncreasePenalty(node.children[1], VERY_STRONGLY_CONNECTED) + _SetSplitPenalty( + pytree_utils.FirstLeafNode(node.children[2]), STRONGLY_CONNECTED) + else: + _IncreasePenalty(node, COMPARISON) + + def Visit_star_expr(self, node): # pylint: disable=invalid-name + # star_expr ::= '*' expr + self.DefaultNodeVisit(node) + _IncreasePenalty(node, STAR_EXPR) + + def Visit_expr(self, node): # pylint: disable=invalid-name + # expr ::= xor_expr ('|' xor_expr)* + self.DefaultNodeVisit(node) + _IncreasePenalty(node, EXPR) + _SetBitwiseOperandPenalty(node, '|') + + def Visit_xor_expr(self, node): # pylint: disable=invalid-name + # xor_expr ::= and_expr ('^' and_expr)* + self.DefaultNodeVisit(node) + _IncreasePenalty(node, XOR_EXPR) + _SetBitwiseOperandPenalty(node, '^') + + def Visit_and_expr(self, node): # pylint: disable=invalid-name + # and_expr ::= shift_expr ('&' shift_expr)* + self.DefaultNodeVisit(node) + _IncreasePenalty(node, AND_EXPR) + _SetBitwiseOperandPenalty(node, '&') + + def Visit_shift_expr(self, node): # pylint: disable=invalid-name + # shift_expr ::= arith_expr (('<<'|'>>') arith_expr)* + self.DefaultNodeVisit(node) + _IncreasePenalty(node, SHIFT_EXPR) + + _ARITH_OPS = frozenset({'PLUS', 'MINUS'}) + + def Visit_arith_expr(self, node): # pylint: disable=invalid-name + # arith_expr ::= term (('+'|'-') term)* + self.DefaultNodeVisit(node) + _IncreasePenalty(node, ARITH_EXPR) + _SetExpressionOperandPenalty(node, self._ARITH_OPS) + + _TERM_OPS = frozenset({'STAR', 'AT', 'SLASH', 'PERCENT', 'DOUBLESLASH'}) + + def Visit_term(self, node): # pylint: disable=invalid-name + # term ::= factor (('*'|'@'|'/'|'%'|'//') factor)* + self.DefaultNodeVisit(node) + _IncreasePenalty(node, TERM) + _SetExpressionOperandPenalty(node, self._TERM_OPS) + + def Visit_factor(self, node): # pyline: disable=invalid-name + # factor ::= ('+'|'-'|'~') factor | power + self.DefaultNodeVisit(node) + _IncreasePenalty(node, FACTOR) + + def Visit_atom(self, node): # pylint: disable=invalid-name + # atom ::= ('(' [yield_expr|testlist_gexp] ')' + # '[' [listmaker] ']' | + # '{' [dictsetmaker] '}') + self.DefaultNodeVisit(node) + if (node.children[0].value == '(' and + not hasattr(node.children[0], 'is_pseudo')): + if node.children[-1].value == ')': + if pytree_utils.NodeName(node.parent) == 'if_stmt': + _SetSplitPenalty(node.children[-1], STRONGLY_CONNECTED) + else: + if len(node.children) > 2: + _SetSplitPenalty(pytree_utils.FirstLeafNode(node.children[1]), EXPR) + _SetSplitPenalty(node.children[-1], ATOM) + elif node.children[0].value in '[{' and len(node.children) == 2: + # Keep empty containers together if we can. + _SetUnbreakable(node.children[-1]) + + def Visit_testlist_gexp(self, node): # pylint: disable=invalid-name + self.DefaultNodeVisit(node) + prev_was_comma = False + for child in node.children: + if isinstance(child, pytree.Leaf) and child.value == ',': + _SetUnbreakable(child) + prev_was_comma = True + else: + if prev_was_comma: + _SetSplitPenalty(pytree_utils.FirstLeafNode(child), TOGETHER) prev_was_comma = False - for child in node.children: - if isinstance( child, pytree.Leaf ) and child.value == ',': - _SetUnbreakable( child ) - prev_was_comma = True - else: - if prev_was_comma: - _SetSplitPenalty( pytree_utils.FirstLeafNode( child ), TOGETHER ) - prev_was_comma = False -def _SetUnbreakable( node ): - """Set an UNBREAKABLE penalty annotation for the given node.""" - _RecAnnotate( node, pytree_utils.Annotation.SPLIT_PENALTY, UNBREAKABLE ) +def _SetUnbreakable(node): + """Set an UNBREAKABLE penalty annotation for the given node.""" + _RecAnnotate(node, pytree_utils.Annotation.SPLIT_PENALTY, UNBREAKABLE) -def _SetStronglyConnected( *nodes ): - """Set a STRONGLY_CONNECTED penalty annotation for the given nodes.""" - for node in nodes: - _RecAnnotate( node, pytree_utils.Annotation.SPLIT_PENALTY, STRONGLY_CONNECTED ) +def _SetStronglyConnected(*nodes): + """Set a STRONGLY_CONNECTED penalty annotation for the given nodes.""" + for node in nodes: + _RecAnnotate( + node, pytree_utils.Annotation.SPLIT_PENALTY, STRONGLY_CONNECTED) -def _SetExpressionPenalty( node, penalty ): - """Set a penalty annotation on children nodes.""" +def _SetExpressionPenalty(node, penalty): + """Set a penalty annotation on children nodes.""" - def RecExpression( node, first_child_leaf ): - if node is first_child_leaf: - return + def RecExpression(node, first_child_leaf): + if node is first_child_leaf: + return - if isinstance( node, pytree.Leaf ): - if node.value in { '(', 'for', 'if' }: - return - penalty_annotation = pytree_utils.GetNodeAnnotation( - node, pytree_utils.Annotation.SPLIT_PENALTY, default = 0 ) - if penalty_annotation < penalty: - _SetSplitPenalty( node, penalty ) - else: - for child in node.children: - RecExpression( child, first_child_leaf ) - - RecExpression( node, pytree_utils.FirstLeafNode( node ) ) - - -def _SetBitwiseOperandPenalty( node, op ): - for index in py3compat.range( 1, len( node.children ) - 1 ): - child = node.children[ index ] - if isinstance( child, pytree.Leaf ) and child.value == op: - if style.Get( 'SPLIT_BEFORE_BITWISE_OPERATOR' ): - _SetSplitPenalty( child, style.Get( 'SPLIT_PENALTY_BITWISE_OPERATOR' ) ) - else: - _SetSplitPenalty( - pytree_utils.FirstLeafNode( node.children[ index + 1 ] ), - style.Get( 'SPLIT_PENALTY_BITWISE_OPERATOR' ) ) - - -def _SetExpressionOperandPenalty( node, ops ): - for index in py3compat.range( 1, len( node.children ) - 1 ): - child = node.children[ index ] - if pytree_utils.NodeName( child ) in ops: - if style.Get( 'SPLIT_BEFORE_ARITHMETIC_OPERATOR' ): - _SetSplitPenalty( - child, style.Get( 'SPLIT_PENALTY_ARITHMETIC_OPERATOR' ) ) - else: - _SetSplitPenalty( - pytree_utils.FirstLeafNode( node.children[ index + 1 ] ), - style.Get( 'SPLIT_PENALTY_ARITHMETIC_OPERATOR' ) ) - - -def _IncreasePenalty( node, amt ): - """Increase a penalty annotation on children nodes.""" - - def RecExpression( node, first_child_leaf ): - if node is first_child_leaf: - return - - if isinstance( node, pytree.Leaf ): - if node.value in { '(', 'for' }: - return - penalty = pytree_utils.GetNodeAnnotation( - node, pytree_utils.Annotation.SPLIT_PENALTY, default = 0 ) - _SetSplitPenalty( node, penalty + amt ) - else: - for child in node.children: - RecExpression( child, first_child_leaf ) + if isinstance(node, pytree.Leaf): + if node.value in {'(', 'for', 'if'}: + return + penalty_annotation = pytree_utils.GetNodeAnnotation( + node, pytree_utils.Annotation.SPLIT_PENALTY, default=0) + if penalty_annotation < penalty: + _SetSplitPenalty(node, penalty) + else: + for child in node.children: + RecExpression(child, first_child_leaf) + + RecExpression(node, pytree_utils.FirstLeafNode(node)) + + +def _SetBitwiseOperandPenalty(node, op): + for index in py3compat.range(1, len(node.children) - 1): + child = node.children[index] + if isinstance(child, pytree.Leaf) and child.value == op: + if style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'): + _SetSplitPenalty(child, style.Get('SPLIT_PENALTY_BITWISE_OPERATOR')) + else: + _SetSplitPenalty( + pytree_utils.FirstLeafNode(node.children[index + 1]), + style.Get('SPLIT_PENALTY_BITWISE_OPERATOR')) + + +def _SetExpressionOperandPenalty(node, ops): + for index in py3compat.range(1, len(node.children) - 1): + child = node.children[index] + if pytree_utils.NodeName(child) in ops: + if style.Get('SPLIT_BEFORE_ARITHMETIC_OPERATOR'): + _SetSplitPenalty(child, style.Get('SPLIT_PENALTY_ARITHMETIC_OPERATOR')) + else: + _SetSplitPenalty( + pytree_utils.FirstLeafNode(node.children[index + 1]), + style.Get('SPLIT_PENALTY_ARITHMETIC_OPERATOR')) + + +def _IncreasePenalty(node, amt): + """Increase a penalty annotation on children nodes.""" + + def RecExpression(node, first_child_leaf): + if node is first_child_leaf: + return + + if isinstance(node, pytree.Leaf): + if node.value in {'(', 'for'}: + return + penalty = pytree_utils.GetNodeAnnotation( + node, pytree_utils.Annotation.SPLIT_PENALTY, default=0) + _SetSplitPenalty(node, penalty + amt) + else: + for child in node.children: + RecExpression(child, first_child_leaf) - RecExpression( node, pytree_utils.FirstLeafNode( node ) ) + RecExpression(node, pytree_utils.FirstLeafNode(node)) -def _RecAnnotate( tree, annotate_name, annotate_value ): - """Recursively set the given annotation on all leafs of the subtree. +def _RecAnnotate(tree, annotate_name, annotate_value): + """Recursively set the given annotation on all leafs of the subtree. Takes care to only increase the penalty. If the node already has a higher or equal penalty associated with it, this is a no-op. @@ -603,40 +595,40 @@ def _RecAnnotate( tree, annotate_name, annotate_value ): annotate_name: name of the annotation to set annotate_value: value of the annotation to set """ - for child in tree.children: - _RecAnnotate( child, annotate_name, annotate_value ) - if isinstance( tree, pytree.Leaf ): - cur_annotate = pytree_utils.GetNodeAnnotation( - tree, annotate_name, default = 0 ) - if cur_annotate < annotate_value: - pytree_utils.SetNodeAnnotation( tree, annotate_name, annotate_value ) - - -_COMP_OPS = frozenset( { '==', '!=', '<=', '<', '>', '>=', '<>', 'in', 'is' } ) - - -def _StronglyConnectedCompOp( op ): - if ( len( op.children[ 1 ].children ) == 2 and - pytree_utils.NodeName( op.children[ 1 ] ) == 'comp_op' ): - if ( pytree_utils.FirstLeafNode( op.children[ 1 ] ).value == 'not' and - pytree_utils.LastLeafNode( op.children[ 1 ] ).value == 'in' ): - return True - if ( pytree_utils.FirstLeafNode( op.children[ 1 ] ).value == 'is' and - pytree_utils.LastLeafNode( op.children[ 1 ] ).value == 'not' ): - return True - if ( isinstance( op.children[ 1 ], pytree.Leaf ) and - op.children[ 1 ].value in _COMP_OPS ): - return True - return False - - -def _DecrementSplitPenalty( node, amt ): - penalty = pytree_utils.GetNodeAnnotation( - node, pytree_utils.Annotation.SPLIT_PENALTY, default = amt ) - penalty = penalty - amt if amt < penalty else 0 - _SetSplitPenalty( node, penalty ) - - -def _SetSplitPenalty( node, penalty ): - pytree_utils.SetNodeAnnotation( - node, pytree_utils.Annotation.SPLIT_PENALTY, penalty ) + for child in tree.children: + _RecAnnotate(child, annotate_name, annotate_value) + if isinstance(tree, pytree.Leaf): + cur_annotate = pytree_utils.GetNodeAnnotation( + tree, annotate_name, default=0) + if cur_annotate < annotate_value: + pytree_utils.SetNodeAnnotation(tree, annotate_name, annotate_value) + + +_COMP_OPS = frozenset({'==', '!=', '<=', '<', '>', '>=', '<>', 'in', 'is'}) + + +def _StronglyConnectedCompOp(op): + if (len(op.children[1].children) == 2 and + pytree_utils.NodeName(op.children[1]) == 'comp_op'): + if (pytree_utils.FirstLeafNode(op.children[1]).value == 'not' and + pytree_utils.LastLeafNode(op.children[1]).value == 'in'): + return True + if (pytree_utils.FirstLeafNode(op.children[1]).value == 'is' and + pytree_utils.LastLeafNode(op.children[1]).value == 'not'): + return True + if (isinstance(op.children[1], pytree.Leaf) and + op.children[1].value in _COMP_OPS): + return True + return False + + +def _DecrementSplitPenalty(node, amt): + penalty = pytree_utils.GetNodeAnnotation( + node, pytree_utils.Annotation.SPLIT_PENALTY, default=amt) + penalty = penalty - amt if amt < penalty else 0 + _SetSplitPenalty(node, penalty) + + +def _SetSplitPenalty(node, penalty): + pytree_utils.SetNodeAnnotation( + node, pytree_utils.Annotation.SPLIT_PENALTY, penalty) diff --git a/yapf/pytree/subtype_assigner.py b/yapf/pytree/subtype_assigner.py index 19c65b323..06d1411f8 100644 --- a/yapf/pytree/subtype_assigner.py +++ b/yapf/pytree/subtype_assigner.py @@ -34,14 +34,14 @@ from yapf.yapflib import subtypes -def AssignSubtypes( tree ): - """Run the subtype assigner visitor over the tree, modifying it in place. +def AssignSubtypes(tree): + """Run the subtype assigner visitor over the tree, modifying it in place. Arguments: tree: the top-level pytree node to annotate with subtypes. """ - subtype_assigner = _SubtypeAssigner() - subtype_assigner.Visit( tree ) + subtype_assigner = _SubtypeAssigner() + subtype_assigner.Visit(tree) # Map tokens in argument lists to their respective subtype. @@ -53,448 +53,446 @@ def AssignSubtypes( tree ): } -class _SubtypeAssigner( pytree_visitor.PyTreeVisitor ): - """_SubtypeAssigner - see file-level docstring for detailed description. +class _SubtypeAssigner(pytree_visitor.PyTreeVisitor): + """_SubtypeAssigner - see file-level docstring for detailed description. The subtype is added as an annotation to the pytree token. """ - def Visit_dictsetmaker( self, node ): # pylint: disable=invalid-name - # dictsetmaker ::= (test ':' test (comp_for | - # (',' test ':' test)* [','])) | - # (test (comp_for | (',' test)* [','])) - for child in node.children: - self.Visit( child ) - - comp_for = False - dict_maker = False - - for child in node.children: - if pytree_utils.NodeName( child ) == 'comp_for': - comp_for = True - _AppendFirstLeafTokenSubtype( child, subtypes.DICT_SET_GENERATOR ) - elif child.type in ( grammar_token.COLON, grammar_token.DOUBLESTAR ): - dict_maker = True - - if not comp_for and dict_maker: - last_was_colon = False - unpacking = False - for child in node.children: - if child.type == grammar_token.DOUBLESTAR: - _AppendFirstLeafTokenSubtype( child, subtypes.KWARGS_STAR_STAR ) - if last_was_colon: - if style.Get( 'INDENT_DICTIONARY_VALUE' ): - _InsertPseudoParentheses( child ) - else: - _AppendFirstLeafTokenSubtype( child, subtypes.DICTIONARY_VALUE ) - elif ( isinstance( child, pytree.Node ) or - ( not child.value.startswith( '#' ) and - child.value not in '{:,' ) ): - # Mark the first leaf of a key entry as a DICTIONARY_KEY. We - # normally want to split before them if the dictionary cannot exist - # on a single line. - if not unpacking or pytree_utils.FirstLeafNode( - child ).value == '**': - _AppendFirstLeafTokenSubtype( child, subtypes.DICTIONARY_KEY ) - _AppendSubtypeRec( child, subtypes.DICTIONARY_KEY_PART ) - last_was_colon = child.type == grammar_token.COLON - if child.type == grammar_token.DOUBLESTAR: - unpacking = True - elif last_was_colon: - unpacking = False - - def Visit_expr_stmt( self, node ): # pylint: disable=invalid-name - # expr_stmt ::= testlist_star_expr (augassign (yield_expr|testlist) - # | ('=' (yield_expr|testlist_star_expr))*) - for child in node.children: - self.Visit( child ) - if isinstance( child, pytree.Leaf ) and child.value == '=': - _AppendTokenSubtype( child, subtypes.ASSIGN_OPERATOR ) - - def Visit_or_test( self, node ): # pylint: disable=invalid-name - # or_test ::= and_test ('or' and_test)* - for child in node.children: - self.Visit( child ) - if isinstance( child, pytree.Leaf ) and child.value == 'or': - _AppendTokenSubtype( child, subtypes.BINARY_OPERATOR ) - - def Visit_and_test( self, node ): # pylint: disable=invalid-name - # and_test ::= not_test ('and' not_test)* - for child in node.children: - self.Visit( child ) - if isinstance( child, pytree.Leaf ) and child.value == 'and': - _AppendTokenSubtype( child, subtypes.BINARY_OPERATOR ) - - def Visit_not_test( self, node ): # pylint: disable=invalid-name - # not_test ::= 'not' not_test | comparison - for child in node.children: - self.Visit( child ) - if isinstance( child, pytree.Leaf ) and child.value == 'not': - _AppendTokenSubtype( child, subtypes.UNARY_OPERATOR ) - - def Visit_comparison( self, node ): # pylint: disable=invalid-name - # comparison ::= expr (comp_op expr)* - # comp_op ::= '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not in'|'is'|'is not' - for child in node.children: - self.Visit( child ) - if ( isinstance( child, pytree.Leaf ) and child.value - in { '<', '>', '==', '>=', '<=', '<>', '!=', 'in', 'is' } ): - _AppendTokenSubtype( child, subtypes.BINARY_OPERATOR ) - elif pytree_utils.NodeName( child ) == 'comp_op': - for grandchild in child.children: - _AppendTokenSubtype( grandchild, subtypes.BINARY_OPERATOR ) - - def Visit_star_expr( self, node ): # pylint: disable=invalid-name - # star_expr ::= '*' expr - for child in node.children: - self.Visit( child ) - if isinstance( child, pytree.Leaf ) and child.value == '*': - _AppendTokenSubtype( child, subtypes.UNARY_OPERATOR ) - _AppendTokenSubtype( child, subtypes.VARARGS_STAR ) - - def Visit_expr( self, node ): # pylint: disable=invalid-name - # expr ::= xor_expr ('|' xor_expr)* - for child in node.children: - self.Visit( child ) - if isinstance( child, pytree.Leaf ) and child.value == '|': - _AppendTokenSubtype( child, subtypes.BINARY_OPERATOR ) - - def Visit_xor_expr( self, node ): # pylint: disable=invalid-name - # xor_expr ::= and_expr ('^' and_expr)* - for child in node.children: - self.Visit( child ) - if isinstance( child, pytree.Leaf ) and child.value == '^': - _AppendTokenSubtype( child, subtypes.BINARY_OPERATOR ) - - def Visit_and_expr( self, node ): # pylint: disable=invalid-name - # and_expr ::= shift_expr ('&' shift_expr)* - for child in node.children: - self.Visit( child ) - if isinstance( child, pytree.Leaf ) and child.value == '&': - _AppendTokenSubtype( child, subtypes.BINARY_OPERATOR ) - - def Visit_shift_expr( self, node ): # pylint: disable=invalid-name - # shift_expr ::= arith_expr (('<<'|'>>') arith_expr)* - for child in node.children: - self.Visit( child ) - if isinstance( child, pytree.Leaf ) and child.value in { '<<', '>>' }: - _AppendTokenSubtype( child, subtypes.BINARY_OPERATOR ) - - def Visit_arith_expr( self, node ): # pylint: disable=invalid-name - # arith_expr ::= term (('+'|'-') term)* - for child in node.children: - self.Visit( child ) - if _IsAExprOperator( child ): - _AppendTokenSubtype( child, subtypes.BINARY_OPERATOR ) - - if _IsSimpleExpression( node ): - for child in node.children: - if _IsAExprOperator( child ): - _AppendTokenSubtype( child, subtypes.SIMPLE_EXPRESSION ) - - def Visit_term( self, node ): # pylint: disable=invalid-name - # term ::= factor (('*'|'/'|'%'|'//'|'@') factor)* - for child in node.children: - self.Visit( child ) - if _IsMExprOperator( child ): - _AppendTokenSubtype( child, subtypes.BINARY_OPERATOR ) - - if _IsSimpleExpression( node ): - for child in node.children: - if _IsMExprOperator( child ): - _AppendTokenSubtype( child, subtypes.SIMPLE_EXPRESSION ) - - def Visit_factor( self, node ): # pylint: disable=invalid-name - # factor ::= ('+'|'-'|'~') factor | power - for child in node.children: - self.Visit( child ) - if isinstance( child, pytree.Leaf ) and child.value in '+-~': - _AppendTokenSubtype( child, subtypes.UNARY_OPERATOR ) - - def Visit_power( self, node ): # pylint: disable=invalid-name - # power ::= atom trailer* ['**' factor] - for child in node.children: - self.Visit( child ) - if isinstance( child, pytree.Leaf ) and child.value == '**': - _AppendTokenSubtype( child, subtypes.BINARY_OPERATOR ) - - def Visit_trailer( self, node ): # pylint: disable=invalid-name - for child in node.children: - self.Visit( child ) - if isinstance( child, pytree.Leaf ) and child.value in '[]': - _AppendTokenSubtype( child, subtypes.SUBSCRIPT_BRACKET ) - - def Visit_subscript( self, node ): # pylint: disable=invalid-name - # subscript ::= test | [test] ':' [test] [sliceop] - for child in node.children: - self.Visit( child ) - if isinstance( child, pytree.Leaf ) and child.value == ':': - _AppendTokenSubtype( child, subtypes.SUBSCRIPT_COLON ) - - def Visit_sliceop( self, node ): # pylint: disable=invalid-name - # sliceop ::= ':' [test] - for child in node.children: - self.Visit( child ) - if isinstance( child, pytree.Leaf ) and child.value == ':': - _AppendTokenSubtype( child, subtypes.SUBSCRIPT_COLON ) - - def Visit_argument( self, node ): # pylint: disable=invalid-name - # argument ::= - # test [comp_for] | test '=' test - self._ProcessArgLists( node ) - #TODO add a subtype to each argument? - - def Visit_arglist( self, node ): # pylint: disable=invalid-name - # arglist ::= - # (argument ',')* (argument [','] - # | '*' test (',' argument)* [',' '**' test] - # | '**' test) - self._ProcessArgLists( node ) - _SetArgListSubtype( - node, subtypes.DEFAULT_OR_NAMED_ASSIGN, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST ) + def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name + # dictsetmaker ::= (test ':' test (comp_for | + # (',' test ':' test)* [','])) | + # (test (comp_for | (',' test)* [','])) + for child in node.children: + self.Visit(child) - def Visit_tname( self, node ): # pylint: disable=invalid-name - self._ProcessArgLists( node ) - _SetArgListSubtype( - node, subtypes.DEFAULT_OR_NAMED_ASSIGN, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST ) - - def Visit_decorator( self, node ): # pylint: disable=invalid-name - # decorator ::= - # '@' dotted_name [ '(' [arglist] ')' ] NEWLINE - for child in node.children: - if isinstance( child, pytree.Leaf ) and child.value == '@': - _AppendTokenSubtype( child, subtype = subtypes.DECORATOR ) - self.Visit( child ) - - def Visit_funcdef( self, node ): # pylint: disable=invalid-name - # funcdef ::= - # 'def' NAME parameters ['->' test] ':' suite - for child in node.children: - if child.type == grammar_token.NAME and child.value != 'def': - _AppendTokenSubtype( child, subtypes.FUNC_DEF ) - break - for child in node.children: - self.Visit( child ) - - def Visit_parameters( self, node ): # pylint: disable=invalid-name - # parameters ::= '(' [typedargslist] ')' - self._ProcessArgLists( node ) - if len( node.children ) > 2: - _AppendFirstLeafTokenSubtype( node.children[ 1 ], subtypes.PARAMETER_START ) - _AppendLastLeafTokenSubtype( node.children[ -2 ], subtypes.PARAMETER_STOP ) - - def Visit_typedargslist( self, node ): # pylint: disable=invalid-name - # typedargslist ::= - # ((tfpdef ['=' test] ',')* - # ('*' [tname] (',' tname ['=' test])* [',' '**' tname] - # | '**' tname) - # | tfpdef ['=' test] (',' tfpdef ['=' test])* [',']) - self._ProcessArgLists( node ) - _SetArgListSubtype( - node, subtypes.DEFAULT_OR_NAMED_ASSIGN, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST ) - tname = False - if not node.children: - return - - _AppendFirstLeafTokenSubtype( node.children[ 0 ], subtypes.PARAMETER_START ) - _AppendLastLeafTokenSubtype( node.children[ -1 ], subtypes.PARAMETER_STOP ) - - tname = pytree_utils.NodeName( node.children[ 0 ] ) == 'tname' - for i in range( 1, len( node.children ) ): - prev_child = node.children[ i - 1 ] - child = node.children[ i ] - if prev_child.type == grammar_token.COMMA: - _AppendFirstLeafTokenSubtype( child, subtypes.PARAMETER_START ) - elif child.type == grammar_token.COMMA: - _AppendLastLeafTokenSubtype( prev_child, subtypes.PARAMETER_STOP ) - - if pytree_utils.NodeName( child ) == 'tname': - tname = True - _SetArgListSubtype( - child, subtypes.TYPED_NAME, subtypes.TYPED_NAME_ARG_LIST ) - elif child.type == grammar_token.COMMA: - tname = False - elif child.type == grammar_token.EQUAL and tname: - _AppendTokenSubtype( child, subtype = subtypes.TYPED_NAME ) - tname = False - - def Visit_varargslist( self, node ): # pylint: disable=invalid-name - # varargslist ::= - # ((vfpdef ['=' test] ',')* - # ('*' [vname] (',' vname ['=' test])* [',' '**' vname] - # | '**' vname) - # | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) - self._ProcessArgLists( node ) - for child in node.children: - self.Visit( child ) - if isinstance( child, pytree.Leaf ) and child.value == '=': - _AppendTokenSubtype( child, subtypes.VARARGS_LIST ) - - def Visit_comp_for( self, node ): # pylint: disable=invalid-name - # comp_for ::= 'for' exprlist 'in' testlist_safe [comp_iter] - _AppendSubtypeRec( node, subtypes.COMP_FOR ) - # Mark the previous node as COMP_EXPR unless this is a nested comprehension - # as these will have the outer comprehension as their previous node. - attr = pytree_utils.GetNodeAnnotation( - node.parent, pytree_utils.Annotation.SUBTYPE ) - if not attr or subtypes.COMP_FOR not in attr: - _AppendSubtypeRec( node.parent.children[ 0 ], subtypes.COMP_EXPR ) - self.DefaultNodeVisit( node ) - - def Visit_old_comp_for( self, node ): # pylint: disable=invalid-name - # Python 3.7 - self.Visit_comp_for( node ) - - def Visit_comp_if( self, node ): # pylint: disable=invalid-name - # comp_if ::= 'if' old_test [comp_iter] - _AppendSubtypeRec( node, subtypes.COMP_IF ) - self.DefaultNodeVisit( node ) - - def Visit_old_comp_if( self, node ): # pylint: disable=invalid-name - # Python 3.7 - self.Visit_comp_if( node ) - - def _ProcessArgLists( self, node ): - """Common method for processing argument lists.""" - for child in node.children: - self.Visit( child ) - if isinstance( child, pytree.Leaf ): - _AppendTokenSubtype( - child, - subtype = _ARGLIST_TOKEN_TO_SUBTYPE.get( - child.value, subtypes.NONE ) ) - - -def _SetArgListSubtype( node, node_subtype, list_subtype ): - """Set named assign subtype on elements in a arg list.""" - - def HasSubtype( node ): - """Return True if the arg list has a named assign subtype.""" - if isinstance( node, pytree.Leaf ): - return node_subtype in pytree_utils.GetNodeAnnotation( - node, pytree_utils.Annotation.SUBTYPE, set() ) - - for child in node.children: - node_name = pytree_utils.NodeName( child ) - if node_name not in { 'atom', 'arglist', 'power' }: - if HasSubtype( child ): - return True - - return False - - if not HasSubtype( node ): - return + comp_for = False + dict_maker = False + + for child in node.children: + if pytree_utils.NodeName(child) == 'comp_for': + comp_for = True + _AppendFirstLeafTokenSubtype(child, subtypes.DICT_SET_GENERATOR) + elif child.type in (grammar_token.COLON, grammar_token.DOUBLESTAR): + dict_maker = True + + if not comp_for and dict_maker: + last_was_colon = False + unpacking = False + for child in node.children: + if child.type == grammar_token.DOUBLESTAR: + _AppendFirstLeafTokenSubtype(child, subtypes.KWARGS_STAR_STAR) + if last_was_colon: + if style.Get('INDENT_DICTIONARY_VALUE'): + _InsertPseudoParentheses(child) + else: + _AppendFirstLeafTokenSubtype(child, subtypes.DICTIONARY_VALUE) + elif (isinstance(child, pytree.Node) or + (not child.value.startswith('#') and child.value not in '{:,')): + # Mark the first leaf of a key entry as a DICTIONARY_KEY. We + # normally want to split before them if the dictionary cannot exist + # on a single line. + if not unpacking or pytree_utils.FirstLeafNode(child).value == '**': + _AppendFirstLeafTokenSubtype(child, subtypes.DICTIONARY_KEY) + _AppendSubtypeRec(child, subtypes.DICTIONARY_KEY_PART) + last_was_colon = child.type == grammar_token.COLON + if child.type == grammar_token.DOUBLESTAR: + unpacking = True + elif last_was_colon: + unpacking = False + + def Visit_expr_stmt(self, node): # pylint: disable=invalid-name + # expr_stmt ::= testlist_star_expr (augassign (yield_expr|testlist) + # | ('=' (yield_expr|testlist_star_expr))*) + for child in node.children: + self.Visit(child) + if isinstance(child, pytree.Leaf) and child.value == '=': + _AppendTokenSubtype(child, subtypes.ASSIGN_OPERATOR) + + def Visit_or_test(self, node): # pylint: disable=invalid-name + # or_test ::= and_test ('or' and_test)* + for child in node.children: + self.Visit(child) + if isinstance(child, pytree.Leaf) and child.value == 'or': + _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) + def Visit_and_test(self, node): # pylint: disable=invalid-name + # and_test ::= not_test ('and' not_test)* for child in node.children: - node_name = pytree_utils.NodeName( child ) - if node_name not in { 'atom', 'COMMA' }: - _AppendFirstLeafTokenSubtype( child, list_subtype ) + self.Visit(child) + if isinstance(child, pytree.Leaf) and child.value == 'and': + _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) + def Visit_not_test(self, node): # pylint: disable=invalid-name + # not_test ::= 'not' not_test | comparison + for child in node.children: + self.Visit(child) + if isinstance(child, pytree.Leaf) and child.value == 'not': + _AppendTokenSubtype(child, subtypes.UNARY_OPERATOR) -def _AppendTokenSubtype( node, subtype ): - """Append the token's subtype only if it's not already set.""" - pytree_utils.AppendNodeAnnotation( node, pytree_utils.Annotation.SUBTYPE, subtype ) + def Visit_comparison(self, node): # pylint: disable=invalid-name + # comparison ::= expr (comp_op expr)* + # comp_op ::= '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not in'|'is'|'is not' + for child in node.children: + self.Visit(child) + if (isinstance(child, pytree.Leaf) and + child.value in {'<', '>', '==', '>=', '<=', '<>', '!=', 'in', 'is'}): + _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) + elif pytree_utils.NodeName(child) == 'comp_op': + for grandchild in child.children: + _AppendTokenSubtype(grandchild, subtypes.BINARY_OPERATOR) + + def Visit_star_expr(self, node): # pylint: disable=invalid-name + # star_expr ::= '*' expr + for child in node.children: + self.Visit(child) + if isinstance(child, pytree.Leaf) and child.value == '*': + _AppendTokenSubtype(child, subtypes.UNARY_OPERATOR) + _AppendTokenSubtype(child, subtypes.VARARGS_STAR) + + def Visit_expr(self, node): # pylint: disable=invalid-name + # expr ::= xor_expr ('|' xor_expr)* + for child in node.children: + self.Visit(child) + if isinstance(child, pytree.Leaf) and child.value == '|': + _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) + + def Visit_xor_expr(self, node): # pylint: disable=invalid-name + # xor_expr ::= and_expr ('^' and_expr)* + for child in node.children: + self.Visit(child) + if isinstance(child, pytree.Leaf) and child.value == '^': + _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) + + def Visit_and_expr(self, node): # pylint: disable=invalid-name + # and_expr ::= shift_expr ('&' shift_expr)* + for child in node.children: + self.Visit(child) + if isinstance(child, pytree.Leaf) and child.value == '&': + _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) + + def Visit_shift_expr(self, node): # pylint: disable=invalid-name + # shift_expr ::= arith_expr (('<<'|'>>') arith_expr)* + for child in node.children: + self.Visit(child) + if isinstance(child, pytree.Leaf) and child.value in {'<<', '>>'}: + _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) + + def Visit_arith_expr(self, node): # pylint: disable=invalid-name + # arith_expr ::= term (('+'|'-') term)* + for child in node.children: + self.Visit(child) + if _IsAExprOperator(child): + _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) + if _IsSimpleExpression(node): + for child in node.children: + if _IsAExprOperator(child): + _AppendTokenSubtype(child, subtypes.SIMPLE_EXPRESSION) -def _AppendFirstLeafTokenSubtype( node, subtype ): - """Append the first leaf token's subtypes.""" - if isinstance( node, pytree.Leaf ): - _AppendTokenSubtype( node, subtype ) - return - _AppendFirstLeafTokenSubtype( node.children[ 0 ], subtype ) + def Visit_term(self, node): # pylint: disable=invalid-name + # term ::= factor (('*'|'/'|'%'|'//'|'@') factor)* + for child in node.children: + self.Visit(child) + if _IsMExprOperator(child): + _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) + + if _IsSimpleExpression(node): + for child in node.children: + if _IsMExprOperator(child): + _AppendTokenSubtype(child, subtypes.SIMPLE_EXPRESSION) + + def Visit_factor(self, node): # pylint: disable=invalid-name + # factor ::= ('+'|'-'|'~') factor | power + for child in node.children: + self.Visit(child) + if isinstance(child, pytree.Leaf) and child.value in '+-~': + _AppendTokenSubtype(child, subtypes.UNARY_OPERATOR) + + def Visit_power(self, node): # pylint: disable=invalid-name + # power ::= atom trailer* ['**' factor] + for child in node.children: + self.Visit(child) + if isinstance(child, pytree.Leaf) and child.value == '**': + _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) + + def Visit_trailer(self, node): # pylint: disable=invalid-name + for child in node.children: + self.Visit(child) + if isinstance(child, pytree.Leaf) and child.value in '[]': + _AppendTokenSubtype(child, subtypes.SUBSCRIPT_BRACKET) + + def Visit_subscript(self, node): # pylint: disable=invalid-name + # subscript ::= test | [test] ':' [test] [sliceop] + for child in node.children: + self.Visit(child) + if isinstance(child, pytree.Leaf) and child.value == ':': + _AppendTokenSubtype(child, subtypes.SUBSCRIPT_COLON) + + def Visit_sliceop(self, node): # pylint: disable=invalid-name + # sliceop ::= ':' [test] + for child in node.children: + self.Visit(child) + if isinstance(child, pytree.Leaf) and child.value == ':': + _AppendTokenSubtype(child, subtypes.SUBSCRIPT_COLON) + + def Visit_argument(self, node): # pylint: disable=invalid-name + # argument ::= + # test [comp_for] | test '=' test + self._ProcessArgLists(node) + #TODO add a subtype to each argument? + + def Visit_arglist(self, node): # pylint: disable=invalid-name + # arglist ::= + # (argument ',')* (argument [','] + # | '*' test (',' argument)* [',' '**' test] + # | '**' test) + self._ProcessArgLists(node) + _SetArgListSubtype( + node, subtypes.DEFAULT_OR_NAMED_ASSIGN, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) + + def Visit_tname(self, node): # pylint: disable=invalid-name + self._ProcessArgLists(node) + _SetArgListSubtype( + node, subtypes.DEFAULT_OR_NAMED_ASSIGN, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) + + def Visit_decorator(self, node): # pylint: disable=invalid-name + # decorator ::= + # '@' dotted_name [ '(' [arglist] ')' ] NEWLINE + for child in node.children: + if isinstance(child, pytree.Leaf) and child.value == '@': + _AppendTokenSubtype(child, subtype=subtypes.DECORATOR) + self.Visit(child) + + def Visit_funcdef(self, node): # pylint: disable=invalid-name + # funcdef ::= + # 'def' NAME parameters ['->' test] ':' suite + for child in node.children: + if child.type == grammar_token.NAME and child.value != 'def': + _AppendTokenSubtype(child, subtypes.FUNC_DEF) + break + for child in node.children: + self.Visit(child) + + def Visit_parameters(self, node): # pylint: disable=invalid-name + # parameters ::= '(' [typedargslist] ')' + self._ProcessArgLists(node) + if len(node.children) > 2: + _AppendFirstLeafTokenSubtype(node.children[1], subtypes.PARAMETER_START) + _AppendLastLeafTokenSubtype(node.children[-2], subtypes.PARAMETER_STOP) + + def Visit_typedargslist(self, node): # pylint: disable=invalid-name + # typedargslist ::= + # ((tfpdef ['=' test] ',')* + # ('*' [tname] (',' tname ['=' test])* [',' '**' tname] + # | '**' tname) + # | tfpdef ['=' test] (',' tfpdef ['=' test])* [',']) + self._ProcessArgLists(node) + _SetArgListSubtype( + node, subtypes.DEFAULT_OR_NAMED_ASSIGN, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) + tname = False + if not node.children: + return + + _AppendFirstLeafTokenSubtype(node.children[0], subtypes.PARAMETER_START) + _AppendLastLeafTokenSubtype(node.children[-1], subtypes.PARAMETER_STOP) + + tname = pytree_utils.NodeName(node.children[0]) == 'tname' + for i in range(1, len(node.children)): + prev_child = node.children[i - 1] + child = node.children[i] + if prev_child.type == grammar_token.COMMA: + _AppendFirstLeafTokenSubtype(child, subtypes.PARAMETER_START) + elif child.type == grammar_token.COMMA: + _AppendLastLeafTokenSubtype(prev_child, subtypes.PARAMETER_STOP) + + if pytree_utils.NodeName(child) == 'tname': + tname = True + _SetArgListSubtype( + child, subtypes.TYPED_NAME, subtypes.TYPED_NAME_ARG_LIST) + elif child.type == grammar_token.COMMA: + tname = False + elif child.type == grammar_token.EQUAL and tname: + _AppendTokenSubtype(child, subtype=subtypes.TYPED_NAME) + tname = False + + def Visit_varargslist(self, node): # pylint: disable=invalid-name + # varargslist ::= + # ((vfpdef ['=' test] ',')* + # ('*' [vname] (',' vname ['=' test])* [',' '**' vname] + # | '**' vname) + # | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) + self._ProcessArgLists(node) + for child in node.children: + self.Visit(child) + if isinstance(child, pytree.Leaf) and child.value == '=': + _AppendTokenSubtype(child, subtypes.VARARGS_LIST) + + def Visit_comp_for(self, node): # pylint: disable=invalid-name + # comp_for ::= 'for' exprlist 'in' testlist_safe [comp_iter] + _AppendSubtypeRec(node, subtypes.COMP_FOR) + # Mark the previous node as COMP_EXPR unless this is a nested comprehension + # as these will have the outer comprehension as their previous node. + attr = pytree_utils.GetNodeAnnotation( + node.parent, pytree_utils.Annotation.SUBTYPE) + if not attr or subtypes.COMP_FOR not in attr: + _AppendSubtypeRec(node.parent.children[0], subtypes.COMP_EXPR) + self.DefaultNodeVisit(node) + + def Visit_old_comp_for(self, node): # pylint: disable=invalid-name + # Python 3.7 + self.Visit_comp_for(node) + + def Visit_comp_if(self, node): # pylint: disable=invalid-name + # comp_if ::= 'if' old_test [comp_iter] + _AppendSubtypeRec(node, subtypes.COMP_IF) + self.DefaultNodeVisit(node) + + def Visit_old_comp_if(self, node): # pylint: disable=invalid-name + # Python 3.7 + self.Visit_comp_if(node) + + def _ProcessArgLists(self, node): + """Common method for processing argument lists.""" + for child in node.children: + self.Visit(child) + if isinstance(child, pytree.Leaf): + _AppendTokenSubtype( + child, + subtype=_ARGLIST_TOKEN_TO_SUBTYPE.get(child.value, subtypes.NONE)) -def _AppendLastLeafTokenSubtype( node, subtype ): - """Append the last leaf token's subtypes.""" - if isinstance( node, pytree.Leaf ): - _AppendTokenSubtype( node, subtype ) - return - _AppendLastLeafTokenSubtype( node.children[ -1 ], subtype ) +def _SetArgListSubtype(node, node_subtype, list_subtype): + """Set named assign subtype on elements in a arg list.""" + def HasSubtype(node): + """Return True if the arg list has a named assign subtype.""" + if isinstance(node, pytree.Leaf): + return node_subtype in pytree_utils.GetNodeAnnotation( + node, pytree_utils.Annotation.SUBTYPE, set()) -def _AppendSubtypeRec( node, subtype, force = True ): - """Append the leafs in the node to the given subtype.""" - if isinstance( node, pytree.Leaf ): - _AppendTokenSubtype( node, subtype ) - return for child in node.children: - _AppendSubtypeRec( child, subtype, force = force ) - - -def _InsertPseudoParentheses( node ): - """Insert pseudo parentheses so that dicts can be formatted correctly.""" - comment_node = None - if isinstance( node, pytree.Node ): - if node.children[ -1 ].type == grammar_token.COMMENT: - comment_node = node.children[ -1 ].clone() - node.children[ -1 ].remove() - - first = pytree_utils.FirstLeafNode( node ) - last = pytree_utils.LastLeafNode( node ) - - if first == last and first.type == grammar_token.COMMENT: - # A comment was inserted before the value, which is a pytree.Leaf. - # Encompass the dictionary's value into an ATOM node. - last = first.next_sibling - last_clone = last.clone() - new_node = pytree.Node( syms.atom, [ first.clone(), last_clone ] ) - for orig_leaf, clone_leaf in zip( last.leaves(), last_clone.leaves() ): - pytree_utils.CopyYapfAnnotations( orig_leaf, clone_leaf ) - if hasattr( orig_leaf, 'is_pseudo' ): - clone_leaf.is_pseudo = orig_leaf.is_pseudo - - node.replace( new_node ) - node = new_node - last.remove() - - first = pytree_utils.FirstLeafNode( node ) - last = pytree_utils.LastLeafNode( node ) - - lparen = pytree.Leaf( - grammar_token.LPAR, - u'(', - context = ( '', ( first.get_lineno(), first.column - 1 ) ) ) - last_lineno = last.get_lineno() - if last.type == grammar_token.STRING and '\n' in last.value: - last_lineno += last.value.count( '\n' ) - - if last.type == grammar_token.STRING and '\n' in last.value: - last_column = len( last.value.split( '\n' )[ -1 ] ) + 1 - else: - last_column = last.column + len( last.value ) + 1 - rparen = pytree.Leaf( - grammar_token.RPAR, u')', context = ( '', ( last_lineno, last_column ) ) ) - - lparen.is_pseudo = True - rparen.is_pseudo = True - - if isinstance( node, pytree.Node ): - node.insert_child( 0, lparen ) - node.append_child( rparen ) - if comment_node: - node.append_child( comment_node ) - _AppendFirstLeafTokenSubtype( node, subtypes.DICTIONARY_VALUE ) - else: - clone = node.clone() - for orig_leaf, clone_leaf in zip( node.leaves(), clone.leaves() ): - pytree_utils.CopyYapfAnnotations( orig_leaf, clone_leaf ) - new_node = pytree.Node( syms.atom, [ lparen, clone, rparen ] ) - node.replace( new_node ) - _AppendFirstLeafTokenSubtype( clone, subtypes.DICTIONARY_VALUE ) - - -def _IsAExprOperator( node ): - return isinstance( node, pytree.Leaf ) and node.value in { '+', '-' } - - -def _IsMExprOperator( node ): - return isinstance( node, - pytree.Leaf ) and node.value in { '*', '/', '%', '//', '@' } - - -def _IsSimpleExpression( node ): - """A node with only leafs as children.""" - return all( isinstance( child, pytree.Leaf ) for child in node.children ) + node_name = pytree_utils.NodeName(child) + if node_name not in {'atom', 'arglist', 'power'}: + if HasSubtype(child): + return True + + return False + + if not HasSubtype(node): + return + + for child in node.children: + node_name = pytree_utils.NodeName(child) + if node_name not in {'atom', 'COMMA'}: + _AppendFirstLeafTokenSubtype(child, list_subtype) + + +def _AppendTokenSubtype(node, subtype): + """Append the token's subtype only if it's not already set.""" + pytree_utils.AppendNodeAnnotation( + node, pytree_utils.Annotation.SUBTYPE, subtype) + + +def _AppendFirstLeafTokenSubtype(node, subtype): + """Append the first leaf token's subtypes.""" + if isinstance(node, pytree.Leaf): + _AppendTokenSubtype(node, subtype) + return + _AppendFirstLeafTokenSubtype(node.children[0], subtype) + + +def _AppendLastLeafTokenSubtype(node, subtype): + """Append the last leaf token's subtypes.""" + if isinstance(node, pytree.Leaf): + _AppendTokenSubtype(node, subtype) + return + _AppendLastLeafTokenSubtype(node.children[-1], subtype) + + +def _AppendSubtypeRec(node, subtype, force=True): + """Append the leafs in the node to the given subtype.""" + if isinstance(node, pytree.Leaf): + _AppendTokenSubtype(node, subtype) + return + for child in node.children: + _AppendSubtypeRec(child, subtype, force=force) + + +def _InsertPseudoParentheses(node): + """Insert pseudo parentheses so that dicts can be formatted correctly.""" + comment_node = None + if isinstance(node, pytree.Node): + if node.children[-1].type == grammar_token.COMMENT: + comment_node = node.children[-1].clone() + node.children[-1].remove() + + first = pytree_utils.FirstLeafNode(node) + last = pytree_utils.LastLeafNode(node) + + if first == last and first.type == grammar_token.COMMENT: + # A comment was inserted before the value, which is a pytree.Leaf. + # Encompass the dictionary's value into an ATOM node. + last = first.next_sibling + last_clone = last.clone() + new_node = pytree.Node(syms.atom, [first.clone(), last_clone]) + for orig_leaf, clone_leaf in zip(last.leaves(), last_clone.leaves()): + pytree_utils.CopyYapfAnnotations(orig_leaf, clone_leaf) + if hasattr(orig_leaf, 'is_pseudo'): + clone_leaf.is_pseudo = orig_leaf.is_pseudo + + node.replace(new_node) + node = new_node + last.remove() + + first = pytree_utils.FirstLeafNode(node) + last = pytree_utils.LastLeafNode(node) + + lparen = pytree.Leaf( + grammar_token.LPAR, + u'(', + context=('', (first.get_lineno(), first.column - 1))) + last_lineno = last.get_lineno() + if last.type == grammar_token.STRING and '\n' in last.value: + last_lineno += last.value.count('\n') + + if last.type == grammar_token.STRING and '\n' in last.value: + last_column = len(last.value.split('\n')[-1]) + 1 + else: + last_column = last.column + len(last.value) + 1 + rparen = pytree.Leaf( + grammar_token.RPAR, u')', context=('', (last_lineno, last_column))) + + lparen.is_pseudo = True + rparen.is_pseudo = True + + if isinstance(node, pytree.Node): + node.insert_child(0, lparen) + node.append_child(rparen) + if comment_node: + node.append_child(comment_node) + _AppendFirstLeafTokenSubtype(node, subtypes.DICTIONARY_VALUE) + else: + clone = node.clone() + for orig_leaf, clone_leaf in zip(node.leaves(), clone.leaves()): + pytree_utils.CopyYapfAnnotations(orig_leaf, clone_leaf) + new_node = pytree.Node(syms.atom, [lparen, clone, rparen]) + node.replace(new_node) + _AppendFirstLeafTokenSubtype(clone, subtypes.DICTIONARY_VALUE) + + +def _IsAExprOperator(node): + return isinstance(node, pytree.Leaf) and node.value in {'+', '-'} + + +def _IsMExprOperator(node): + return isinstance(node, + pytree.Leaf) and node.value in {'*', '/', '%', '//', '@'} + + +def _IsSimpleExpression(node): + """A node with only leafs as children.""" + return all(isinstance(child, pytree.Leaf) for child in node.children) diff --git a/yapf/third_party/yapf_diff/yapf_diff.py b/yapf/third_party/yapf_diff/yapf_diff.py index afd3ebc91..f069aedcb 100644 --- a/yapf/third_party/yapf_diff/yapf_diff.py +++ b/yapf/third_party/yapf_diff/yapf_diff.py @@ -33,114 +33,114 @@ import sys if sys.version_info.major >= 3: - from io import StringIO + from io import StringIO else: - from io import BytesIO as StringIO + from io import BytesIO as StringIO def main(): - parser = argparse.ArgumentParser( - description = __doc__, formatter_class = argparse.RawDescriptionHelpFormatter ) - parser.add_argument( - '-i', - '--in-place', - action = 'store_true', - default = False, - help = 'apply edits to files instead of displaying a diff' ) - parser.add_argument( - '-p', - '--prefix', - metavar = 'NUM', - default = 1, - help = 'strip the smallest prefix containing P slashes' ) - parser.add_argument( - '--regex', - metavar = 'PATTERN', - default = None, - help = 'custom pattern selecting file paths to reformat ' - '(case sensitive, overrides -iregex)' ) - parser.add_argument( - '--iregex', - metavar = 'PATTERN', - default = r'.*\.(py)', - help = 'custom pattern selecting file paths to reformat ' - '(case insensitive, overridden by -regex)' ) - parser.add_argument( - '-v', - '--verbose', - action = 'store_true', - help = 'be more verbose, ineffective without -i' ) - parser.add_argument( - '--style', - help = 'specify formatting style: either a style name (for ' - 'example "pep8" or "google"), or the name of a file with ' - 'style settings. The default is pep8 unless a ' - '.style.yapf or setup.cfg file located in one of the ' - 'parent directories of the source file (or current ' - 'directory for stdin)' ) - parser.add_argument( - '--binary', default = 'yapf', help = 'location of binary to use for yapf' ) - args = parser.parse_args() + parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument( + '-i', + '--in-place', + action='store_true', + default=False, + help='apply edits to files instead of displaying a diff') + parser.add_argument( + '-p', + '--prefix', + metavar='NUM', + default=1, + help='strip the smallest prefix containing P slashes') + parser.add_argument( + '--regex', + metavar='PATTERN', + default=None, + help='custom pattern selecting file paths to reformat ' + '(case sensitive, overrides -iregex)') + parser.add_argument( + '--iregex', + metavar='PATTERN', + default=r'.*\.(py)', + help='custom pattern selecting file paths to reformat ' + '(case insensitive, overridden by -regex)') + parser.add_argument( + '-v', + '--verbose', + action='store_true', + help='be more verbose, ineffective without -i') + parser.add_argument( + '--style', + help='specify formatting style: either a style name (for ' + 'example "pep8" or "google"), or the name of a file with ' + 'style settings. The default is pep8 unless a ' + '.style.yapf or setup.cfg file located in one of the ' + 'parent directories of the source file (or current ' + 'directory for stdin)') + parser.add_argument( + '--binary', default='yapf', help='location of binary to use for yapf') + args = parser.parse_args() - # Extract changed lines for each file. - filename = None - lines_by_file = {} - for line in sys.stdin: - match = re.search( r'^\+\+\+\ (.*?/){%s}(\S*)' % args.prefix, line ) - if match: - filename = match.group( 2 ) - if filename is None: - continue + # Extract changed lines for each file. + filename = None + lines_by_file = {} + for line in sys.stdin: + match = re.search(r'^\+\+\+\ (.*?/){%s}(\S*)' % args.prefix, line) + if match: + filename = match.group(2) + if filename is None: + continue - if args.regex is not None: - if not re.match( '^%s$' % args.regex, filename ): - continue - elif not re.match( '^%s$' % args.iregex, filename, re.IGNORECASE ): - continue + if args.regex is not None: + if not re.match('^%s$' % args.regex, filename): + continue + elif not re.match('^%s$' % args.iregex, filename, re.IGNORECASE): + continue - match = re.search( r'^@@.*\+(\d+)(,(\d+))?', line ) - if match: - start_line = int( match.group( 1 ) ) - line_count = 1 - if match.group( 3 ): - line_count = int( match.group( 3 ) ) - if line_count == 0: - continue - end_line = start_line + line_count - 1 - lines_by_file.setdefault( filename, [] ).extend( - [ '--lines', str( start_line ) + '-' + str( end_line ) ] ) + match = re.search(r'^@@.*\+(\d+)(,(\d+))?', line) + if match: + start_line = int(match.group(1)) + line_count = 1 + if match.group(3): + line_count = int(match.group(3)) + if line_count == 0: + continue + end_line = start_line + line_count - 1 + lines_by_file.setdefault(filename, []).extend( + ['--lines', str(start_line) + '-' + str(end_line)]) - # Reformat files containing changes in place. - for filename, lines in lines_by_file.items(): - if args.in_place and args.verbose: - print( 'Formatting {}'.format( filename ) ) - command = [ args.binary, filename ] - if args.in_place: - command.append( '-i' ) - command.extend( lines ) - if args.style: - command.extend( [ '--style', args.style ] ) - p = subprocess.Popen( - command, - stdout = subprocess.PIPE, - stderr = None, - stdin = subprocess.PIPE, - universal_newlines = True ) - stdout, stderr = p.communicate() - if p.returncode != 0: - sys.exit( p.returncode ) + # Reformat files containing changes in place. + for filename, lines in lines_by_file.items(): + if args.in_place and args.verbose: + print('Formatting {}'.format(filename)) + command = [args.binary, filename] + if args.in_place: + command.append('-i') + command.extend(lines) + if args.style: + command.extend(['--style', args.style]) + p = subprocess.Popen( + command, + stdout=subprocess.PIPE, + stderr=None, + stdin=subprocess.PIPE, + universal_newlines=True) + stdout, stderr = p.communicate() + if p.returncode != 0: + sys.exit(p.returncode) - if not args.in_place: - with open( filename ) as f: - code = f.readlines() - formatted_code = StringIO( stdout ).readlines() - diff = difflib.unified_diff( - code, formatted_code, filename, filename, '(before formatting)', - '(after formatting)' ) - diff_string = ''.join( diff ) - if len( diff_string ) > 0: - sys.stdout.write( diff_string ) + if not args.in_place: + with open(filename) as f: + code = f.readlines() + formatted_code = StringIO(stdout).readlines() + diff = difflib.unified_diff( + code, formatted_code, filename, filename, '(before formatting)', + '(after formatting)') + diff_string = ''.join(diff) + if len(diff_string) > 0: + sys.stdout.write(diff_string) if __name__ == '__main__': - main() + main() diff --git a/yapf/yapflib/errors.py b/yapf/yapflib/errors.py index 8864b49c6..cb8694d2c 100644 --- a/yapf/yapflib/errors.py +++ b/yapf/yapflib/errors.py @@ -16,8 +16,8 @@ from lib2to3.pgen2 import tokenize -def FormatErrorMsg( e ): - """Convert an exception into a standard format. +def FormatErrorMsg(e): + """Convert an exception into a standard format. The standard error message format is: @@ -29,19 +29,18 @@ def FormatErrorMsg( e ): Returns: A properly formatted error message string. """ - if isinstance( e, SyntaxError ): - return '{}:{}:{}: {}'.format( e.filename, e.lineno, e.offset, e.msg ) - if isinstance( e, tokenize.TokenError ): - return '{}:{}:{}: {}'.format( - e.filename, e.args[ 1 ][ 0 ], e.args[ 1 ][ 1 ], e.args[ 0 ] ) + if isinstance(e, SyntaxError): + return '{}:{}:{}: {}'.format(e.filename, e.lineno, e.offset, e.msg) + if isinstance(e, tokenize.TokenError): return '{}:{}:{}: {}'.format( - e.args[ 1 ][ 0 ], e.args[ 1 ][ 1 ], e.args[ 1 ][ 2 ], e.msg ) + e.filename, e.args[1][0], e.args[1][1], e.args[0]) + return '{}:{}:{}: {}'.format(e.args[1][0], e.args[1][1], e.args[1][2], e.msg) -class YapfError( Exception ): - """Parent class for user errors or input errors. +class YapfError(Exception): + """Parent class for user errors or input errors. Exceptions of this type are handled by the command line tool and result in clear error messages, as opposed to backtraces. """ - pass + pass diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 07ee951a2..9c071db3d 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -30,43 +30,44 @@ CRLF = '\r\n' -def _GetExcludePatternsFromYapfIgnore( filename ): - """Get a list of file patterns to ignore from .yapfignore.""" - ignore_patterns = [] - if os.path.isfile( filename ) and os.access( filename, os.R_OK ): - with open( filename, 'r' ) as fd: - for line in fd: - if line.strip() and not line.startswith( '#' ): - ignore_patterns.append( line.strip() ) +def _GetExcludePatternsFromYapfIgnore(filename): + """Get a list of file patterns to ignore from .yapfignore.""" + ignore_patterns = [] + if os.path.isfile(filename) and os.access(filename, os.R_OK): + with open(filename, 'r') as fd: + for line in fd: + if line.strip() and not line.startswith('#'): + ignore_patterns.append(line.strip()) - if any( e.startswith( './' ) for e in ignore_patterns ): - raise errors.YapfError( 'path in .yapfignore should not start with ./' ) + if any(e.startswith('./') for e in ignore_patterns): + raise errors.YapfError('path in .yapfignore should not start with ./') - return ignore_patterns + return ignore_patterns -def _GetExcludePatternsFromPyprojectToml( filename ): - """Get a list of file patterns to ignore from pyproject.toml.""" - ignore_patterns = [] - try: - import toml - except ImportError: - raise errors.YapfError( - "toml package is needed for using pyproject.toml as a " - "configuration file" ) +def _GetExcludePatternsFromPyprojectToml(filename): + """Get a list of file patterns to ignore from pyproject.toml.""" + ignore_patterns = [] + try: + import toml + except ImportError: + raise errors.YapfError( + "toml package is needed for using pyproject.toml as a " + "configuration file") - if os.path.isfile( filename ) and os.access( filename, os.R_OK ): - pyproject_toml = toml.load( filename ) - ignore_patterns = pyproject_toml.get( 'tool', {} ).get( 'yapfignore', {} ).get( - 'ignore_patterns', [] ) - if any( e.startswith( './' ) for e in ignore_patterns ): - raise errors.YapfError( 'path in pyproject.toml should not start with ./' ) + if os.path.isfile(filename) and os.access(filename, os.R_OK): + pyproject_toml = toml.load(filename) + ignore_patterns = pyproject_toml.get('tool', + {}).get('yapfignore', + {}).get('ignore_patterns', []) + if any(e.startswith('./') for e in ignore_patterns): + raise errors.YapfError('path in pyproject.toml should not start with ./') - return ignore_patterns + return ignore_patterns -def GetExcludePatternsForDir( dirname ): - """Return patterns of files to exclude from ignorefile in a given directory. +def GetExcludePatternsForDir(dirname): + """Return patterns of files to exclude from ignorefile in a given directory. Looks for .yapfignore in the directory dirname. @@ -77,20 +78,20 @@ def GetExcludePatternsForDir( dirname ): A List of file patterns to exclude if ignore file is found, otherwise empty List. """ - ignore_patterns = [] + ignore_patterns = [] - yapfignore_file = os.path.join( dirname, '.yapfignore' ) - if os.path.exists( yapfignore_file ): - ignore_patterns += _GetExcludePatternsFromYapfIgnore( yapfignore_file ) + yapfignore_file = os.path.join(dirname, '.yapfignore') + if os.path.exists(yapfignore_file): + ignore_patterns += _GetExcludePatternsFromYapfIgnore(yapfignore_file) - pyproject_toml_file = os.path.join( dirname, 'pyproject.toml' ) - if os.path.exists( pyproject_toml_file ): - ignore_patterns += _GetExcludePatternsFromPyprojectToml( pyproject_toml_file ) - return ignore_patterns + pyproject_toml_file = os.path.join(dirname, 'pyproject.toml') + if os.path.exists(pyproject_toml_file): + ignore_patterns += _GetExcludePatternsFromPyprojectToml(pyproject_toml_file) + return ignore_patterns -def GetDefaultStyleForDir( dirname, default_style = style.DEFAULT_STYLE ): - """Return default style name for a given directory. +def GetDefaultStyleForDir(dirname, default_style=style.DEFAULT_STYLE): + """Return default style name for a given directory. Looks for .style.yapf or setup.cfg or pyproject.toml in the parent directories. @@ -103,65 +104,66 @@ def GetDefaultStyleForDir( dirname, default_style = style.DEFAULT_STYLE ): Returns: The filename if found, otherwise return the default style. """ - dirname = os.path.abspath( dirname ) - while True: - # See if we have a .style.yapf file. - style_file = os.path.join( dirname, style.LOCAL_STYLE ) - if os.path.exists( style_file ): - return style_file - - # See if we have a setup.cfg file with a '[yapf]' section. - config_file = os.path.join( dirname, style.SETUP_CONFIG ) - try: - fd = open( config_file ) - except IOError: - pass # It's okay if it's not there. - else: - with fd: - config = py3compat.ConfigParser() - config.read_file( fd ) - if config.has_section( 'yapf' ): - return config_file - - # See if we have a pyproject.toml file with a '[tool.yapf]' section. - config_file = os.path.join( dirname, style.PYPROJECT_TOML ) + dirname = os.path.abspath(dirname) + while True: + # See if we have a .style.yapf file. + style_file = os.path.join(dirname, style.LOCAL_STYLE) + if os.path.exists(style_file): + return style_file + + # See if we have a setup.cfg file with a '[yapf]' section. + config_file = os.path.join(dirname, style.SETUP_CONFIG) + try: + fd = open(config_file) + except IOError: + pass # It's okay if it's not there. + else: + with fd: + config = py3compat.ConfigParser() + config.read_file(fd) + if config.has_section('yapf'): + return config_file + + # See if we have a pyproject.toml file with a '[tool.yapf]' section. + config_file = os.path.join(dirname, style.PYPROJECT_TOML) + try: + fd = open(config_file) + except IOError: + pass # It's okay if it's not there. + else: + with fd: try: - fd = open( config_file ) - except IOError: - pass # It's okay if it's not there. - else: - with fd: - try: - import toml - except ImportError: - raise errors.YapfError( - "toml package is needed for using pyproject.toml as a " - "configuration file" ) + import toml + except ImportError: + raise errors.YapfError( + "toml package is needed for using pyproject.toml as a " + "configuration file") - pyproject_toml = toml.load( config_file ) - style_dict = pyproject_toml.get( 'tool', {} ).get( 'yapf', None ) - if style_dict is not None: - return config_file + pyproject_toml = toml.load(config_file) + style_dict = pyproject_toml.get('tool', {}).get('yapf', None) + if style_dict is not None: + return config_file - if ( not dirname or not os.path.basename( dirname ) or - dirname == os.path.abspath( os.path.sep ) ): - break - dirname = os.path.dirname( dirname ) + if (not dirname or not os.path.basename(dirname) or + dirname == os.path.abspath(os.path.sep)): + break + dirname = os.path.dirname(dirname) - global_file = os.path.expanduser( style.GLOBAL_STYLE ) - if os.path.exists( global_file ): - return global_file + global_file = os.path.expanduser(style.GLOBAL_STYLE) + if os.path.exists(global_file): + return global_file - return default_style + return default_style -def GetCommandLineFiles( command_line_file_list, recursive, exclude ): - """Return the list of files specified on the command line.""" - return _FindPythonFiles( command_line_file_list, recursive, exclude ) +def GetCommandLineFiles(command_line_file_list, recursive, exclude): + """Return the list of files specified on the command line.""" + return _FindPythonFiles(command_line_file_list, recursive, exclude) -def WriteReformattedCode( filename, reformatted_code, encoding = '', in_place = False ): - """Emit the reformatted code. +def WriteReformattedCode( + filename, reformatted_code, encoding='', in_place=False): + """Emit the reformatted code. Write the reformatted code into the file, if in_place is True. Otherwise, write to stdout. @@ -172,117 +174,117 @@ def WriteReformattedCode( filename, reformatted_code, encoding = '', in_place = encoding: (unicode) The encoding of the file. in_place: (bool) If True, then write the reformatted code to the file. """ - if in_place: - with py3compat.open_with_encoding( filename, mode = 'w', encoding = encoding, - newline = '' ) as fd: - fd.write( reformatted_code ) - else: - py3compat.EncodeAndWriteToStdout( reformatted_code ) - - -def LineEnding( lines ): - """Retrieve the line ending of the original source.""" - endings = { CRLF: 0, CR: 0, LF: 0} - for line in lines: - if line.endswith( CRLF ): - endings[ CRLF ] += 1 - elif line.endswith( CR ): - endings[ CR ] += 1 - elif line.endswith( LF ): - endings[ LF ] += 1 - return ( sorted( endings, key = endings.get, reverse = True ) or [ LF ] )[ 0 ] - - -def _FindPythonFiles( filenames, recursive, exclude ): - """Find all Python files.""" - if exclude and any( e.startswith( './' ) for e in exclude ): - raise errors.YapfError( "path in '--exclude' should not start with ./" ) - exclude = exclude and [ e.rstrip( "/" + os.path.sep ) for e in exclude ] - - python_files = [] - for filename in filenames: - if filename != '.' and exclude and IsIgnored( filename, exclude ): + if in_place: + with py3compat.open_with_encoding(filename, mode='w', encoding=encoding, + newline='') as fd: + fd.write(reformatted_code) + else: + py3compat.EncodeAndWriteToStdout(reformatted_code) + + +def LineEnding(lines): + """Retrieve the line ending of the original source.""" + endings = {CRLF: 0, CR: 0, LF: 0} + for line in lines: + if line.endswith(CRLF): + endings[CRLF] += 1 + elif line.endswith(CR): + endings[CR] += 1 + elif line.endswith(LF): + endings[LF] += 1 + return (sorted(endings, key=endings.get, reverse=True) or [LF])[0] + + +def _FindPythonFiles(filenames, recursive, exclude): + """Find all Python files.""" + if exclude and any(e.startswith('./') for e in exclude): + raise errors.YapfError("path in '--exclude' should not start with ./") + exclude = exclude and [e.rstrip("/" + os.path.sep) for e in exclude] + + python_files = [] + for filename in filenames: + if filename != '.' and exclude and IsIgnored(filename, exclude): + continue + if os.path.isdir(filename): + if not recursive: + raise errors.YapfError( + "directory specified without '--recursive' flag: %s" % filename) + + # TODO(morbo): Look into a version of os.walk that can handle recursion. + excluded_dirs = [] + for dirpath, dirnames, filelist in os.walk(filename): + if dirpath != '.' and exclude and IsIgnored(dirpath, exclude): + excluded_dirs.append(dirpath) + continue + elif any(dirpath.startswith(e) for e in excluded_dirs): + continue + for f in filelist: + filepath = os.path.join(dirpath, f) + if exclude and IsIgnored(filepath, exclude): continue - if os.path.isdir( filename ): - if not recursive: - raise errors.YapfError( - "directory specified without '--recursive' flag: %s" % filename ) - - # TODO(morbo): Look into a version of os.walk that can handle recursion. - excluded_dirs = [] - for dirpath, dirnames, filelist in os.walk( filename ): - if dirpath != '.' and exclude and IsIgnored( dirpath, exclude ): - excluded_dirs.append( dirpath ) - continue - elif any( dirpath.startswith( e ) for e in excluded_dirs ): - continue - for f in filelist: - filepath = os.path.join( dirpath, f ) - if exclude and IsIgnored( filepath, exclude ): - continue - if IsPythonFile( filepath ): - python_files.append( filepath ) - # To prevent it from scanning the contents excluded folders, os.walk() - # lets you amend its list of child dirs `dirnames`. These edits must be - # made in-place instead of creating a modified copy of `dirnames`. - # list.remove() is slow and list.pop() is a headache. Instead clear - # `dirnames` then repopulate it. - dirnames_ = [ dirnames.pop( 0 ) for i in range( len( dirnames ) ) ] - for dirname in dirnames_: - dir_ = os.path.join( dirpath, dirname ) - if IsIgnored( dir_, exclude ): - excluded_dirs.append( dir_ ) - else: - dirnames.append( dirname ) - - elif os.path.isfile( filename ): - python_files.append( filename ) - - return python_files - - -def IsIgnored( path, exclude ): - """Return True if filename matches any patterns in exclude.""" - if exclude is None: - return False - path = path.lstrip( os.path.sep ) - while path.startswith( '.' + os.path.sep ): - path = path[ 2 : ] - return any( fnmatch.fnmatch( path, e.rstrip( os.path.sep ) ) for e in exclude ) - - -def IsPythonFile( filename ): - """Return True if filename is a Python file.""" - if os.path.splitext( filename )[ 1 ] == '.py': - return True - - try: - with open( filename, 'rb' ) as fd: - encoding = py3compat.detect_encoding( fd.readline )[ 0 ] - - # Check for correctness of encoding. - with py3compat.open_with_encoding( filename, mode = 'r', - encoding = encoding ) as fd: - fd.read() - except UnicodeDecodeError: - encoding = 'latin-1' - except ( IOError, SyntaxError ): - # If we fail to detect encoding (or the encoding cookie is incorrect - which - # will make detect_encoding raise SyntaxError), assume it's not a Python - # file. - return False - - try: - with py3compat.open_with_encoding( filename, mode = 'r', - encoding = encoding ) as fd: - first_line = fd.readline( 256 ) - except IOError: - return False - - return re.match( r'^#!.*\bpython[23]?\b', first_line ) - - -def FileEncoding( filename ): - """Return the file's encoding.""" - with open( filename, 'rb' ) as fd: - return py3compat.detect_encoding( fd.readline )[ 0 ] + if IsPythonFile(filepath): + python_files.append(filepath) + # To prevent it from scanning the contents excluded folders, os.walk() + # lets you amend its list of child dirs `dirnames`. These edits must be + # made in-place instead of creating a modified copy of `dirnames`. + # list.remove() is slow and list.pop() is a headache. Instead clear + # `dirnames` then repopulate it. + dirnames_ = [dirnames.pop(0) for i in range(len(dirnames))] + for dirname in dirnames_: + dir_ = os.path.join(dirpath, dirname) + if IsIgnored(dir_, exclude): + excluded_dirs.append(dir_) + else: + dirnames.append(dirname) + + elif os.path.isfile(filename): + python_files.append(filename) + + return python_files + + +def IsIgnored(path, exclude): + """Return True if filename matches any patterns in exclude.""" + if exclude is None: + return False + path = path.lstrip(os.path.sep) + while path.startswith('.' + os.path.sep): + path = path[2:] + return any(fnmatch.fnmatch(path, e.rstrip(os.path.sep)) for e in exclude) + + +def IsPythonFile(filename): + """Return True if filename is a Python file.""" + if os.path.splitext(filename)[1] == '.py': + return True + + try: + with open(filename, 'rb') as fd: + encoding = py3compat.detect_encoding(fd.readline)[0] + + # Check for correctness of encoding. + with py3compat.open_with_encoding(filename, mode='r', + encoding=encoding) as fd: + fd.read() + except UnicodeDecodeError: + encoding = 'latin-1' + except (IOError, SyntaxError): + # If we fail to detect encoding (or the encoding cookie is incorrect - which + # will make detect_encoding raise SyntaxError), assume it's not a Python + # file. + return False + + try: + with py3compat.open_with_encoding(filename, mode='r', + encoding=encoding) as fd: + first_line = fd.readline(256) + except IOError: + return False + + return re.match(r'^#!.*\bpython[23]?\b', first_line) + + +def FileEncoding(filename): + """Return the file's encoding.""" + with open(filename, 'rb') as fd: + return py3compat.detect_encoding(fd.readline)[0] diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index bd08aa9ba..40bf5e25b 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -33,8 +33,8 @@ from yapf.yapflib import subtypes -class FormatDecisionState( object ): - """The current state when indenting a logical line. +class FormatDecisionState(object): + """The current state when indenting a logical line. The FormatDecisionState object is meant to be copied instead of referenced. @@ -56,8 +56,8 @@ class FormatDecisionState( object ): column_limit: The column limit specified by the style. """ - def __init__( self, line, first_indent ): - """Initializer. + def __init__(self, line, first_indent): + """Initializer. Initializes to the state after placing the first token from 'line' at 'first_indent'. @@ -66,64 +66,65 @@ def __init__( self, line, first_indent ): line: (LogicalLine) The logical line we're currently processing. first_indent: (int) The indent of the first token. """ - self.next_token = line.first - self.column = first_indent - self.line = line - self.paren_level = 0 - self.lowest_level_on_line = 0 - self.ignore_stack_for_comparison = False - self.stack = [ _ParenState( first_indent, first_indent ) ] - self.comp_stack = [] - self.param_list_stack = [] - self.first_indent = first_indent - self.column_limit = style.Get( 'COLUMN_LIMIT' ) - - def Clone( self ): - """Clones a FormatDecisionState object.""" - new = FormatDecisionState( self.line, self.first_indent ) - new.next_token = self.next_token - new.column = self.column - new.line = self.line - new.paren_level = self.paren_level - new.line.depth = self.line.depth - new.lowest_level_on_line = self.lowest_level_on_line - new.ignore_stack_for_comparison = self.ignore_stack_for_comparison - new.first_indent = self.first_indent - new.stack = [ state.Clone() for state in self.stack ] - new.comp_stack = [ state.Clone() for state in self.comp_stack ] - new.param_list_stack = [ state.Clone() for state in self.param_list_stack ] - return new - - def __eq__( self, other ): - # Note: 'first_indent' is implicit in the stack. Also, we ignore 'previous', - # because it shouldn't have a bearing on this comparison. (I.e., it will - # report equal if 'next_token' does.) - return ( - self.next_token == other.next_token and self.column == other.column and - self.paren_level == other.paren_level and - self.line.depth == other.line.depth and - self.lowest_level_on_line == other.lowest_level_on_line and ( - self.ignore_stack_for_comparison or other.ignore_stack_for_comparison or - self.stack == other.stack and self.comp_stack == other.comp_stack and - self.param_list_stack == other.param_list_stack ) ) - - def __ne__( self, other ): - return not self == other - - def __hash__( self ): - return hash( - ( - self.next_token, self.column, self.paren_level, self.line.depth, - self.lowest_level_on_line ) ) - - def __repr__( self ): - return ( - 'column::%d, next_token::%s, paren_level::%d, stack::[\n\t%s' % ( - self.column, repr( self.next_token ), self.paren_level, - '\n\t'.join( repr( s ) for s in self.stack ) + ']' ) ) - - def CanSplit( self, must_split ): - """Determine if we can split before the next token. + self.next_token = line.first + self.column = first_indent + self.line = line + self.paren_level = 0 + self.lowest_level_on_line = 0 + self.ignore_stack_for_comparison = False + self.stack = [_ParenState(first_indent, first_indent)] + self.comp_stack = [] + self.param_list_stack = [] + self.first_indent = first_indent + self.column_limit = style.Get('COLUMN_LIMIT') + + def Clone(self): + """Clones a FormatDecisionState object.""" + new = FormatDecisionState(self.line, self.first_indent) + new.next_token = self.next_token + new.column = self.column + new.line = self.line + new.paren_level = self.paren_level + new.line.depth = self.line.depth + new.lowest_level_on_line = self.lowest_level_on_line + new.ignore_stack_for_comparison = self.ignore_stack_for_comparison + new.first_indent = self.first_indent + new.stack = [state.Clone() for state in self.stack] + new.comp_stack = [state.Clone() for state in self.comp_stack] + new.param_list_stack = [state.Clone() for state in self.param_list_stack] + return new + + def __eq__(self, other): + # Note: 'first_indent' is implicit in the stack. Also, we ignore 'previous', + # because it shouldn't have a bearing on this comparison. (I.e., it will + # report equal if 'next_token' does.) + return ( + self.next_token == other.next_token and self.column == other.column and + self.paren_level == other.paren_level and + self.line.depth == other.line.depth and + self.lowest_level_on_line == other.lowest_level_on_line and ( + self.ignore_stack_for_comparison or + other.ignore_stack_for_comparison or self.stack == other.stack and + self.comp_stack == other.comp_stack and + self.param_list_stack == other.param_list_stack)) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash( + ( + self.next_token, self.column, self.paren_level, self.line.depth, + self.lowest_level_on_line)) + + def __repr__(self): + return ( + 'column::%d, next_token::%s, paren_level::%d, stack::[\n\t%s' % ( + self.column, repr(self.next_token), self.paren_level, + '\n\t'.join(repr(s) for s in self.stack) + ']')) + + def CanSplit(self, must_split): + """Determine if we can split before the next token. Arguments: must_split: (bool) A newline was required before this token. @@ -131,443 +132,436 @@ def CanSplit( self, must_split ): Returns: True if the line can be split before the next token. """ - current = self.next_token - previous = current.previous_token + current = self.next_token + previous = current.previous_token + + if current.is_pseudo: + return False + + if (not must_split and subtypes.DICTIONARY_KEY_PART in current.subtypes and + subtypes.DICTIONARY_KEY not in current.subtypes and + not style.Get('ALLOW_MULTILINE_DICTIONARY_KEYS')): + # In some situations, a dictionary may be multiline, but pylint doesn't + # like it. So don't allow it unless forced to. + return False + + if (not must_split and subtypes.DICTIONARY_VALUE in current.subtypes and + not style.Get('ALLOW_SPLIT_BEFORE_DICT_VALUE')): + return False + + if previous and previous.value == '(' and current.value == ')': + # Don't split an empty function call list if we aren't splitting before + # dict values. + token = previous.previous_token + while token: + prev = token.previous_token + if not prev or prev.name not in {'NAME', 'DOT'}: + break + token = token.previous_token + if token and subtypes.DICTIONARY_VALUE in token.subtypes: + if not style.Get('ALLOW_SPLIT_BEFORE_DICT_VALUE'): + return False + + if previous and previous.value == '.' and current.value == '.': + return False + + return current.can_break_before + + def MustSplit(self): + """Returns True if the line must split before the next token.""" + current = self.next_token + previous = current.previous_token + + if current.is_pseudo: + return False + + if current.must_break_before: + return True + + if not previous: + return False + + if style.Get('SPLIT_ALL_COMMA_SEPARATED_VALUES') and previous.value == ',': + return True + + if (style.Get('SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES') and + previous.value == ','): + # Avoid breaking in a container that fits in the current line if possible + opening = _GetOpeningBracket(current) + + # Can't find opening bracket, behave the same way as + # SPLIT_ALL_COMMA_SEPARATED_VALUES. + if not opening: + return True + + if current.is_comment: + # Don't require splitting before a comment, since it may be related to + # the current line. + return False - if current.is_pseudo: - return False + # Allow the fallthrough code to handle the closing bracket. + if current != opening.matching_bracket: + # If the container doesn't fit in the current line, must split + return not self._ContainerFitsOnStartLine(opening) + + if (self.stack[-1].split_before_closing_bracket and + (current.value in '}]' and style.Get('SPLIT_BEFORE_CLOSING_BRACKET') or + current.value in '}])' and style.Get('INDENT_CLOSING_BRACKETS'))): + # Split before the closing bracket if we can. + if subtypes.SUBSCRIPT_BRACKET not in current.subtypes: + return current.node_split_penalty != split_penalty.UNBREAKABLE + + if (current.value == ')' and previous.value == ',' and + not _IsSingleElementTuple(current.matching_bracket)): + return True + + # Prevent splitting before the first argument in compound statements + # with the exception of function declarations. + if (style.Get('SPLIT_BEFORE_FIRST_ARGUMENT') and + _IsCompoundStatement(self.line.first) and + not _IsFunctionDef(self.line.first)): + return False + + ########################################################################### + # List Splitting + if (style.Get('DEDENT_CLOSING_BRACKETS') or + style.Get('INDENT_CLOSING_BRACKETS') or + style.Get('SPLIT_BEFORE_FIRST_ARGUMENT')): + bracket = current if current.ClosesScope() else previous + if subtypes.SUBSCRIPT_BRACKET not in bracket.subtypes: + if bracket.OpensScope(): + if style.Get('COALESCE_BRACKETS'): + if current.OpensScope(): + # Prefer to keep all opening brackets together. + return False + + if (not _IsLastScopeInLine(bracket) or + logical_line.IsSurroundedByBrackets(bracket)): + last_token = bracket.matching_bracket + else: + last_token = _LastTokenInLine(bracket.matching_bracket) + + if not self._FitsOnLine(bracket, last_token): + # Split before the first element if the whole list can't fit on a + # single line. + self.stack[-1].split_before_closing_bracket = True + return True - if ( not must_split and subtypes.DICTIONARY_KEY_PART in current.subtypes and - subtypes.DICTIONARY_KEY not in current.subtypes and - not style.Get( 'ALLOW_MULTILINE_DICTIONARY_KEYS' ) ): - # In some situations, a dictionary may be multiline, but pylint doesn't - # like it. So don't allow it unless forced to. + elif (style.Get('DEDENT_CLOSING_BRACKETS') or + style.Get('INDENT_CLOSING_BRACKETS')) and current.ClosesScope(): + # Split before and dedent the closing bracket. + return self.stack[-1].split_before_closing_bracket + + if (style.Get('SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN') and + current.is_name): + # An expression that's surrounded by parens gets split after the opening + # parenthesis. + def SurroundedByParens(token): + """Check if it's an expression surrounded by parentheses.""" + while token: + if token.value == ',': return False + if token.value == ')': + return not token.next_token + if token.OpensScope(): + token = token.matching_bracket.next_token + else: + token = token.next_token + return False - if ( not must_split and subtypes.DICTIONARY_VALUE in current.subtypes and - not style.Get( 'ALLOW_SPLIT_BEFORE_DICT_VALUE' ) ): + if (previous.value == '(' and not previous.is_pseudo and + not logical_line.IsSurroundedByBrackets(previous)): + pptoken = previous.previous_token + if (pptoken and not pptoken.is_name and not pptoken.is_keyword and + SurroundedByParens(current)): + return True + + if (current.is_name or current.is_string) and previous.value == ',': + # If the list has function calls in it and the full list itself cannot + # fit on the line, then we want to split. Otherwise, we'll get something + # like this: + # + # X = [ + # Bar(xxx='some string', + # yyy='another long string', + # zzz='a third long string'), Bar( + # xxx='some string', + # yyy='another long string', + # zzz='a third long string') + # ] + # + # or when a string formatting syntax. + func_call_or_string_format = False + tok = current.next_token + if current.is_name: + while tok and (tok.is_name or tok.value == '.'): + tok = tok.next_token + func_call_or_string_format = tok and tok.value == '(' + elif current.is_string: + while tok and tok.is_string: + tok = tok.next_token + func_call_or_string_format = tok and tok.value == '%' + if func_call_or_string_format: + open_bracket = logical_line.IsSurroundedByBrackets(current) + if open_bracket: + if open_bracket.value in '[{': + if not self._FitsOnLine(open_bracket, + open_bracket.matching_bracket): + return True + elif tok.value == '(': + if not self._FitsOnLine(current, tok.matching_bracket): + return True + + if (current.OpensScope() and previous.value == ',' and + subtypes.DICTIONARY_KEY not in current.next_token.subtypes): + # If we have a list of tuples, then we can get a similar look as above. If + # the full list cannot fit on the line, then we want a split. + open_bracket = logical_line.IsSurroundedByBrackets(current) + if (open_bracket and open_bracket.value in '[{' and + subtypes.SUBSCRIPT_BRACKET not in open_bracket.subtypes): + if not self._FitsOnLine(current, current.matching_bracket): + return True + + ########################################################################### + # Dict/Set Splitting + if (style.Get('EACH_DICT_ENTRY_ON_SEPARATE_LINE') and + subtypes.DICTIONARY_KEY in current.subtypes and not current.is_comment): + # Place each dictionary entry onto its own line. + if previous.value == '{' and previous.previous_token: + opening = _GetOpeningBracket(previous.previous_token) + if (opening and opening.value == '(' and opening.previous_token and + opening.previous_token.is_name): + # This is a dictionary that's an argument to a function. + if (self._FitsOnLine(previous, previous.matching_bracket) and + previous.matching_bracket.next_token and + (not opening.matching_bracket.next_token or + opening.matching_bracket.next_token.value != '.') and + _ScopeHasNoCommas(previous)): + # Don't split before the key if: + # - The dictionary fits on a line, and + # - The function call isn't part of a builder-style call and + # - The dictionary has one entry and no trailing comma return False - - if previous and previous.value == '(' and current.value == ')': - # Don't split an empty function call list if we aren't splitting before - # dict values. - token = previous.previous_token - while token: - prev = token.previous_token - if not prev or prev.name not in { 'NAME', 'DOT' }: - break - token = token.previous_token - if token and subtypes.DICTIONARY_VALUE in token.subtypes: - if not style.Get( 'ALLOW_SPLIT_BEFORE_DICT_VALUE' ): - return False - - if previous and previous.value == '.' and current.value == '.': + return True + + if (style.Get('SPLIT_BEFORE_DICT_SET_GENERATOR') and + subtypes.DICT_SET_GENERATOR in current.subtypes): + # Split before a dict/set generator. + return True + + if (subtypes.DICTIONARY_VALUE in current.subtypes or + (previous.is_pseudo and previous.value == '(' and + not current.is_comment)): + # Split before the dictionary value if we can't fit every dictionary + # entry on its own line. + if not current.OpensScope(): + opening = _GetOpeningBracket(current) + if not self._EachDictEntryFitsOnOneLine(opening): + return style.Get('ALLOW_SPLIT_BEFORE_DICT_VALUE') + + if previous.value == '{': + # Split if the dict/set cannot fit on one line and ends in a comma. + closing = previous.matching_bracket + if (not self._FitsOnLine(previous, closing) and + closing.previous_token.value == ','): + self.stack[-1].split_before_closing_bracket = True + return True + + ########################################################################### + # Argument List Splitting + if (style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and not current.is_comment and + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in current.subtypes): + if (previous.value not in {'=', ':', '*', '**'} and + current.value not in ':=,)' and not _IsFunctionDefinition(previous)): + # If we're going to split the lines because of named arguments, then we + # want to split after the opening bracket as well. But not when this is + # part of a function definition. + if previous.value == '(': + # Make sure we don't split after the opening bracket if the + # continuation indent is greater than the opening bracket: + # + # a( + # b=1, + # c=2) + if (self._FitsOnLine(previous, previous.matching_bracket) and + logical_line.IsSurroundedByBrackets(previous)): + # An argument to a function is a function call with named + # assigns. return False - return current.can_break_before - - def MustSplit( self ): - """Returns True if the line must split before the next token.""" - current = self.next_token - previous = current.previous_token - - if current.is_pseudo: + # Don't split if not required + if (not style.Get('SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN') and + not style.Get('SPLIT_BEFORE_FIRST_ARGUMENT')): return False - if current.must_break_before: - return True - - if not previous: - return False - - if style.Get( 'SPLIT_ALL_COMMA_SEPARATED_VALUES' ) and previous.value == ',': - return True + column = self.column - self.stack[-1].last_space + return column > style.Get('CONTINUATION_INDENT_WIDTH') - if ( style.Get( 'SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES' ) and - previous.value == ',' ): - # Avoid breaking in a container that fits in the current line if possible - opening = _GetOpeningBracket( current ) - - # Can't find opening bracket, behave the same way as - # SPLIT_ALL_COMMA_SEPARATED_VALUES. - if not opening: - return True - - if current.is_comment: - # Don't require splitting before a comment, since it may be related to - # the current line. - return False - - # Allow the fallthrough code to handle the closing bracket. - if current != opening.matching_bracket: - # If the container doesn't fit in the current line, must split - return not self._ContainerFitsOnStartLine( opening ) - - if ( self.stack[ -1 ].split_before_closing_bracket and - ( current.value in '}]' and style.Get( 'SPLIT_BEFORE_CLOSING_BRACKET' ) or - current.value in '}])' and style.Get( 'INDENT_CLOSING_BRACKETS' ) ) ): - # Split before the closing bracket if we can. - if subtypes.SUBSCRIPT_BRACKET not in current.subtypes: - return current.node_split_penalty != split_penalty.UNBREAKABLE - - if ( current.value == ')' and previous.value == ',' and - not _IsSingleElementTuple( current.matching_bracket ) ): - return True + opening = _GetOpeningBracket(current) + if opening: + return not self._ContainerFitsOnStartLine(opening) - # Prevent splitting before the first argument in compound statements - # with the exception of function declarations. - if ( style.Get( 'SPLIT_BEFORE_FIRST_ARGUMENT' ) and - _IsCompoundStatement( self.line.first ) and - not _IsFunctionDef( self.line.first ) ): - return False + if (current.value not in '{)' and previous.value == '(' and + self._ArgumentListHasDictionaryEntry(current)): + return True - ########################################################################### - # List Splitting - if ( style.Get( 'DEDENT_CLOSING_BRACKETS' ) or - style.Get( 'INDENT_CLOSING_BRACKETS' ) or - style.Get( 'SPLIT_BEFORE_FIRST_ARGUMENT' ) ): - bracket = current if current.ClosesScope() else previous - if subtypes.SUBSCRIPT_BRACKET not in bracket.subtypes: - if bracket.OpensScope(): - if style.Get( 'COALESCE_BRACKETS' ): - if current.OpensScope(): - # Prefer to keep all opening brackets together. - return False - - if ( not _IsLastScopeInLine( bracket ) or - logical_line.IsSurroundedByBrackets( bracket ) ): - last_token = bracket.matching_bracket - else: - last_token = _LastTokenInLine( bracket.matching_bracket ) - - if not self._FitsOnLine( bracket, last_token ): - # Split before the first element if the whole list can't fit on a - # single line. - self.stack[ -1 ].split_before_closing_bracket = True - return True - - elif ( style.Get( 'DEDENT_CLOSING_BRACKETS' ) or - style.Get( 'INDENT_CLOSING_BRACKETS' ) - ) and current.ClosesScope(): - # Split before and dedent the closing bracket. - return self.stack[ -1 ].split_before_closing_bracket - - if ( style.Get( 'SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN' ) and - current.is_name ): - # An expression that's surrounded by parens gets split after the opening - # parenthesis. - def SurroundedByParens( token ): - """Check if it's an expression surrounded by parentheses.""" - while token: - if token.value == ',': - return False - if token.value == ')': - return not token.next_token - if token.OpensScope(): - token = token.matching_bracket.next_token - else: - token = token.next_token - return False - - if ( previous.value == '(' and not previous.is_pseudo and - not logical_line.IsSurroundedByBrackets( previous ) ): - pptoken = previous.previous_token - if ( pptoken and not pptoken.is_name and not pptoken.is_keyword and - SurroundedByParens( current ) ): - return True - - if ( current.is_name or current.is_string ) and previous.value == ',': - # If the list has function calls in it and the full list itself cannot - # fit on the line, then we want to split. Otherwise, we'll get something - # like this: - # - # X = [ - # Bar(xxx='some string', - # yyy='another long string', - # zzz='a third long string'), Bar( - # xxx='some string', - # yyy='another long string', - # zzz='a third long string') - # ] - # - # or when a string formatting syntax. - func_call_or_string_format = False - tok = current.next_token - if current.is_name: - while tok and ( tok.is_name or tok.value == '.' ): - tok = tok.next_token - func_call_or_string_format = tok and tok.value == '(' - elif current.is_string: - while tok and tok.is_string: - tok = tok.next_token - func_call_or_string_format = tok and tok.value == '%' - if func_call_or_string_format: - open_bracket = logical_line.IsSurroundedByBrackets( current ) - if open_bracket: - if open_bracket.value in '[{': - if not self._FitsOnLine( open_bracket, - open_bracket.matching_bracket ): - return True - elif tok.value == '(': - if not self._FitsOnLine( current, tok.matching_bracket ): - return True - - if ( current.OpensScope() and previous.value == ',' and - subtypes.DICTIONARY_KEY not in current.next_token.subtypes ): - # If we have a list of tuples, then we can get a similar look as above. If - # the full list cannot fit on the line, then we want a split. - open_bracket = logical_line.IsSurroundedByBrackets( current ) - if ( open_bracket and open_bracket.value in '[{' and - subtypes.SUBSCRIPT_BRACKET not in open_bracket.subtypes ): - if not self._FitsOnLine( current, current.matching_bracket ): - return True - - ########################################################################### - # Dict/Set Splitting - if ( style.Get( 'EACH_DICT_ENTRY_ON_SEPARATE_LINE' ) and - subtypes.DICTIONARY_KEY in current.subtypes and not current.is_comment ): - # Place each dictionary entry onto its own line. - if previous.value == '{' and previous.previous_token: - opening = _GetOpeningBracket( previous.previous_token ) - if ( opening and opening.value == '(' and opening.previous_token and - opening.previous_token.is_name ): - # This is a dictionary that's an argument to a function. - if ( self._FitsOnLine( previous, previous.matching_bracket ) and - previous.matching_bracket.next_token and - ( not opening.matching_bracket.next_token or - opening.matching_bracket.next_token.value != '.' ) and - _ScopeHasNoCommas( previous ) ): - # Don't split before the key if: - # - The dictionary fits on a line, and - # - The function call isn't part of a builder-style call and - # - The dictionary has one entry and no trailing comma - return False + if style.Get('SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED'): + # Split before arguments in a function call or definition if the + # arguments are terminated by a comma. + opening = _GetOpeningBracket(current) + if opening and opening.previous_token and opening.previous_token.is_name: + if previous.value in '(,': + if opening.matching_bracket.previous_token.value == ',': return True - if ( style.Get( 'SPLIT_BEFORE_DICT_SET_GENERATOR' ) and - subtypes.DICT_SET_GENERATOR in current.subtypes ): - # Split before a dict/set generator. - return True + if ((current.is_name or current.value in {'*', '**'}) and + previous.value == ','): + # If we have a function call within an argument list and it won't fit on + # the remaining line, but it will fit on a line by itself, then go ahead + # and split before the call. + opening = _GetOpeningBracket(current) + if (opening and opening.value == '(' and opening.previous_token and + (opening.previous_token.is_name or + opening.previous_token.value in {'*', '**'})): + is_func_call = False + opening = current + while opening: + if opening.value == '(': + is_func_call = True + break + if (not (opening.is_name or opening.value in {'*', '**'}) and + opening.value != '.'): + break + opening = opening.next_token - if ( subtypes.DICTIONARY_VALUE in current.subtypes or - ( previous.is_pseudo and previous.value == '(' and - not current.is_comment ) ): - # Split before the dictionary value if we can't fit every dictionary - # entry on its own line. - if not current.OpensScope(): - opening = _GetOpeningBracket( current ) - if not self._EachDictEntryFitsOnOneLine( opening ): - return style.Get( 'ALLOW_SPLIT_BEFORE_DICT_VALUE' ) - - if previous.value == '{': - # Split if the dict/set cannot fit on one line and ends in a comma. - closing = previous.matching_bracket - if ( not self._FitsOnLine( previous, closing ) and - closing.previous_token.value == ',' ): - self.stack[ -1 ].split_before_closing_bracket = True - return True - - ########################################################################### - # Argument List Splitting - if ( style.Get( 'SPLIT_BEFORE_NAMED_ASSIGNS' ) and not current.is_comment and - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in current.subtypes ): - if ( previous.value not in { '=', ':', '*', '**' } and - current.value not in ':=,)' and - not _IsFunctionDefinition( previous ) ): - # If we're going to split the lines because of named arguments, then we - # want to split after the opening bracket as well. But not when this is - # part of a function definition. - if previous.value == '(': - # Make sure we don't split after the opening bracket if the - # continuation indent is greater than the opening bracket: - # - # a( - # b=1, - # c=2) - if ( self._FitsOnLine( previous, previous.matching_bracket ) and - logical_line.IsSurroundedByBrackets( previous ) ): - # An argument to a function is a function call with named - # assigns. - return False - - # Don't split if not required - if ( not style.Get( 'SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN' ) - and not style.Get( 'SPLIT_BEFORE_FIRST_ARGUMENT' ) ): - return False - - column = self.column - self.stack[ -1 ].last_space - return column > style.Get( 'CONTINUATION_INDENT_WIDTH' ) - - opening = _GetOpeningBracket( current ) - if opening: - return not self._ContainerFitsOnStartLine( opening ) - - if ( current.value not in '{)' and previous.value == '(' and - self._ArgumentListHasDictionaryEntry( current ) ): + if is_func_call: + if (not self._FitsOnLine(current, opening.matching_bracket) or + (opening.matching_bracket.next_token and + opening.matching_bracket.next_token.value != ',' and + not opening.matching_bracket.next_token.ClosesScope())): return True - if style.Get( 'SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED' ): - # Split before arguments in a function call or definition if the - # arguments are terminated by a comma. - opening = _GetOpeningBracket( current ) - if opening and opening.previous_token and opening.previous_token.is_name: - if previous.value in '(,': - if opening.matching_bracket.previous_token.value == ',': - return True - - if ( ( current.is_name or current.value in { '*', '**' } ) and - previous.value == ',' ): - # If we have a function call within an argument list and it won't fit on - # the remaining line, but it will fit on a line by itself, then go ahead - # and split before the call. - opening = _GetOpeningBracket( current ) - if ( opening and opening.value == '(' and opening.previous_token and - ( opening.previous_token.is_name or - opening.previous_token.value in { '*', '**' } ) ): - is_func_call = False - opening = current - while opening: - if opening.value == '(': - is_func_call = True - break - if ( not ( opening.is_name or opening.value in { '*', '**' } ) and - opening.value != '.' ): - break - opening = opening.next_token - - if is_func_call: - if ( not self._FitsOnLine( current, opening.matching_bracket ) or - ( opening.matching_bracket.next_token and - opening.matching_bracket.next_token.value != ',' and - not opening.matching_bracket.next_token.ClosesScope() ) ): - return True - - pprevious = previous.previous_token - - # A function call with a dictionary as its first argument may result in - # unreadable formatting if the dictionary spans multiple lines. The - # dictionary itself is formatted just fine, but the remaining arguments are - # indented too far: + pprevious = previous.previous_token + + # A function call with a dictionary as its first argument may result in + # unreadable formatting if the dictionary spans multiple lines. The + # dictionary itself is formatted just fine, but the remaining arguments are + # indented too far: + # + # function_call({ + # KEY_1: 'value one', + # KEY_2: 'value two', + # }, + # default=False) + if (current.value == '{' and previous.value == '(' and pprevious and + pprevious.is_name): + dict_end = current.matching_bracket + next_token = dict_end.next_token + if next_token.value == ',' and not self._FitsOnLine(current, dict_end): + return True + + if (current.is_name and pprevious and pprevious.is_name and + previous.value == '('): + + if (not self._FitsOnLine(previous, previous.matching_bracket) and + _IsFunctionCallWithArguments(current)): + # There is a function call, with more than 1 argument, where the first + # argument is itself a function call with arguments that does not fit + # into the line. In this specific case, if we split after the first + # argument's opening '(', then the formatting will look bad for the + # rest of the arguments. E.g.: + # + # outer_function_call(inner_function_call( + # inner_arg1, inner_arg2), + # outer_arg1, outer_arg2) # - # function_call({ - # KEY_1: 'value one', - # KEY_2: 'value two', - # }, - # default=False) - if ( current.value == '{' and previous.value == '(' and pprevious and - pprevious.is_name ): - dict_end = current.matching_bracket - next_token = dict_end.next_token - if next_token.value == ',' and not self._FitsOnLine( current, dict_end ): - return True - - if ( current.is_name and pprevious and pprevious.is_name and - previous.value == '(' ): - - if ( not self._FitsOnLine( previous, previous.matching_bracket ) and - _IsFunctionCallWithArguments( current ) ): - # There is a function call, with more than 1 argument, where the first - # argument is itself a function call with arguments that does not fit - # into the line. In this specific case, if we split after the first - # argument's opening '(', then the formatting will look bad for the - # rest of the arguments. E.g.: - # - # outer_function_call(inner_function_call( - # inner_arg1, inner_arg2), - # outer_arg1, outer_arg2) - # - # Instead, enforce a split before that argument to keep things looking - # good. - if ( style.Get( 'SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN' ) or - style.Get( 'SPLIT_BEFORE_FIRST_ARGUMENT' ) ): - return True - - opening = _GetOpeningBracket( current ) - if ( opening and opening.value == '(' and opening.previous_token and - ( opening.previous_token.is_name or - opening.previous_token.value in { '*', '**' } ) ): - is_func_call = False - opening = current - while opening: - if opening.value == '(': - is_func_call = True - break - if ( not ( opening.is_name or opening.value in { '*', '**' } ) - and opening.value != '.' ): - break - opening = opening.next_token - - if is_func_call: - if ( - not self._FitsOnLine( current, - opening.matching_bracket ) or - ( opening.matching_bracket.next_token and - opening.matching_bracket.next_token.value != ',' and - not opening.matching_bracket.next_token.ClosesScope() ) ): - return True - - if ( previous.OpensScope() and not current.OpensScope() and - not current.is_comment and - subtypes.SUBSCRIPT_BRACKET not in previous.subtypes ): - if pprevious and not pprevious.is_keyword and not pprevious.is_name: - # We want to split if there's a comment in the container. - token = current - while token != previous.matching_bracket: - if token.is_comment: - return True - token = token.next_token - if previous.value == '(': - pptoken = previous.previous_token - if not pptoken or not pptoken.is_name: - # Split after the opening of a tuple if it doesn't fit on the current - # line and it's not a function call. - if self._FitsOnLine( previous, previous.matching_bracket ): - return False - elif not self._FitsOnLine( previous, previous.matching_bracket ): - if len( previous.container_elements ) == 1: - return False - - elements = previous.container_elements + [ - previous.matching_bracket - ] - i = 1 - while i < len( elements ): - if ( not elements[ i - 1 ].OpensScope() and - not self._FitsOnLine( elements[ i - 1 ], elements[ i ] ) ): - return True - i += 1 - - if ( self.column_limit - self.column ) / float( - self.column_limit ) < 0.3: - # Try not to squish all of the arguments off to the right. - return True - else: - # Split after the opening of a container if it doesn't fit on the - # current line. - if not self._FitsOnLine( previous, previous.matching_bracket ): - return True - - ########################################################################### - # Original Formatting Splitting - # These checks rely upon the original formatting. This is in order to - # attempt to keep hand-written code in the same condition as it was before. - # However, this may cause the formatter to fail to be idempotent. - if ( style.Get( 'SPLIT_BEFORE_BITWISE_OPERATOR' ) and current.value in '&|' and - previous.lineno < current.lineno ): - # Retain the split before a bitwise operator. + # Instead, enforce a split before that argument to keep things looking + # good. + if (style.Get('SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN') or + style.Get('SPLIT_BEFORE_FIRST_ARGUMENT')): + return True + + opening = _GetOpeningBracket(current) + if (opening and opening.value == '(' and opening.previous_token and + (opening.previous_token.is_name or + opening.previous_token.value in {'*', '**'})): + is_func_call = False + opening = current + while opening: + if opening.value == '(': + is_func_call = True + break + if (not (opening.is_name or opening.value in {'*', '**'}) and + opening.value != '.'): + break + opening = opening.next_token + + if is_func_call: + if (not self._FitsOnLine(current, opening.matching_bracket) or + (opening.matching_bracket.next_token and + opening.matching_bracket.next_token.value != ',' and + not opening.matching_bracket.next_token.ClosesScope())): + return True + + if (previous.OpensScope() and not current.OpensScope() and + not current.is_comment and + subtypes.SUBSCRIPT_BRACKET not in previous.subtypes): + if pprevious and not pprevious.is_keyword and not pprevious.is_name: + # We want to split if there's a comment in the container. + token = current + while token != previous.matching_bracket: + if token.is_comment: return True + token = token.next_token + if previous.value == '(': + pptoken = previous.previous_token + if not pptoken or not pptoken.is_name: + # Split after the opening of a tuple if it doesn't fit on the current + # line and it's not a function call. + if self._FitsOnLine(previous, previous.matching_bracket): + return False + elif not self._FitsOnLine(previous, previous.matching_bracket): + if len(previous.container_elements) == 1: + return False - if ( current.is_comment and - previous.lineno < current.lineno - current.value.count( '\n' ) ): - # If a comment comes in the middle of a logical line (like an if - # conditional with comments interspersed), then we want to split if the - # original comments were on a separate line. + elements = previous.container_elements + [previous.matching_bracket] + i = 1 + while i < len(elements): + if (not elements[i - 1].OpensScope() and + not self._FitsOnLine(elements[i - 1], elements[i])): + return True + i += 1 + + if (self.column_limit - self.column) / float(self.column_limit) < 0.3: + # Try not to squish all of the arguments off to the right. return True + else: + # Split after the opening of a container if it doesn't fit on the + # current line. + if not self._FitsOnLine(previous, previous.matching_bracket): + return True + + ########################################################################### + # Original Formatting Splitting + # These checks rely upon the original formatting. This is in order to + # attempt to keep hand-written code in the same condition as it was before. + # However, this may cause the formatter to fail to be idempotent. + if (style.Get('SPLIT_BEFORE_BITWISE_OPERATOR') and current.value in '&|' and + previous.lineno < current.lineno): + # Retain the split before a bitwise operator. + return True + + if (current.is_comment and + previous.lineno < current.lineno - current.value.count('\n')): + # If a comment comes in the middle of a logical line (like an if + # conditional with comments interspersed), then we want to split if the + # original comments were on a separate line. + return True - return False + return False - def AddTokenToState( self, newline, dry_run, must_split = False ): - """Add a token to the format decision state. + def AddTokenToState(self, newline, dry_run, must_split=False): + """Add a token to the format decision state. Allow the heuristic to try out adding the token with and without a newline. Later on, the algorithm will determine which one has the lowest penalty. @@ -581,21 +575,21 @@ def AddTokenToState( self, newline, dry_run, must_split = False ): Returns: The penalty of splitting after the current token. """ - self._PushParameterListState( newline ) + self._PushParameterListState(newline) - penalty = 0 - if newline: - penalty = self._AddTokenOnNewline( dry_run, must_split ) - else: - self._AddTokenOnCurrentLine( dry_run ) + penalty = 0 + if newline: + penalty = self._AddTokenOnNewline(dry_run, must_split) + else: + self._AddTokenOnCurrentLine(dry_run) - penalty += self._CalculateComprehensionState( newline ) - penalty += self._CalculateParameterListState( newline ) + penalty += self._CalculateComprehensionState(newline) + penalty += self._CalculateParameterListState(newline) - return self.MoveStateToNextToken() + penalty + return self.MoveStateToNextToken() + penalty - def _AddTokenOnCurrentLine( self, dry_run ): - """Puts the token on the current line. + def _AddTokenOnCurrentLine(self, dry_run): + """Puts the token on the current line. Appends the next token to the state and updates information necessary for indentation. @@ -603,37 +597,37 @@ def _AddTokenOnCurrentLine( self, dry_run ): Arguments: dry_run: (bool) Commit whitespace changes to the FormatToken if True. """ - current = self.next_token - previous = current.previous_token - - spaces = current.spaces_required_before - if isinstance( spaces, list ): - # Don't set the value here, as we need to look at the lines near - # this one to determine the actual horizontal alignment value. - spaces = 0 - - if not dry_run: - current.AddWhitespacePrefix( newlines_before = 0, spaces = spaces ) - - if previous.OpensScope(): - if not current.is_comment: - # Align closing scopes that are on a newline with the opening scope: - # - # foo = [a, - # b, - # ] - self.stack[ -1 ].closing_scope_indent = self.column - 1 - if style.Get( 'ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT' ): - self.stack[ -1 ].closing_scope_indent += 1 - self.stack[ -1 ].indent = self.column + spaces - else: - self.stack[ -1 ].closing_scope_indent = ( - self.stack[ -1 ].indent - style.Get( 'CONTINUATION_INDENT_WIDTH' ) ) - - self.column += spaces - - def _AddTokenOnNewline( self, dry_run, must_split ): - """Adds a line break and necessary indentation. + current = self.next_token + previous = current.previous_token + + spaces = current.spaces_required_before + if isinstance(spaces, list): + # Don't set the value here, as we need to look at the lines near + # this one to determine the actual horizontal alignment value. + spaces = 0 + + if not dry_run: + current.AddWhitespacePrefix(newlines_before=0, spaces=spaces) + + if previous.OpensScope(): + if not current.is_comment: + # Align closing scopes that are on a newline with the opening scope: + # + # foo = [a, + # b, + # ] + self.stack[-1].closing_scope_indent = self.column - 1 + if style.Get('ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'): + self.stack[-1].closing_scope_indent += 1 + self.stack[-1].indent = self.column + spaces + else: + self.stack[-1].closing_scope_indent = ( + self.stack[-1].indent - style.Get('CONTINUATION_INDENT_WIDTH')) + + self.column += spaces + + def _AddTokenOnNewline(self, dry_run, must_split): + """Adds a line break and necessary indentation. Appends the next token to the state and updates information necessary for indentation. @@ -646,63 +640,63 @@ def _AddTokenOnNewline( self, dry_run, must_split ): Returns: The split penalty for splitting after the current state. """ - current = self.next_token - previous = current.previous_token - - self.column = self._GetNewlineColumn() - - if not dry_run: - indent_level = self.line.depth - spaces = self.column - if spaces: - spaces -= indent_level * style.Get( 'INDENT_WIDTH' ) - current.AddWhitespacePrefix( - newlines_before = 1, spaces = spaces, indent_level = indent_level ) - - if not current.is_comment: - self.stack[ -1 ].last_space = self.column - self.lowest_level_on_line = self.paren_level - - if ( previous.OpensScope() or - ( previous.is_comment and previous.previous_token is not None and - previous.previous_token.OpensScope() ) ): - dedent = ( style.Get( 'CONTINUATION_INDENT_WIDTH' ), - 0 )[ style.Get( 'INDENT_CLOSING_BRACKETS' ) ] - self.stack[ -1 ].closing_scope_indent = ( - max( 0, self.stack[ -1 ].indent - dedent ) ) - self.stack[ -1 ].split_before_closing_bracket = True - - # Calculate the split penalty. - penalty = current.split_penalty - - if must_split: - # Don't penalize for a must split. - return penalty - - if previous.is_pseudo and previous.value == '(': - # Small penalty for splitting after a pseudo paren. - penalty += 50 - - # Add a penalty for each increasing newline we add, but don't penalize for - # splitting before an if-expression or list comprehension. - if current.value not in { 'if', 'for' }: - last = self.stack[ -1 ] - last.num_line_splits += 1 - penalty += ( - style.Get( 'SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT' ) * - last.num_line_splits ) - - if current.OpensScope() and previous.OpensScope(): - # Prefer to keep opening brackets coalesced (unless it's at the beginning - # of a function call). - pprev = previous.previous_token - if not pprev or not pprev.is_name: - penalty += 10 - - return penalty + 10 - - def MoveStateToNextToken( self ): - """Calculate format decision state information and move onto the next token. + current = self.next_token + previous = current.previous_token + + self.column = self._GetNewlineColumn() + + if not dry_run: + indent_level = self.line.depth + spaces = self.column + if spaces: + spaces -= indent_level * style.Get('INDENT_WIDTH') + current.AddWhitespacePrefix( + newlines_before=1, spaces=spaces, indent_level=indent_level) + + if not current.is_comment: + self.stack[-1].last_space = self.column + self.lowest_level_on_line = self.paren_level + + if (previous.OpensScope() or + (previous.is_comment and previous.previous_token is not None and + previous.previous_token.OpensScope())): + dedent = (style.Get('CONTINUATION_INDENT_WIDTH'), + 0)[style.Get('INDENT_CLOSING_BRACKETS')] + self.stack[-1].closing_scope_indent = ( + max(0, self.stack[-1].indent - dedent)) + self.stack[-1].split_before_closing_bracket = True + + # Calculate the split penalty. + penalty = current.split_penalty + + if must_split: + # Don't penalize for a must split. + return penalty + + if previous.is_pseudo and previous.value == '(': + # Small penalty for splitting after a pseudo paren. + penalty += 50 + + # Add a penalty for each increasing newline we add, but don't penalize for + # splitting before an if-expression or list comprehension. + if current.value not in {'if', 'for'}: + last = self.stack[-1] + last.num_line_splits += 1 + penalty += ( + style.Get('SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT') * + last.num_line_splits) + + if current.OpensScope() and previous.OpensScope(): + # Prefer to keep opening brackets coalesced (unless it's at the beginning + # of a function call). + pprev = previous.previous_token + if not pprev or not pprev.is_name: + penalty += 10 + + return penalty + 10 + + def MoveStateToNextToken(self): + """Calculate format decision state information and move onto the next token. Before moving onto the next token, we first calculate the format decision state given the current token and its formatting decisions. Then the format @@ -711,55 +705,55 @@ def MoveStateToNextToken( self ): Returns: The penalty for the number of characters over the column limit. """ - current = self.next_token - if not current.OpensScope() and not current.ClosesScope(): - self.lowest_level_on_line = min( - self.lowest_level_on_line, self.paren_level ) - - # If we encounter an opening bracket, we add a level to our stack to prepare - # for the subsequent tokens. - if current.OpensScope(): - last = self.stack[ -1 ] - new_indent = style.Get( 'CONTINUATION_INDENT_WIDTH' ) + last.last_space - - self.stack.append( _ParenState( new_indent, self.stack[ -1 ].last_space ) ) - self.paren_level += 1 - - # If we encounter a closing bracket, we can remove a level from our - # parenthesis stack. - if len( self.stack ) > 1 and current.ClosesScope(): - if subtypes.DICTIONARY_KEY_PART in current.subtypes: - self.stack[ -2 ].last_space = self.stack[ -2 ].indent - else: - self.stack[ -2 ].last_space = self.stack[ -1 ].last_space - self.stack.pop() - self.paren_level -= 1 - - is_multiline_string = current.is_string and '\n' in current.value - if is_multiline_string: - # This is a multiline string. Only look at the first line. - self.column += len( current.value.split( '\n' )[ 0 ] ) - elif not current.is_pseudo: - self.column += len( current.value ) - - self.next_token = self.next_token.next_token - - # Calculate the penalty for overflowing the column limit. - penalty = 0 - if ( not current.is_pylint_comment and not current.is_pytype_comment and - not current.is_copybara_comment and self.column > self.column_limit ): - excess_characters = self.column - self.column_limit - penalty += style.Get( 'SPLIT_PENALTY_EXCESS_CHARACTER' ) * excess_characters - - if is_multiline_string: - # If this is a multiline string, the column is actually the - # end of the last line in the string. - self.column = len( current.value.split( '\n' )[ -1 ] ) - - return penalty - - def _CalculateComprehensionState( self, newline ): - """Makes required changes to comprehension state. + current = self.next_token + if not current.OpensScope() and not current.ClosesScope(): + self.lowest_level_on_line = min( + self.lowest_level_on_line, self.paren_level) + + # If we encounter an opening bracket, we add a level to our stack to prepare + # for the subsequent tokens. + if current.OpensScope(): + last = self.stack[-1] + new_indent = style.Get('CONTINUATION_INDENT_WIDTH') + last.last_space + + self.stack.append(_ParenState(new_indent, self.stack[-1].last_space)) + self.paren_level += 1 + + # If we encounter a closing bracket, we can remove a level from our + # parenthesis stack. + if len(self.stack) > 1 and current.ClosesScope(): + if subtypes.DICTIONARY_KEY_PART in current.subtypes: + self.stack[-2].last_space = self.stack[-2].indent + else: + self.stack[-2].last_space = self.stack[-1].last_space + self.stack.pop() + self.paren_level -= 1 + + is_multiline_string = current.is_string and '\n' in current.value + if is_multiline_string: + # This is a multiline string. Only look at the first line. + self.column += len(current.value.split('\n')[0]) + elif not current.is_pseudo: + self.column += len(current.value) + + self.next_token = self.next_token.next_token + + # Calculate the penalty for overflowing the column limit. + penalty = 0 + if (not current.is_pylint_comment and not current.is_pytype_comment and + not current.is_copybara_comment and self.column > self.column_limit): + excess_characters = self.column - self.column_limit + penalty += style.Get('SPLIT_PENALTY_EXCESS_CHARACTER') * excess_characters + + if is_multiline_string: + # If this is a multiline string, the column is actually the + # end of the last line in the string. + self.column = len(current.value.split('\n')[-1]) + + return penalty + + def _CalculateComprehensionState(self, newline): + """Makes required changes to comprehension state. Args: newline: Whether the current token is to be added on a newline. @@ -768,82 +762,81 @@ def _CalculateComprehensionState( self, newline ): The penalty for the token-newline combination given the current comprehension state. """ - current = self.next_token - previous = current.previous_token - top_of_stack = self.comp_stack[ -1 ] if self.comp_stack else None - penalty = 0 - - if top_of_stack is not None: - # Check if the token terminates the current comprehension. - if current == top_of_stack.closing_bracket: - last = self.comp_stack.pop() - # Lightly penalize comprehensions that are split across multiple lines. - if last.has_interior_split: - penalty += style.Get( 'SPLIT_PENALTY_COMPREHENSION' ) - - return penalty - - if newline: - top_of_stack.has_interior_split = True - - if ( subtypes.COMP_EXPR in current.subtypes and - subtypes.COMP_EXPR not in previous.subtypes ): - self.comp_stack.append( object_state.ComprehensionState( current ) ) - return penalty - - if current.value == 'for' and subtypes.COMP_FOR in current.subtypes: - if top_of_stack.for_token is not None: - # Treat nested comprehensions like normal comp_if expressions. - # Example: - # my_comp = [ - # a.qux + b.qux - # for a in foo - # --> for b in bar <-- - # if a.zut + b.zut - # ] - if ( style.Get( 'SPLIT_COMPLEX_COMPREHENSION' ) and - top_of_stack.has_split_at_for != newline and - ( top_of_stack.has_split_at_for or - not top_of_stack.HasTrivialExpr() ) ): - penalty += split_penalty.UNBREAKABLE - else: - top_of_stack.for_token = current - top_of_stack.has_split_at_for = newline - - # Try to keep trivial expressions on the same line as the comp_for. - if ( style.Get( 'SPLIT_COMPLEX_COMPREHENSION' ) and newline and - top_of_stack.HasTrivialExpr() ): - penalty += split_penalty.CONNECTED - - if ( subtypes.COMP_IF in current.subtypes and - subtypes.COMP_IF not in previous.subtypes ): - # Penalize breaking at comp_if when it doesn't match the newline structure - # in the rest of the comprehension. - if ( style.Get( 'SPLIT_COMPLEX_COMPREHENSION' ) and - top_of_stack.has_split_at_for != newline and - ( top_of_stack.has_split_at_for or - not top_of_stack.HasTrivialExpr() ) ): - penalty += split_penalty.UNBREAKABLE + current = self.next_token + previous = current.previous_token + top_of_stack = self.comp_stack[-1] if self.comp_stack else None + penalty = 0 + + if top_of_stack is not None: + # Check if the token terminates the current comprehension. + if current == top_of_stack.closing_bracket: + last = self.comp_stack.pop() + # Lightly penalize comprehensions that are split across multiple lines. + if last.has_interior_split: + penalty += style.Get('SPLIT_PENALTY_COMPREHENSION') return penalty - def _PushParameterListState( self, newline ): - """Push a new parameter list state for a function definition. + if newline: + top_of_stack.has_interior_split = True + + if (subtypes.COMP_EXPR in current.subtypes and + subtypes.COMP_EXPR not in previous.subtypes): + self.comp_stack.append(object_state.ComprehensionState(current)) + return penalty + + if current.value == 'for' and subtypes.COMP_FOR in current.subtypes: + if top_of_stack.for_token is not None: + # Treat nested comprehensions like normal comp_if expressions. + # Example: + # my_comp = [ + # a.qux + b.qux + # for a in foo + # --> for b in bar <-- + # if a.zut + b.zut + # ] + if (style.Get('SPLIT_COMPLEX_COMPREHENSION') and + top_of_stack.has_split_at_for != newline and + (top_of_stack.has_split_at_for or + not top_of_stack.HasTrivialExpr())): + penalty += split_penalty.UNBREAKABLE + else: + top_of_stack.for_token = current + top_of_stack.has_split_at_for = newline + + # Try to keep trivial expressions on the same line as the comp_for. + if (style.Get('SPLIT_COMPLEX_COMPREHENSION') and newline and + top_of_stack.HasTrivialExpr()): + penalty += split_penalty.CONNECTED + + if (subtypes.COMP_IF in current.subtypes and + subtypes.COMP_IF not in previous.subtypes): + # Penalize breaking at comp_if when it doesn't match the newline structure + # in the rest of the comprehension. + if (style.Get('SPLIT_COMPLEX_COMPREHENSION') and + top_of_stack.has_split_at_for != newline and + (top_of_stack.has_split_at_for or not top_of_stack.HasTrivialExpr())): + penalty += split_penalty.UNBREAKABLE + + return penalty + + def _PushParameterListState(self, newline): + """Push a new parameter list state for a function definition. Args: newline: Whether the current token is to be added on a newline. """ - current = self.next_token - previous = current.previous_token + current = self.next_token + previous = current.previous_token - if _IsFunctionDefinition( previous ): - first_param_column = previous.total_length + self.stack[ -2 ].indent - self.param_list_stack.append( - object_state.ParameterListState( - previous, newline, first_param_column ) ) + if _IsFunctionDefinition(previous): + first_param_column = previous.total_length + self.stack[-2].indent + self.param_list_stack.append( + object_state.ParameterListState( + previous, newline, first_param_column)) - def _CalculateParameterListState( self, newline ): - """Makes required changes to parameter list state. + def _CalculateParameterListState(self, newline): + """Makes required changes to parameter list state. Args: newline: Whether the current token is to be added on a newline. @@ -852,355 +845,355 @@ def _CalculateParameterListState( self, newline ): The penalty for the token-newline combination given the current parameter state. """ - current = self.next_token - previous = current.previous_token - penalty = 0 - - if _IsFunctionDefinition( previous ): - first_param_column = previous.total_length + self.stack[ -2 ].indent - if not newline: - param_list = self.param_list_stack[ -1 ] - if param_list.parameters and param_list.has_typed_return: - last_param = param_list.parameters[ -1 ].first_token - last_token = _LastTokenInLine( previous.matching_bracket ) - total_length = last_token.total_length - total_length -= last_param.total_length - len( last_param.value ) - if total_length + self.column > self.column_limit: - # If we need to split before the trailing code of a function - # definition with return types, then also split before the opening - # parameter so that the trailing bit isn't indented on a line by - # itself: - # - # def rrrrrrrrrrrrrrrrrrrrrr(ccccccccccccccccccccccc: Tuple[Text] - # ) -> List[Tuple[Text, Text]]: - # pass - penalty += split_penalty.VERY_STRONGLY_CONNECTED - return penalty - - if first_param_column <= self.column: - # Make sure we don't split after the opening bracket if the - # continuation indent is greater than the opening bracket: - # - # a( - # b=1, - # c=2) - penalty += split_penalty.VERY_STRONGLY_CONNECTED - return penalty - - if not self.param_list_stack: - return penalty - - param_list = self.param_list_stack[ -1 ] - if current == self.param_list_stack[ -1 ].closing_bracket: - self.param_list_stack.pop() # We're done with this state. - if newline and param_list.has_typed_return: - if param_list.split_before_closing_bracket: - penalty -= split_penalty.STRONGLY_CONNECTED - elif param_list.LastParamFitsOnLine( self.column ): - penalty += split_penalty.STRONGLY_CONNECTED - - if ( not newline and param_list.has_typed_return and - param_list.has_split_before_first_param ): - # Prefer splitting before the closing bracket if there's a return type - # and we've already split before the first parameter. - penalty += split_penalty.STRONGLY_CONNECTED - - return penalty - - if not param_list.parameters: - return penalty - - if newline: - if self._FitsOnLine( param_list.parameters[ 0 ].first_token, - _LastTokenInLine( param_list.closing_bracket ) ): - penalty += split_penalty.STRONGLY_CONNECTED - - if ( not newline and style.Get( 'SPLIT_BEFORE_NAMED_ASSIGNS' ) and - param_list.has_default_values and - current != param_list.parameters[ 0 ].first_token and - current != param_list.closing_bracket and - subtypes.PARAMETER_START in current.subtypes ): - # If we want to split before parameters when there are named assigns, - # then add a penalty for not splitting. - penalty += split_penalty.STRONGLY_CONNECTED - + current = self.next_token + previous = current.previous_token + penalty = 0 + + if _IsFunctionDefinition(previous): + first_param_column = previous.total_length + self.stack[-2].indent + if not newline: + param_list = self.param_list_stack[-1] + if param_list.parameters and param_list.has_typed_return: + last_param = param_list.parameters[-1].first_token + last_token = _LastTokenInLine(previous.matching_bracket) + total_length = last_token.total_length + total_length -= last_param.total_length - len(last_param.value) + if total_length + self.column > self.column_limit: + # If we need to split before the trailing code of a function + # definition with return types, then also split before the opening + # parameter so that the trailing bit isn't indented on a line by + # itself: + # + # def rrrrrrrrrrrrrrrrrrrrrr(ccccccccccccccccccccccc: Tuple[Text] + # ) -> List[Tuple[Text, Text]]: + # pass + penalty += split_penalty.VERY_STRONGLY_CONNECTED return penalty - def _IndentWithContinuationAlignStyle( self, column ): - if column == 0: - return column - align_style = style.Get( 'CONTINUATION_ALIGN_STYLE' ) - if align_style == 'FIXED': - return ( - ( self.line.depth * style.Get( 'INDENT_WIDTH' ) ) + - style.Get( 'CONTINUATION_INDENT_WIDTH' ) ) - if align_style == 'VALIGN-RIGHT': - indent_width = style.Get( 'INDENT_WIDTH' ) - return indent_width * int( ( column + indent_width - 1 ) / indent_width ) - return column - - def _GetNewlineColumn( self ): - """Return the new column on the newline.""" - current = self.next_token - previous = current.previous_token - top_of_stack = self.stack[ -1 ] - - if isinstance( current.spaces_required_before, list ): - # Don't set the value here, as we need to look at the lines near - # this one to determine the actual horizontal alignment value. - return 0 - elif current.spaces_required_before > 2 or self.line.disable: - return current.spaces_required_before - - cont_aligned_indent = self._IndentWithContinuationAlignStyle( - top_of_stack.indent ) - - if current.OpensScope(): - return cont_aligned_indent if self.paren_level else self.first_indent - - if current.ClosesScope(): - if ( previous.OpensScope() or - ( previous.is_comment and previous.previous_token is not None and - previous.previous_token.OpensScope() ) ): - return max( - 0, top_of_stack.indent - style.Get( 'CONTINUATION_INDENT_WIDTH' ) ) - return top_of_stack.closing_scope_indent - - if ( previous and previous.is_string and current.is_string and - subtypes.DICTIONARY_VALUE in current.subtypes ): - return previous.column - - if style.Get( 'INDENT_DICTIONARY_VALUE' ): - if previous and ( previous.value == ':' or previous.is_pseudo ): - if subtypes.DICTIONARY_VALUE in current.subtypes: - return top_of_stack.indent - - if ( not self.param_list_stack and _IsCompoundStatement( self.line.first ) and - ( not ( style.Get( 'DEDENT_CLOSING_BRACKETS' ) or - style.Get( 'INDENT_CLOSING_BRACKETS' ) ) or - style.Get( 'SPLIT_BEFORE_FIRST_ARGUMENT' ) ) ): - token_indent = ( - len( self.line.first.whitespace_prefix.split( '\n' )[ -1 ] ) + - style.Get( 'INDENT_WIDTH' ) ) - if token_indent == top_of_stack.indent: - return token_indent + style.Get( 'CONTINUATION_INDENT_WIDTH' ) - - if ( self.param_list_stack and - not self.param_list_stack[ -1 ].SplitBeforeClosingBracket( - top_of_stack.indent ) and top_of_stack.indent - == ( ( self.line.depth + 1 ) * style.Get( 'INDENT_WIDTH' ) ) ): - # NOTE: comment inside argument list is not excluded in subtype assigner - if ( subtypes.PARAMETER_START in current.subtypes or - ( previous.is_comment and - subtypes.PARAMETER_START in previous.subtypes ) ): - return top_of_stack.indent + style.Get( 'CONTINUATION_INDENT_WIDTH' ) - - return cont_aligned_indent - - def _FitsOnLine( self, start, end ): - """Determines if line between start and end can fit on the current line.""" - length = end.total_length - start.total_length - if not start.is_pseudo: - length += len( start.value ) - return length + self.column <= self.column_limit - - def _EachDictEntryFitsOnOneLine( self, opening ): - """Determine if each dict elems can fit on one line.""" - - def PreviousNonCommentToken( tok ): - tok = tok.previous_token - while tok.is_comment: - tok = tok.previous_token - return tok - - def ImplicitStringConcatenation( tok ): - num_strings = 0 - if tok.is_pseudo: - tok = tok.next_token - while tok.is_string: - num_strings += 1 - tok = tok.next_token - return num_strings > 1 - - def DictValueIsContainer( opening, closing ): - """Return true if the dictionary value is a container.""" - if not opening or not closing: - return False - colon = opening.previous_token - while colon: - if not colon.is_pseudo: - break - colon = colon.previous_token - if not colon or colon.value != ':': - return False - key = colon.previous_token - if not key: - return False - return subtypes.DICTIONARY_KEY_PART in key.subtypes - - closing = opening.matching_bracket - entry_start = opening.next_token - current = opening.next_token.next_token - - while current and current != closing: - if subtypes.DICTIONARY_KEY in current.subtypes: - prev = PreviousNonCommentToken( current ) - if prev.value == ',': - prev = PreviousNonCommentToken( prev.previous_token ) - if not DictValueIsContainer( prev.matching_bracket, prev ): - length = prev.total_length - entry_start.total_length - length += len( entry_start.value ) - if length + self.stack[ -2 ].indent >= self.column_limit: - return False - entry_start = current - if current.OpensScope(): - if ( ( current.value == '{' or - ( current.is_pseudo and current.next_token.value == '{' ) and - subtypes.DICTIONARY_VALUE in current.subtypes ) or - ImplicitStringConcatenation( current ) ): - # A dictionary entry that cannot fit on a single line shouldn't matter - # to this calculation. If it can't fit on a single line, then the - # opening should be on the same line as the key and the rest on - # newlines after it. But the other entries should be on single lines - # if possible. - if current.matching_bracket: - current = current.matching_bracket - while current: - if current == closing: - return True - if subtypes.DICTIONARY_KEY in current.subtypes: - entry_start = current - break - current = current.next_token - else: - current = current.matching_bracket - else: - current = current.next_token - - # At this point, current is the closing bracket. Go back one to get the end - # of the dictionary entry. - current = PreviousNonCommentToken( current ) - length = current.total_length - entry_start.total_length - length += len( entry_start.value ) - return length + self.stack[ -2 ].indent <= self.column_limit - - def _ArgumentListHasDictionaryEntry( self, token ): - """Check if the function argument list has a dictionary as an arg.""" - if _IsArgumentToFunction( token ): - while token: - if token.value == '{': - length = token.matching_bracket.total_length - token.total_length - return length + self.stack[ -2 ].indent > self.column_limit - if token.ClosesScope(): - break - if token.OpensScope(): - token = token.matching_bracket - token = token.next_token + if first_param_column <= self.column: + # Make sure we don't split after the opening bracket if the + # continuation indent is greater than the opening bracket: + # + # a( + # b=1, + # c=2) + penalty += split_penalty.VERY_STRONGLY_CONNECTED + return penalty + + if not self.param_list_stack: + return penalty + + param_list = self.param_list_stack[-1] + if current == self.param_list_stack[-1].closing_bracket: + self.param_list_stack.pop() # We're done with this state. + if newline and param_list.has_typed_return: + if param_list.split_before_closing_bracket: + penalty -= split_penalty.STRONGLY_CONNECTED + elif param_list.LastParamFitsOnLine(self.column): + penalty += split_penalty.STRONGLY_CONNECTED + + if (not newline and param_list.has_typed_return and + param_list.has_split_before_first_param): + # Prefer splitting before the closing bracket if there's a return type + # and we've already split before the first parameter. + penalty += split_penalty.STRONGLY_CONNECTED + + return penalty + + if not param_list.parameters: + return penalty + + if newline: + if self._FitsOnLine(param_list.parameters[0].first_token, + _LastTokenInLine(param_list.closing_bracket)): + penalty += split_penalty.STRONGLY_CONNECTED + + if (not newline and style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and + param_list.has_default_values and + current != param_list.parameters[0].first_token and + current != param_list.closing_bracket and + subtypes.PARAMETER_START in current.subtypes): + # If we want to split before parameters when there are named assigns, + # then add a penalty for not splitting. + penalty += split_penalty.STRONGLY_CONNECTED + + return penalty + + def _IndentWithContinuationAlignStyle(self, column): + if column == 0: + return column + align_style = style.Get('CONTINUATION_ALIGN_STYLE') + if align_style == 'FIXED': + return ( + (self.line.depth * style.Get('INDENT_WIDTH')) + + style.Get('CONTINUATION_INDENT_WIDTH')) + if align_style == 'VALIGN-RIGHT': + indent_width = style.Get('INDENT_WIDTH') + return indent_width * int((column + indent_width - 1) / indent_width) + return column + + def _GetNewlineColumn(self): + """Return the new column on the newline.""" + current = self.next_token + previous = current.previous_token + top_of_stack = self.stack[-1] + + if isinstance(current.spaces_required_before, list): + # Don't set the value here, as we need to look at the lines near + # this one to determine the actual horizontal alignment value. + return 0 + elif current.spaces_required_before > 2 or self.line.disable: + return current.spaces_required_before + + cont_aligned_indent = self._IndentWithContinuationAlignStyle( + top_of_stack.indent) + + if current.OpensScope(): + return cont_aligned_indent if self.paren_level else self.first_indent + + if current.ClosesScope(): + if (previous.OpensScope() or + (previous.is_comment and previous.previous_token is not None and + previous.previous_token.OpensScope())): + return max( + 0, top_of_stack.indent - style.Get('CONTINUATION_INDENT_WIDTH')) + return top_of_stack.closing_scope_indent + + if (previous and previous.is_string and current.is_string and + subtypes.DICTIONARY_VALUE in current.subtypes): + return previous.column + + if style.Get('INDENT_DICTIONARY_VALUE'): + if previous and (previous.value == ':' or previous.is_pseudo): + if subtypes.DICTIONARY_VALUE in current.subtypes: + return top_of_stack.indent + + if (not self.param_list_stack and _IsCompoundStatement(self.line.first) and + (not (style.Get('DEDENT_CLOSING_BRACKETS') or + style.Get('INDENT_CLOSING_BRACKETS')) or + style.Get('SPLIT_BEFORE_FIRST_ARGUMENT'))): + token_indent = ( + len(self.line.first.whitespace_prefix.split('\n')[-1]) + + style.Get('INDENT_WIDTH')) + if token_indent == top_of_stack.indent: + return token_indent + style.Get('CONTINUATION_INDENT_WIDTH') + + if (self.param_list_stack and + not self.param_list_stack[-1].SplitBeforeClosingBracket( + top_of_stack.indent) and top_of_stack.indent + == ((self.line.depth + 1) * style.Get('INDENT_WIDTH'))): + # NOTE: comment inside argument list is not excluded in subtype assigner + if (subtypes.PARAMETER_START in current.subtypes or + (previous.is_comment and + subtypes.PARAMETER_START in previous.subtypes)): + return top_of_stack.indent + style.Get('CONTINUATION_INDENT_WIDTH') + + return cont_aligned_indent + + def _FitsOnLine(self, start, end): + """Determines if line between start and end can fit on the current line.""" + length = end.total_length - start.total_length + if not start.is_pseudo: + length += len(start.value) + return length + self.column <= self.column_limit + + def _EachDictEntryFitsOnOneLine(self, opening): + """Determine if each dict elems can fit on one line.""" + + def PreviousNonCommentToken(tok): + tok = tok.previous_token + while tok.is_comment: + tok = tok.previous_token + return tok + + def ImplicitStringConcatenation(tok): + num_strings = 0 + if tok.is_pseudo: + tok = tok.next_token + while tok.is_string: + num_strings += 1 + tok = tok.next_token + return num_strings > 1 + + def DictValueIsContainer(opening, closing): + """Return true if the dictionary value is a container.""" + if not opening or not closing: + return False + colon = opening.previous_token + while colon: + if not colon.is_pseudo: + break + colon = colon.previous_token + if not colon or colon.value != ':': return False + key = colon.previous_token + if not key: + return False + return subtypes.DICTIONARY_KEY_PART in key.subtypes + + closing = opening.matching_bracket + entry_start = opening.next_token + current = opening.next_token.next_token + + while current and current != closing: + if subtypes.DICTIONARY_KEY in current.subtypes: + prev = PreviousNonCommentToken(current) + if prev.value == ',': + prev = PreviousNonCommentToken(prev.previous_token) + if not DictValueIsContainer(prev.matching_bracket, prev): + length = prev.total_length - entry_start.total_length + length += len(entry_start.value) + if length + self.stack[-2].indent >= self.column_limit: + return False + entry_start = current + if current.OpensScope(): + if ((current.value == '{' or + (current.is_pseudo and current.next_token.value == '{') and + subtypes.DICTIONARY_VALUE in current.subtypes) or + ImplicitStringConcatenation(current)): + # A dictionary entry that cannot fit on a single line shouldn't matter + # to this calculation. If it can't fit on a single line, then the + # opening should be on the same line as the key and the rest on + # newlines after it. But the other entries should be on single lines + # if possible. + if current.matching_bracket: + current = current.matching_bracket + while current: + if current == closing: + return True + if subtypes.DICTIONARY_KEY in current.subtypes: + entry_start = current + break + current = current.next_token + else: + current = current.matching_bracket + else: + current = current.next_token - def _ContainerFitsOnStartLine( self, opening ): - """Check if the container can fit on its starting line.""" - return ( - opening.matching_bracket.total_length - opening.total_length + - self.stack[ -1 ].indent ) <= self.column_limit + # At this point, current is the closing bracket. Go back one to get the end + # of the dictionary entry. + current = PreviousNonCommentToken(current) + length = current.total_length - entry_start.total_length + length += len(entry_start.value) + return length + self.stack[-2].indent <= self.column_limit + + def _ArgumentListHasDictionaryEntry(self, token): + """Check if the function argument list has a dictionary as an arg.""" + if _IsArgumentToFunction(token): + while token: + if token.value == '{': + length = token.matching_bracket.total_length - token.total_length + return length + self.stack[-2].indent > self.column_limit + if token.ClosesScope(): + break + if token.OpensScope(): + token = token.matching_bracket + token = token.next_token + return False + + def _ContainerFitsOnStartLine(self, opening): + """Check if the container can fit on its starting line.""" + return ( + opening.matching_bracket.total_length - opening.total_length + + self.stack[-1].indent) <= self.column_limit _COMPOUND_STMTS = frozenset( - { 'for', 'while', 'if', 'elif', 'with', 'except', 'def', 'class' } ) + {'for', 'while', 'if', 'elif', 'with', 'except', 'def', 'class'}) -def _IsCompoundStatement( token ): - if token.value == 'async': - token = token.next_token - return token.value in _COMPOUND_STMTS +def _IsCompoundStatement(token): + if token.value == 'async': + token = token.next_token + return token.value in _COMPOUND_STMTS -def _IsFunctionDef( token ): - if token.value == 'async': - token = token.next_token - return token.value == 'def' +def _IsFunctionDef(token): + if token.value == 'async': + token = token.next_token + return token.value == 'def' -def _IsFunctionCallWithArguments( token ): - while token: - if token.value == '(': - token = token.next_token - return token and token.value != ')' - elif token.name not in { 'NAME', 'DOT', 'EQUAL' }: - break - token = token.next_token - return False +def _IsFunctionCallWithArguments(token): + while token: + if token.value == '(': + token = token.next_token + return token and token.value != ')' + elif token.name not in {'NAME', 'DOT', 'EQUAL'}: + break + token = token.next_token + return False -def _IsArgumentToFunction( token ): - bracket = logical_line.IsSurroundedByBrackets( token ) - if not bracket or bracket.value != '(': - return False - previous = bracket.previous_token - return previous and previous.is_name +def _IsArgumentToFunction(token): + bracket = logical_line.IsSurroundedByBrackets(token) + if not bracket or bracket.value != '(': + return False + previous = bracket.previous_token + return previous and previous.is_name -def _GetOpeningBracket( current ): - """Get the opening bracket containing the current token.""" - if current.matching_bracket and not current.is_pseudo: - return current if current.OpensScope() else current.matching_bracket +def _GetOpeningBracket(current): + """Get the opening bracket containing the current token.""" + if current.matching_bracket and not current.is_pseudo: + return current if current.OpensScope() else current.matching_bracket - while current: - if current.ClosesScope(): - current = current.matching_bracket - elif current.is_pseudo: - current = current.previous_token - elif current.OpensScope(): - return current - current = current.previous_token - return None + while current: + if current.ClosesScope(): + current = current.matching_bracket + elif current.is_pseudo: + current = current.previous_token + elif current.OpensScope(): + return current + current = current.previous_token + return None -def _LastTokenInLine( current ): - while not current.is_comment and current.next_token: - current = current.next_token - return current +def _LastTokenInLine(current): + while not current.is_comment and current.next_token: + current = current.next_token + return current -def _IsFunctionDefinition( current ): - prev = current.previous_token - return current.value == '(' and prev and subtypes.FUNC_DEF in prev.subtypes +def _IsFunctionDefinition(current): + prev = current.previous_token + return current.value == '(' and prev and subtypes.FUNC_DEF in prev.subtypes -def _IsLastScopeInLine( current ): - current = current.matching_bracket - while current: - current = current.next_token - if current and current.OpensScope(): - return False - return True +def _IsLastScopeInLine(current): + current = current.matching_bracket + while current: + current = current.next_token + if current and current.OpensScope(): + return False + return True -def _IsSingleElementTuple( token ): - """Check if it's a single-element tuple.""" - close = token.matching_bracket - token = token.next_token - num_commas = 0 - while token != close: - if token.value == ',': - num_commas += 1 - token = token.matching_bracket if token.OpensScope() else token.next_token - return num_commas == 1 +def _IsSingleElementTuple(token): + """Check if it's a single-element tuple.""" + close = token.matching_bracket + token = token.next_token + num_commas = 0 + while token != close: + if token.value == ',': + num_commas += 1 + token = token.matching_bracket if token.OpensScope() else token.next_token + return num_commas == 1 -def _ScopeHasNoCommas( token ): - """Check if the scope has no commas.""" - close = token.matching_bracket - token = token.next_token - while token != close: - if token.value == ',': - return False - token = token.matching_bracket if token.OpensScope() else token.next_token - return True +def _ScopeHasNoCommas(token): + """Check if the scope has no commas.""" + close = token.matching_bracket + token = token.next_token + while token != close: + if token.value == ',': + return False + token = token.matching_bracket if token.OpensScope() else token.next_token + return True -class _ParenState( object ): - """Maintains the state of the bracket enclosures. +class _ParenState(object): + """Maintains the state of the bracket enclosures. A stack of _ParenState objects are kept so that we know how to indent relative to the brackets. @@ -1217,34 +1210,34 @@ class _ParenState( object ): Each subsequent line split gets an increasing penalty. """ - # TODO(morbo): This doesn't track "bin packing." - - def __init__( self, indent, last_space ): - self.indent = indent - self.last_space = last_space - self.closing_scope_indent = 0 - self.split_before_closing_bracket = False - self.num_line_splits = 0 - - def Clone( self ): - state = _ParenState( self.indent, self.last_space ) - state.closing_scope_indent = self.closing_scope_indent - state.split_before_closing_bracket = self.split_before_closing_bracket - state.num_line_splits = self.num_line_splits - return state - - def __repr__( self ): - return '[indent::%d, last_space::%d, closing_scope_indent::%d]' % ( - self.indent, self.last_space, self.closing_scope_indent ) - - def __eq__( self, other ): - return hash( self ) == hash( other ) - - def __ne__( self, other ): - return not self == other - - def __hash__( self, *args, **kwargs ): - return hash( - ( - self.indent, self.last_space, self.closing_scope_indent, - self.split_before_closing_bracket, self.num_line_splits ) ) + # TODO(morbo): This doesn't track "bin packing." + + def __init__(self, indent, last_space): + self.indent = indent + self.last_space = last_space + self.closing_scope_indent = 0 + self.split_before_closing_bracket = False + self.num_line_splits = 0 + + def Clone(self): + state = _ParenState(self.indent, self.last_space) + state.closing_scope_indent = self.closing_scope_indent + state.split_before_closing_bracket = self.split_before_closing_bracket + state.num_line_splits = self.num_line_splits + return state + + def __repr__(self): + return '[indent::%d, last_space::%d, closing_scope_indent::%d]' % ( + self.indent, self.last_space, self.closing_scope_indent) + + def __eq__(self, other): + return hash(self) == hash(other) + + def __ne__(self, other): + return not self == other + + def __hash__(self, *args, **kwargs): + return hash( + ( + self.indent, self.last_space, self.closing_scope_indent, + self.split_before_closing_bracket, self.num_line_splits)) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 3dd570ef4..382f5f938 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -25,12 +25,12 @@ CONTINUATION = token.N_TOKENS -_OPENING_BRACKETS = frozenset( { '(', '[', '{' } ) -_CLOSING_BRACKETS = frozenset( { ')', ']', '}' } ) +_OPENING_BRACKETS = frozenset({'(', '[', '{'}) +_CLOSING_BRACKETS = frozenset({')', ']', '}'}) -def _TabbedContinuationAlignPadding( spaces, align_style, tab_width ): - """Build padding string for continuation alignment in tabbed indentation. +def _TabbedContinuationAlignPadding(spaces, align_style, tab_width): + """Build padding string for continuation alignment in tabbed indentation. Arguments: spaces: (int) The number of spaces to place before the token for alignment. @@ -40,15 +40,15 @@ def _TabbedContinuationAlignPadding( spaces, align_style, tab_width ): Returns: A padding string for alignment with style specified by align_style option. """ - if align_style in ( 'FIXED', 'VALIGN-RIGHT' ): - if spaces > 0: - return '\t' * int( ( spaces + tab_width - 1 ) / tab_width ) - return '' - return ' ' * spaces + if align_style in ('FIXED', 'VALIGN-RIGHT'): + if spaces > 0: + return '\t' * int((spaces + tab_width - 1) / tab_width) + return '' + return ' ' * spaces -class FormatToken( object ): - """Enhanced token information for formatting. +class FormatToken(object): + """Enhanced token information for formatting. This represents the token plus additional information useful for reformatting the code. @@ -83,57 +83,58 @@ class FormatToken( object ): newlines: The number of newlines needed before this token. """ - def __init__( self, node, name ): - """Constructor. + def __init__(self, node, name): + """Constructor. Arguments: node: (pytree.Leaf) The node that's being wrapped. name: (string) The name of the node. """ - self.node = node - self.name = name - self.type = node.type - self.column = node.column - self.lineno = node.lineno - self.value = node.value - - if self.is_continuation: - self.value = node.value.rstrip() - - self.next_token = None - self.previous_token = None - self.matching_bracket = None - self.parameters = [] - self.container_opening = None - self.container_elements = [] - self.whitespace_prefix = '' - self.total_length = 0 - self.split_penalty = 0 - self.can_break_before = False - self.must_break_before = pytree_utils.GetNodeAnnotation( - node, pytree_utils.Annotation.MUST_SPLIT, default = False ) - self.newlines = pytree_utils.GetNodeAnnotation( - node, pytree_utils.Annotation.NEWLINES ) - self.spaces_required_before = 0 - - if self.is_comment: - self.spaces_required_before = style.Get( 'SPACES_BEFORE_COMMENT' ) - - stypes = pytree_utils.GetNodeAnnotation( node, pytree_utils.Annotation.SUBTYPE ) - self.subtypes = { subtypes.NONE } if not stypes else stypes - self.is_pseudo = hasattr( node, 'is_pseudo' ) and node.is_pseudo - - @property - def formatted_whitespace_prefix( self ): - if style.Get( 'INDENT_BLANK_LINES' ): - without_newlines = self.whitespace_prefix.lstrip( '\n' ) - height = len( self.whitespace_prefix ) - len( without_newlines ) - if height: - return ( '\n' + without_newlines ) * height - return self.whitespace_prefix - - def AddWhitespacePrefix( self, newlines_before, spaces = 0, indent_level = 0 ): - """Register a token's whitespace prefix. + self.node = node + self.name = name + self.type = node.type + self.column = node.column + self.lineno = node.lineno + self.value = node.value + + if self.is_continuation: + self.value = node.value.rstrip() + + self.next_token = None + self.previous_token = None + self.matching_bracket = None + self.parameters = [] + self.container_opening = None + self.container_elements = [] + self.whitespace_prefix = '' + self.total_length = 0 + self.split_penalty = 0 + self.can_break_before = False + self.must_break_before = pytree_utils.GetNodeAnnotation( + node, pytree_utils.Annotation.MUST_SPLIT, default=False) + self.newlines = pytree_utils.GetNodeAnnotation( + node, pytree_utils.Annotation.NEWLINES) + self.spaces_required_before = 0 + + if self.is_comment: + self.spaces_required_before = style.Get('SPACES_BEFORE_COMMENT') + + stypes = pytree_utils.GetNodeAnnotation( + node, pytree_utils.Annotation.SUBTYPE) + self.subtypes = {subtypes.NONE} if not stypes else stypes + self.is_pseudo = hasattr(node, 'is_pseudo') and node.is_pseudo + + @property + def formatted_whitespace_prefix(self): + if style.Get('INDENT_BLANK_LINES'): + without_newlines = self.whitespace_prefix.lstrip('\n') + height = len(self.whitespace_prefix) - len(without_newlines) + if height: + return ('\n' + without_newlines) * height + return self.whitespace_prefix + + def AddWhitespacePrefix(self, newlines_before, spaces=0, indent_level=0): + """Register a token's whitespace prefix. This is the whitespace that will be output before a token's string. @@ -142,196 +143,196 @@ def AddWhitespacePrefix( self, newlines_before, spaces = 0, indent_level = 0 ): spaces: (int) The number of spaces to place before the token. indent_level: (int) The indentation level. """ - if style.Get( 'USE_TABS' ): - if newlines_before > 0: - indent_before = '\t' * indent_level + _TabbedContinuationAlignPadding( - spaces, style.Get( 'CONTINUATION_ALIGN_STYLE' ), - style.Get( 'INDENT_WIDTH' ) ) - else: - indent_before = '\t' * indent_level + ' ' * spaces - else: - indent_before = ( - ' ' * indent_level * style.Get( 'INDENT_WIDTH' ) + ' ' * spaces ) - - if self.is_comment: - comment_lines = [ s.lstrip() for s in self.value.splitlines() ] - self.value = ( '\n' + indent_before ).join( comment_lines ) - - # Update our own value since we are changing node value - self.value = self.value - - if not self.whitespace_prefix: - self.whitespace_prefix = ( - '\n' * ( self.newlines or newlines_before ) + indent_before ) - else: - self.whitespace_prefix += indent_before - - def AdjustNewlinesBefore( self, newlines_before ): - """Change the number of newlines before this token.""" - self.whitespace_prefix = ( - '\n' * newlines_before + self.whitespace_prefix.lstrip( '\n' ) ) - - def RetainHorizontalSpacing( self, first_column, depth ): - """Retains a token's horizontal spacing.""" - previous = self.previous_token - if not previous: - return - - if previous.is_pseudo: - previous = previous.previous_token - if not previous: - return - - cur_lineno = self.lineno - prev_lineno = previous.lineno - if previous.is_multiline_string: - prev_lineno += previous.value.count( '\n' ) - - if ( cur_lineno != prev_lineno or - ( previous.is_pseudo and previous.value != ')' and - cur_lineno != previous.previous_token.lineno ) ): - self.spaces_required_before = ( - self.column - first_column + depth * style.Get( 'INDENT_WIDTH' ) ) - return - - cur_column = self.column - prev_column = previous.column - prev_len = len( previous.value ) - - if previous.is_pseudo and previous.value == ')': - prev_column -= 1 - prev_len = 0 - - if previous.is_multiline_string: - prev_len = len( previous.value.split( '\n' )[ -1 ] ) - if '\n' in previous.value: - prev_column = 0 # Last line starts in column 0. - - self.spaces_required_before = cur_column - ( prev_column + prev_len ) - - def OpensScope( self ): - return self.value in _OPENING_BRACKETS - - def ClosesScope( self ): - return self.value in _CLOSING_BRACKETS - - def AddSubtype( self, subtype ): - self.subtypes.add( subtype ) - - def __repr__( self ): - msg = ( - 'FormatToken(name={0}, value={1}, column={2}, lineno={3}, ' - 'splitpenalty={4}'.format( - 'DOCSTRING' if self.is_docstring else self.name, self.value, - self.column, self.lineno, self.split_penalty ) ) - msg += ', pseudo)' if self.is_pseudo else ')' - return msg - - @property - def node_split_penalty( self ): - """Split penalty attached to the pytree node of this token.""" - return pytree_utils.GetNodeAnnotation( - self.node, pytree_utils.Annotation.SPLIT_PENALTY, default = 0 ) - - @property - def is_binary_op( self ): - """Token is a binary operator.""" - return subtypes.BINARY_OPERATOR in self.subtypes - - @property - @py3compat.lru_cache() - def is_arithmetic_op( self ): - """Token is an arithmetic operator.""" - return self.value in frozenset( - { - '+', # Add - '-', # Subtract - '*', # Multiply - '@', # Matrix Multiply - '/', # Divide - '//', # Floor Divide - '%', # Modulo - '<<', # Left Shift - '>>', # Right Shift - '|', # Bitwise Or - '&', # Bitwise Add - '^', # Bitwise Xor - '**', # Power - } ) - - @property - def is_simple_expr( self ): - """Token is an operator in a simple expression.""" - return subtypes.SIMPLE_EXPRESSION in self.subtypes - - @property - def is_subscript_colon( self ): - """Token is a subscript colon.""" - return subtypes.SUBSCRIPT_COLON in self.subtypes - - @property - def is_comment( self ): - return self.type == token.COMMENT - - @property - def is_continuation( self ): - return self.type == CONTINUATION - - @property - @py3compat.lru_cache() - def is_keyword( self ): - return keyword.iskeyword( self.value ) - - @property - def is_name( self ): - return self.type == token.NAME and not self.is_keyword - - @property - def is_number( self ): - return self.type == token.NUMBER - - @property - def is_string( self ): - return self.type == token.STRING - - @property - def is_multiline_string( self ): - """Test if this string is a multiline string. + if style.Get('USE_TABS'): + if newlines_before > 0: + indent_before = '\t' * indent_level + _TabbedContinuationAlignPadding( + spaces, style.Get('CONTINUATION_ALIGN_STYLE'), + style.Get('INDENT_WIDTH')) + else: + indent_before = '\t' * indent_level + ' ' * spaces + else: + indent_before = ( + ' ' * indent_level * style.Get('INDENT_WIDTH') + ' ' * spaces) + + if self.is_comment: + comment_lines = [s.lstrip() for s in self.value.splitlines()] + self.value = ('\n' + indent_before).join(comment_lines) + + # Update our own value since we are changing node value + self.value = self.value + + if not self.whitespace_prefix: + self.whitespace_prefix = ( + '\n' * (self.newlines or newlines_before) + indent_before) + else: + self.whitespace_prefix += indent_before + + def AdjustNewlinesBefore(self, newlines_before): + """Change the number of newlines before this token.""" + self.whitespace_prefix = ( + '\n' * newlines_before + self.whitespace_prefix.lstrip('\n')) + + def RetainHorizontalSpacing(self, first_column, depth): + """Retains a token's horizontal spacing.""" + previous = self.previous_token + if not previous: + return + + if previous.is_pseudo: + previous = previous.previous_token + if not previous: + return + + cur_lineno = self.lineno + prev_lineno = previous.lineno + if previous.is_multiline_string: + prev_lineno += previous.value.count('\n') + + if (cur_lineno != prev_lineno or + (previous.is_pseudo and previous.value != ')' and + cur_lineno != previous.previous_token.lineno)): + self.spaces_required_before = ( + self.column - first_column + depth * style.Get('INDENT_WIDTH')) + return + + cur_column = self.column + prev_column = previous.column + prev_len = len(previous.value) + + if previous.is_pseudo and previous.value == ')': + prev_column -= 1 + prev_len = 0 + + if previous.is_multiline_string: + prev_len = len(previous.value.split('\n')[-1]) + if '\n' in previous.value: + prev_column = 0 # Last line starts in column 0. + + self.spaces_required_before = cur_column - (prev_column + prev_len) + + def OpensScope(self): + return self.value in _OPENING_BRACKETS + + def ClosesScope(self): + return self.value in _CLOSING_BRACKETS + + def AddSubtype(self, subtype): + self.subtypes.add(subtype) + + def __repr__(self): + msg = ( + 'FormatToken(name={0}, value={1}, column={2}, lineno={3}, ' + 'splitpenalty={4}'.format( + 'DOCSTRING' if self.is_docstring else self.name, self.value, + self.column, self.lineno, self.split_penalty)) + msg += ', pseudo)' if self.is_pseudo else ')' + return msg + + @property + def node_split_penalty(self): + """Split penalty attached to the pytree node of this token.""" + return pytree_utils.GetNodeAnnotation( + self.node, pytree_utils.Annotation.SPLIT_PENALTY, default=0) + + @property + def is_binary_op(self): + """Token is a binary operator.""" + return subtypes.BINARY_OPERATOR in self.subtypes + + @property + @py3compat.lru_cache() + def is_arithmetic_op(self): + """Token is an arithmetic operator.""" + return self.value in frozenset( + { + '+', # Add + '-', # Subtract + '*', # Multiply + '@', # Matrix Multiply + '/', # Divide + '//', # Floor Divide + '%', # Modulo + '<<', # Left Shift + '>>', # Right Shift + '|', # Bitwise Or + '&', # Bitwise Add + '^', # Bitwise Xor + '**', # Power + }) + + @property + def is_simple_expr(self): + """Token is an operator in a simple expression.""" + return subtypes.SIMPLE_EXPRESSION in self.subtypes + + @property + def is_subscript_colon(self): + """Token is a subscript colon.""" + return subtypes.SUBSCRIPT_COLON in self.subtypes + + @property + def is_comment(self): + return self.type == token.COMMENT + + @property + def is_continuation(self): + return self.type == CONTINUATION + + @property + @py3compat.lru_cache() + def is_keyword(self): + return keyword.iskeyword(self.value) + + @property + def is_name(self): + return self.type == token.NAME and not self.is_keyword + + @property + def is_number(self): + return self.type == token.NUMBER + + @property + def is_string(self): + return self.type == token.STRING + + @property + def is_multiline_string(self): + """Test if this string is a multiline string. Returns: A multiline string always ends with triple quotes, so if it is a string token, inspect the last 3 characters and return True if it is a triple double or triple single quote mark. """ - return self.is_string and self.value.endswith( ( '"""', "'''" ) ) - - @property - def is_docstring( self ): - return self.is_string and self.previous_token is None - - @property - def is_pylint_comment( self ): - return self.is_comment and re.match( - r'#.*\bpylint:\s*(disable|enable)=', self.value ) - - @property - def is_pytype_comment( self ): - return self.is_comment and re.match( - r'#.*\bpytype:\s*(disable|enable)=', self.value ) - - @property - def is_copybara_comment( self ): - return self.is_comment and re.match( - r'#.*\bcopybara:\s*(strip|insert|replace)', self.value ) - - @property - def is_assign( self ): - return subtypes.ASSIGN_OPERATOR in self.subtypes - - @property - def is_augassign( self ): - augassigns = { - '+=', '-=', '*=', '@=', '/=', '%=', '&=', '|=', '^=', '<<=', '>>=', '**=', - '//=' - } - return self.value in augassigns + return self.is_string and self.value.endswith(('"""', "'''")) + + @property + def is_docstring(self): + return self.is_string and self.previous_token is None + + @property + def is_pylint_comment(self): + return self.is_comment and re.match( + r'#.*\bpylint:\s*(disable|enable)=', self.value) + + @property + def is_pytype_comment(self): + return self.is_comment and re.match( + r'#.*\bpytype:\s*(disable|enable)=', self.value) + + @property + def is_copybara_comment(self): + return self.is_comment and re.match( + r'#.*\bcopybara:\s*(strip|insert|replace)', self.value) + + @property + def is_assign(self): + return subtypes.ASSIGN_OPERATOR in self.subtypes + + @property + def is_augassign(self): + augassigns = { + '+=', '-=', '*=', '@=', '/=', '%=', '&=', '|=', '^=', '<<=', '>>=', + '**=', '//=' + } + return self.value in augassigns diff --git a/yapf/yapflib/identify_container.py b/yapf/yapflib/identify_container.py index 049694a77..d027cc5d4 100644 --- a/yapf/yapflib/identify_container.py +++ b/yapf/yapflib/identify_container.py @@ -25,45 +25,45 @@ from yapf.pytree import pytree_visitor -def IdentifyContainers( tree ): - """Run the identify containers visitor over the tree, modifying it in place. +def IdentifyContainers(tree): + """Run the identify containers visitor over the tree, modifying it in place. Arguments: tree: the top-level pytree node to annotate with subtypes. """ - identify_containers = _IdentifyContainers() - identify_containers.Visit( tree ) + identify_containers = _IdentifyContainers() + identify_containers.Visit(tree) -class _IdentifyContainers( pytree_visitor.PyTreeVisitor ): - """_IdentifyContainers - see file-level docstring for detailed description.""" +class _IdentifyContainers(pytree_visitor.PyTreeVisitor): + """_IdentifyContainers - see file-level docstring for detailed description.""" - def Visit_trailer( self, node ): # pylint: disable=invalid-name - for child in node.children: - self.Visit( child ) + def Visit_trailer(self, node): # pylint: disable=invalid-name + for child in node.children: + self.Visit(child) - if len( node.children ) != 3: - return - if node.children[ 0 ].type != grammar_token.LPAR: - return + if len(node.children) != 3: + return + if node.children[0].type != grammar_token.LPAR: + return - if pytree_utils.NodeName( node.children[ 1 ] ) == 'arglist': - for child in node.children[ 1 ].children: - pytree_utils.SetOpeningBracket( - pytree_utils.FirstLeafNode( child ), node.children[ 0 ] ) - else: - pytree_utils.SetOpeningBracket( - pytree_utils.FirstLeafNode( node.children[ 1 ] ), node.children[ 0 ] ) + if pytree_utils.NodeName(node.children[1]) == 'arglist': + for child in node.children[1].children: + pytree_utils.SetOpeningBracket( + pytree_utils.FirstLeafNode(child), node.children[0]) + else: + pytree_utils.SetOpeningBracket( + pytree_utils.FirstLeafNode(node.children[1]), node.children[0]) - def Visit_atom( self, node ): # pylint: disable=invalid-name - for child in node.children: - self.Visit( child ) + def Visit_atom(self, node): # pylint: disable=invalid-name + for child in node.children: + self.Visit(child) - if len( node.children ) != 3: - return - if node.children[ 0 ].type != grammar_token.LPAR: - return + if len(node.children) != 3: + return + if node.children[0].type != grammar_token.LPAR: + return - for child in node.children[ 1 ].children: - pytree_utils.SetOpeningBracket( - pytree_utils.FirstLeafNode( child ), node.children[ 0 ] ) + for child in node.children[1].children: + pytree_utils.SetOpeningBracket( + pytree_utils.FirstLeafNode(child), node.children[0]) diff --git a/yapf/yapflib/line_joiner.py b/yapf/yapflib/line_joiner.py index 8a2911397..f0acd2f37 100644 --- a/yapf/yapflib/line_joiner.py +++ b/yapf/yapflib/line_joiner.py @@ -36,11 +36,11 @@ from yapf.yapflib import style -_CLASS_OR_FUNC = frozenset( { 'def', 'class' } ) +_CLASS_OR_FUNC = frozenset({'def', 'class'}) -def CanMergeMultipleLines( lines, last_was_merged = False ): - """Determine if multiple lines can be joined into one. +def CanMergeMultipleLines(lines, last_was_merged=False): + """Determine if multiple lines can be joined into one. Arguments: lines: (list of LogicalLine) This is a splice of LogicalLines from the full @@ -51,39 +51,39 @@ def CanMergeMultipleLines( lines, last_was_merged = False ): True if two consecutive lines can be joined together. In reality, this will only happen if two consecutive lines can be joined, due to the style guide. """ - # The indentation amount for the starting line (number of spaces). - indent_amt = lines[ 0 ].depth * style.Get( 'INDENT_WIDTH' ) - if len( lines ) == 1 or indent_amt > style.Get( 'COLUMN_LIMIT' ): - return False - - if ( len( lines ) >= 3 and lines[ 2 ].depth >= lines[ 1 ].depth and - lines[ 0 ].depth != lines[ 2 ].depth ): - # If lines[2]'s depth is greater than or equal to line[1]'s depth, we're not - # looking at a single statement (e.g., if-then, while, etc.). A following - # line with the same depth as the first line isn't part of the lines we - # would want to combine. - return False # Don't merge more than two lines together. - - if lines[ 0 ].first.value in _CLASS_OR_FUNC: - # Don't join lines onto the starting line of a class or function. - return False - - limit = style.Get( 'COLUMN_LIMIT' ) - indent_amt - if lines[ 0 ].last.total_length < limit: - limit -= lines[ 0 ].last.total_length - - if lines[ 0 ].first.value == 'if': - return _CanMergeLineIntoIfStatement( lines, limit ) - if last_was_merged and lines[ 0 ].first.value in { 'elif', 'else' }: - return _CanMergeLineIntoIfStatement( lines, limit ) - - # TODO(morbo): Other control statements? + # The indentation amount for the starting line (number of spaces). + indent_amt = lines[0].depth * style.Get('INDENT_WIDTH') + if len(lines) == 1 or indent_amt > style.Get('COLUMN_LIMIT'): + return False + + if (len(lines) >= 3 and lines[2].depth >= lines[1].depth and + lines[0].depth != lines[2].depth): + # If lines[2]'s depth is greater than or equal to line[1]'s depth, we're not + # looking at a single statement (e.g., if-then, while, etc.). A following + # line with the same depth as the first line isn't part of the lines we + # would want to combine. + return False # Don't merge more than two lines together. + if lines[0].first.value in _CLASS_OR_FUNC: + # Don't join lines onto the starting line of a class or function. return False + limit = style.Get('COLUMN_LIMIT') - indent_amt + if lines[0].last.total_length < limit: + limit -= lines[0].last.total_length + + if lines[0].first.value == 'if': + return _CanMergeLineIntoIfStatement(lines, limit) + if last_was_merged and lines[0].first.value in {'elif', 'else'}: + return _CanMergeLineIntoIfStatement(lines, limit) + + # TODO(morbo): Other control statements? -def _CanMergeLineIntoIfStatement( lines, limit ): - """Determine if we can merge a short if-then statement into one line. + return False + + +def _CanMergeLineIntoIfStatement(lines, limit): + """Determine if we can merge a short if-then statement into one line. Two lines of an if-then statement can be merged if they were that way in the original source, fit on the line without going over the column limit, and are @@ -97,13 +97,13 @@ def _CanMergeLineIntoIfStatement( lines, limit ): Returns: True if the lines can be merged, False otherwise. """ - if len( lines[ 1 ].tokens ) == 1 and lines[ 1 ].last.is_multiline_string: - # This might be part of a multiline shebang. - return True - if lines[ 0 ].lineno != lines[ 1 ].lineno: - # Don't merge lines if the original lines weren't merged. - return False - if lines[ 1 ].last.total_length >= limit: - # Don't merge lines if the result goes over the column limit. - return False - return style.Get( 'JOIN_MULTIPLE_LINES' ) + if len(lines[1].tokens) == 1 and lines[1].last.is_multiline_string: + # This might be part of a multiline shebang. + return True + if lines[0].lineno != lines[1].lineno: + # Don't merge lines if the original lines weren't merged. + return False + if lines[1].last.total_length >= limit: + # Don't merge lines if the result goes over the column limit. + return False + return style.Get('JOIN_MULTIPLE_LINES') diff --git a/yapf/yapflib/logical_line.py b/yapf/yapflib/logical_line.py index b02e3588b..477d4d625 100644 --- a/yapf/yapflib/logical_line.py +++ b/yapf/yapflib/logical_line.py @@ -29,8 +29,8 @@ from lib2to3.fixer_util import syms as python_symbols -class LogicalLine( object ): - """Represents a single logical line in the output. +class LogicalLine(object): + """Represents a single logical line in the output. Attributes: depth: indentation depth of this line. This is just a numeric value used to @@ -38,8 +38,8 @@ class LogicalLine( object ): actual amount of spaces, which is style-dependent. """ - def __init__( self, depth, tokens = None ): - """Constructor. + def __init__(self, depth, tokens=None): + """Constructor. Creates a new logical line with the given depth an initial list of tokens. Constructs the doubly-linked lists for format tokens using their built-in @@ -49,108 +49,108 @@ def __init__( self, depth, tokens = None ): depth: indentation depth of this line tokens: initial list of tokens """ - self.depth = depth - self._tokens = tokens or [] - self.disable = False - - if self._tokens: - # Set up a doubly linked list. - for index, tok in enumerate( self._tokens[ 1 : ] ): - # Note, 'index' is the index to the previous token. - tok.previous_token = self._tokens[ index ] - self._tokens[ index ].next_token = tok - - def CalculateFormattingInformation( self ): - """Calculate the split penalty and total length for the tokens.""" - # Say that the first token in the line should have a space before it. This - # means only that if this logical line is joined with a predecessor line, - # then there will be a space between them. - self.first.spaces_required_before = 1 - self.first.total_length = len( self.first.value ) - - prev_token = self.first - prev_length = self.first.total_length - for token in self._tokens[ 1 : ]: - if ( token.spaces_required_before == 0 and - _SpaceRequiredBetween( prev_token, token, self.disable ) ): - token.spaces_required_before = 1 - - tok_len = len( token.value ) if not token.is_pseudo else 0 - - spaces_required_before = token.spaces_required_before - if isinstance( spaces_required_before, list ): - assert token.is_comment, token - - # If here, we are looking at a comment token that appears on a line - # with other tokens (but because it is a comment, it is always the last - # token). Rather than specifying the actual number of spaces here, - # hard code a value of 0 and then set it later. This logic only works - # because this comment token is guaranteed to be the last token in the - # list. - spaces_required_before = 0 - - token.total_length = prev_length + tok_len + spaces_required_before - - # The split penalty has to be computed before {must|can}_break_before, - # because these may use it for their decision. - token.split_penalty += _SplitPenalty( prev_token, token ) - token.must_break_before = _MustBreakBefore( prev_token, token ) - token.can_break_before = ( - token.must_break_before or _CanBreakBefore( prev_token, token ) ) - - prev_length = token.total_length - prev_token = token - - def Split( self ): - """Split the line at semicolons.""" - if not self.has_semicolon or self.disable: - return [ self ] - - llines = [] - lline = LogicalLine( self.depth ) - for tok in self._tokens: - if tok.value == ';': - llines.append( lline ) - lline = LogicalLine( self.depth ) - else: - lline.AppendToken( tok ) - - if lline.tokens: - llines.append( lline ) - - for lline in llines: - lline.first.previous_token = None - lline.last.next_token = None - - return llines - - ############################################################################ - # Token Access and Manipulation Methods # - ############################################################################ - - def AppendToken( self, token ): - """Append a new FormatToken to the tokens contained in this line.""" - if self._tokens: - token.previous_token = self.last - self.last.next_token = token - self._tokens.append( token ) - - @property - def first( self ): - """Returns the first non-whitespace token.""" - return self._tokens[ 0 ] - - @property - def last( self ): - """Returns the last non-whitespace token.""" - return self._tokens[ -1 ] - - ############################################################################ - # Token -> String Methods # - ############################################################################ - - def AsCode( self, indent_per_depth = 2 ): - """Return a "code" representation of this line. + self.depth = depth + self._tokens = tokens or [] + self.disable = False + + if self._tokens: + # Set up a doubly linked list. + for index, tok in enumerate(self._tokens[1:]): + # Note, 'index' is the index to the previous token. + tok.previous_token = self._tokens[index] + self._tokens[index].next_token = tok + + def CalculateFormattingInformation(self): + """Calculate the split penalty and total length for the tokens.""" + # Say that the first token in the line should have a space before it. This + # means only that if this logical line is joined with a predecessor line, + # then there will be a space between them. + self.first.spaces_required_before = 1 + self.first.total_length = len(self.first.value) + + prev_token = self.first + prev_length = self.first.total_length + for token in self._tokens[1:]: + if (token.spaces_required_before == 0 and + _SpaceRequiredBetween(prev_token, token, self.disable)): + token.spaces_required_before = 1 + + tok_len = len(token.value) if not token.is_pseudo else 0 + + spaces_required_before = token.spaces_required_before + if isinstance(spaces_required_before, list): + assert token.is_comment, token + + # If here, we are looking at a comment token that appears on a line + # with other tokens (but because it is a comment, it is always the last + # token). Rather than specifying the actual number of spaces here, + # hard code a value of 0 and then set it later. This logic only works + # because this comment token is guaranteed to be the last token in the + # list. + spaces_required_before = 0 + + token.total_length = prev_length + tok_len + spaces_required_before + + # The split penalty has to be computed before {must|can}_break_before, + # because these may use it for their decision. + token.split_penalty += _SplitPenalty(prev_token, token) + token.must_break_before = _MustBreakBefore(prev_token, token) + token.can_break_before = ( + token.must_break_before or _CanBreakBefore(prev_token, token)) + + prev_length = token.total_length + prev_token = token + + def Split(self): + """Split the line at semicolons.""" + if not self.has_semicolon or self.disable: + return [self] + + llines = [] + lline = LogicalLine(self.depth) + for tok in self._tokens: + if tok.value == ';': + llines.append(lline) + lline = LogicalLine(self.depth) + else: + lline.AppendToken(tok) + + if lline.tokens: + llines.append(lline) + + for lline in llines: + lline.first.previous_token = None + lline.last.next_token = None + + return llines + + ############################################################################ + # Token Access and Manipulation Methods # + ############################################################################ + + def AppendToken(self, token): + """Append a new FormatToken to the tokens contained in this line.""" + if self._tokens: + token.previous_token = self.last + self.last.next_token = token + self._tokens.append(token) + + @property + def first(self): + """Returns the first non-whitespace token.""" + return self._tokens[0] + + @property + def last(self): + """Returns the last non-whitespace token.""" + return self._tokens[-1] + + ############################################################################ + # Token -> String Methods # + ############################################################################ + + def AsCode(self, indent_per_depth=2): + """Return a "code" representation of this line. The code representation shows how the line would be printed out as code. @@ -164,518 +164,516 @@ def AsCode( self, indent_per_depth = 2 ): Returns: A string representing the line as code. """ - indent = ' ' * indent_per_depth * self.depth - tokens_str = ' '.join( tok.value for tok in self._tokens ) - return indent + tokens_str + indent = ' ' * indent_per_depth * self.depth + tokens_str = ' '.join(tok.value for tok in self._tokens) + return indent + tokens_str - def __str__( self ): # pragma: no cover - return self.AsCode() + def __str__(self): # pragma: no cover + return self.AsCode() - def __repr__( self ): # pragma: no cover - tokens_repr = ','.join( - '{0}({1!r})'.format( tok.name, tok.value ) for tok in self._tokens ) - return 'LogicalLine(depth={0}, tokens=[{1}])'.format( self.depth, tokens_repr ) + def __repr__(self): # pragma: no cover + tokens_repr = ','.join( + '{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens) + return 'LogicalLine(depth={0}, tokens=[{1}])'.format( + self.depth, tokens_repr) - ############################################################################ - # Properties # - ############################################################################ + ############################################################################ + # Properties # + ############################################################################ - @property - def tokens( self ): - """Access the tokens contained within this line. + @property + def tokens(self): + """Access the tokens contained within this line. The caller must not modify the tokens list returned by this method. Returns: List of tokens in this line. """ - return self._tokens + return self._tokens - @property - def lineno( self ): - """Return the line number of this logical line. + @property + def lineno(self): + """Return the line number of this logical line. Returns: The line number of the first token in this logical line. """ - return self.first.lineno + return self.first.lineno - @property - def start( self ): - """The start of the logical line. + @property + def start(self): + """The start of the logical line. Returns: A tuple of the starting line number and column. """ - return ( self.first.lineno, self.first.column ) + return (self.first.lineno, self.first.column) - @property - def end( self ): - """The end of the logical line. + @property + def end(self): + """The end of the logical line. Returns: A tuple of the ending line number and column. """ - return ( self.last.lineno, self.last.column + len( self.last.value ) ) + return (self.last.lineno, self.last.column + len(self.last.value)) - @property - def is_comment( self ): - return self.first.is_comment + @property + def is_comment(self): + return self.first.is_comment - @property - def has_semicolon( self ): - return any( tok.value == ';' for tok in self._tokens ) + @property + def has_semicolon(self): + return any(tok.value == ';' for tok in self._tokens) -def _IsIdNumberStringToken( tok ): - return tok.is_keyword or tok.is_name or tok.is_number or tok.is_string +def _IsIdNumberStringToken(tok): + return tok.is_keyword or tok.is_name or tok.is_number or tok.is_string -def _IsUnaryOperator( tok ): - return subtypes.UNARY_OPERATOR in tok.subtypes +def _IsUnaryOperator(tok): + return subtypes.UNARY_OPERATOR in tok.subtypes -def _HasPrecedence( tok ): - """Whether a binary operation has precedence within its context.""" - node = tok.node +def _HasPrecedence(tok): + """Whether a binary operation has precedence within its context.""" + node = tok.node - # We let ancestor be the statement surrounding the operation that tok is the - # operator in. - ancestor = node.parent.parent + # We let ancestor be the statement surrounding the operation that tok is the + # operator in. + ancestor = node.parent.parent - while ancestor is not None: - # Search through the ancestor nodes in the parse tree for operators with - # lower precedence. - predecessor_type = pytree_utils.NodeName( ancestor ) - if predecessor_type in [ 'arith_expr', 'term' ]: - # An ancestor "arith_expr" or "term" means we have found an operator - # with lower precedence than our tok. - return True - if predecessor_type != 'atom': - # We understand the context to look for precedence within as an - # arbitrary nesting of "arith_expr", "term", and "atom" nodes. If we - # leave this context we have not found a lower precedence operator. - return False - # Under normal usage we expect a complete parse tree to be available and - # we will return before we get an AttributeError from the root. - ancestor = ancestor.parent + while ancestor is not None: + # Search through the ancestor nodes in the parse tree for operators with + # lower precedence. + predecessor_type = pytree_utils.NodeName(ancestor) + if predecessor_type in ['arith_expr', 'term']: + # An ancestor "arith_expr" or "term" means we have found an operator + # with lower precedence than our tok. + return True + if predecessor_type != 'atom': + # We understand the context to look for precedence within as an + # arbitrary nesting of "arith_expr", "term", and "atom" nodes. If we + # leave this context we have not found a lower precedence operator. + return False + # Under normal usage we expect a complete parse tree to be available and + # we will return before we get an AttributeError from the root. + ancestor = ancestor.parent -def _PriorityIndicatingNoSpace( tok ): - """Whether to remove spaces around an operator due to precedence.""" - if not tok.is_arithmetic_op or not tok.is_simple_expr: - # Limit space removal to highest priority arithmetic operators - return False - return _HasPrecedence( tok ) +def _PriorityIndicatingNoSpace(tok): + """Whether to remove spaces around an operator due to precedence.""" + if not tok.is_arithmetic_op or not tok.is_simple_expr: + # Limit space removal to highest priority arithmetic operators + return False + return _HasPrecedence(tok) -def _IsSubscriptColonAndValuePair( token1, token2 ): - return ( token1.is_number or token1.is_name ) and token2.is_subscript_colon +def _IsSubscriptColonAndValuePair(token1, token2): + return (token1.is_number or token1.is_name) and token2.is_subscript_colon -def _SpaceRequiredBetween( left, right, is_line_disabled ): - """Return True if a space is required between the left and right token.""" - lval = left.value - rval = right.value - if ( left.is_pseudo and _IsIdNumberStringToken( right ) and left.previous_token and - _IsIdNumberStringToken( left.previous_token ) ): - # Space between keyword... tokens and pseudo parens. - return True - if left.is_pseudo or right.is_pseudo: - # There should be a space after the ':' in a dictionary. - if left.OpensScope(): - return True - # The closing pseudo-paren shouldn't affect spacing. - return False - if left.is_continuation or right.is_continuation: - # The continuation node's value has all of the spaces it needs. - return False - if right.name in pytree_utils.NONSEMANTIC_TOKENS: - # No space before a non-semantic token. - return False - if _IsIdNumberStringToken( left ) and _IsIdNumberStringToken( right ): - # Spaces between keyword, string, number, and identifier tokens. - return True - if lval == ',' and rval == ':': - # We do want a space between a comma and colon. - return True - if style.Get( 'SPACE_INSIDE_BRACKETS' ): - # Supersede the "no space before a colon or comma" check. - if left.OpensScope() and rval == ':': - return True - if right.ClosesScope() and lval == ':': - return True - if ( style.Get( 'SPACES_AROUND_SUBSCRIPT_COLON' ) and - ( _IsSubscriptColonAndValuePair( left, right ) or - _IsSubscriptColonAndValuePair( right, left ) ) ): - # Supersede the "never want a space before a colon or comma" check. - return True - if rval in ':,': - # Otherwise, we never want a space before a colon or comma. - return False - if lval == ',' and rval in ']})': - # Add a space between ending ',' and closing bracket if requested. - return style.Get( 'SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET' ) - if lval == ',': - # We want a space after a comma. - return True - if lval == 'from' and rval == '.': - # Space before the '.' in an import statement. - return True - if lval == '.' and rval == 'import': - # Space after the '.' in an import statement. - return True - if ( lval == '=' and rval in { '.', ',,,' } and - subtypes.DEFAULT_OR_NAMED_ASSIGN not in left.subtypes ): - # Space between equal and '.' as in "X = ...". - return True - if lval == ':' and rval in { '.', '...' }: - # Space between : and ... - return True - if ( ( right.is_keyword or right.is_name ) and - ( left.is_keyword or left.is_name ) ): - # Don't merge two keywords/identifiers. - return True - if ( subtypes.SUBSCRIPT_COLON in left.subtypes or - subtypes.SUBSCRIPT_COLON in right.subtypes ): - # A subscript shouldn't have spaces separating its colons. - return False - if ( subtypes.TYPED_NAME in left.subtypes or - subtypes.TYPED_NAME in right.subtypes ): - # A typed argument should have a space after the colon. - return True - if left.is_string: - if ( rval == '=' and - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in right.subtypes ): - # If there is a type hint, then we don't want to add a space between the - # equal sign and the hint. - return False - if rval not in '[)]}.' and not right.is_binary_op: - # A string followed by something other than a subscript, closing bracket, - # dot, or a binary op should have a space after it. - return True - if right.ClosesScope(): - # A string followed by closing brackets should have a space after it - # depending on SPACE_INSIDE_BRACKETS. A string followed by opening - # brackets, however, should not. - return style.Get( 'SPACE_INSIDE_BRACKETS' ) - if subtypes.SUBSCRIPT_BRACKET in right.subtypes: - # It's legal to do this in Python: 'hello'[a] - return False - if left.is_binary_op and lval != '**' and _IsUnaryOperator( right ): - # Space between the binary operator and the unary operator. - return True - if left.is_keyword and _IsUnaryOperator( right ): - # Handle things like "not -3 < x". - return True - if _IsUnaryOperator( left ) and _IsUnaryOperator( right ): - # No space between two unary operators. - return False - if left.is_binary_op or right.is_binary_op: - if lval == '**' or rval == '**': - # Space around the "power" operator. - return style.Get( 'SPACES_AROUND_POWER_OPERATOR' ) - # Enforce spaces around binary operators except the blocked ones. - block_list = style.Get( 'NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS' ) - if lval in block_list or rval in block_list: - return False - if style.Get( 'ARITHMETIC_PRECEDENCE_INDICATION' ): - if _PriorityIndicatingNoSpace( left ) or _PriorityIndicatingNoSpace( - right ): - return False - else: - return True - else: - return True - if ( _IsUnaryOperator( left ) and lval != 'not' and - ( right.is_name or right.is_number or rval == '(' ) ): - # The previous token was a unary op. No space is desired between it and - # the current token. - return False - if ( subtypes.DEFAULT_OR_NAMED_ASSIGN in left.subtypes and - subtypes.TYPED_NAME not in right.subtypes ): - # A named argument or default parameter shouldn't have spaces around it. - return style.Get( 'SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN' ) - if ( subtypes.DEFAULT_OR_NAMED_ASSIGN in right.subtypes and - subtypes.TYPED_NAME not in left.subtypes ): - # A named argument or default parameter shouldn't have spaces around it. - return style.Get( 'SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN' ) - if ( subtypes.VARARGS_LIST in left.subtypes or - subtypes.VARARGS_LIST in right.subtypes ): - return False - if ( subtypes.VARARGS_STAR in left.subtypes or - subtypes.KWARGS_STAR_STAR in left.subtypes ): - # Don't add a space after a vararg's star or a keyword's star-star. - return False - if lval == '@' and subtypes.DECORATOR in left.subtypes: - # Decorators shouldn't be separated from the 'at' sign. - return False - if left.is_keyword and rval == '.': - # Add space between keywords and dots. - return lval not in { 'None', 'print' } - if lval == '.' and right.is_keyword: - # Add space between keywords and dots. - return rval not in { 'None', 'print' } - if lval == '.' or rval == '.': - # Don't place spaces between dots. - return False - if ( ( lval == '(' and rval == ')' ) or ( lval == '[' and rval == ']' ) or - ( lval == '{' and rval == '}' ) ): - # Empty objects shouldn't be separated by spaces. - return False - if not is_line_disabled and ( left.OpensScope() or right.ClosesScope() ): - if ( style.GetOrDefault( 'SPACES_AROUND_DICT_DELIMITERS', False ) and - ( ( lval == '{' and - _IsDictListTupleDelimiterTok( left, is_opening = True ) ) or - ( rval == '}' and - _IsDictListTupleDelimiterTok( right, is_opening = False ) ) ) ): - return True - if ( style.GetOrDefault( 'SPACES_AROUND_LIST_DELIMITERS', False ) and - ( ( lval == '[' and - _IsDictListTupleDelimiterTok( left, is_opening = True ) ) or - ( rval == ']' and - _IsDictListTupleDelimiterTok( right, is_opening = False ) ) ) ): - return True - if ( style.GetOrDefault( 'SPACES_AROUND_TUPLE_DELIMITERS', False ) and - ( ( lval == '(' and - _IsDictListTupleDelimiterTok( left, is_opening = True ) ) or - ( rval == ')' and - _IsDictListTupleDelimiterTok( right, is_opening = False ) ) ) ): - return True - if left.OpensScope() and right.OpensScope(): - # Nested objects' opening brackets shouldn't be separated, unless enabled - # by SPACE_INSIDE_BRACKETS. - return style.Get( 'SPACE_INSIDE_BRACKETS' ) - if left.ClosesScope() and right.ClosesScope(): - # Nested objects' closing brackets shouldn't be separated, unless enabled - # by SPACE_INSIDE_BRACKETS. - return style.Get( 'SPACE_INSIDE_BRACKETS' ) - if left.ClosesScope() and rval in '([': - # A call, set, dictionary, or subscript that has a call or subscript after - # it shouldn't have a space between them. - return False - if left.OpensScope() and _IsIdNumberStringToken( right ): - # Don't separate the opening bracket from the first item, unless enabled - # by SPACE_INSIDE_BRACKETS. - return style.Get( 'SPACE_INSIDE_BRACKETS' ) - if left.is_name and rval in '([': - # Don't separate a call or array access from the name. - return False +def _SpaceRequiredBetween(left, right, is_line_disabled): + """Return True if a space is required between the left and right token.""" + lval = left.value + rval = right.value + if (left.is_pseudo and _IsIdNumberStringToken(right) and + left.previous_token and _IsIdNumberStringToken(left.previous_token)): + # Space between keyword... tokens and pseudo parens. + return True + if left.is_pseudo or right.is_pseudo: + # There should be a space after the ':' in a dictionary. + if left.OpensScope(): + return True + # The closing pseudo-paren shouldn't affect spacing. + return False + if left.is_continuation or right.is_continuation: + # The continuation node's value has all of the spaces it needs. + return False + if right.name in pytree_utils.NONSEMANTIC_TOKENS: + # No space before a non-semantic token. + return False + if _IsIdNumberStringToken(left) and _IsIdNumberStringToken(right): + # Spaces between keyword, string, number, and identifier tokens. + return True + if lval == ',' and rval == ':': + # We do want a space between a comma and colon. + return True + if style.Get('SPACE_INSIDE_BRACKETS'): + # Supersede the "no space before a colon or comma" check. + if left.OpensScope() and rval == ':': + return True + if right.ClosesScope() and lval == ':': + return True + if (style.Get('SPACES_AROUND_SUBSCRIPT_COLON') and + (_IsSubscriptColonAndValuePair(left, right) or + _IsSubscriptColonAndValuePair(right, left))): + # Supersede the "never want a space before a colon or comma" check. + return True + if rval in ':,': + # Otherwise, we never want a space before a colon or comma. + return False + if lval == ',' and rval in ']})': + # Add a space between ending ',' and closing bracket if requested. + return style.Get('SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET') + if lval == ',': + # We want a space after a comma. + return True + if lval == 'from' and rval == '.': + # Space before the '.' in an import statement. + return True + if lval == '.' and rval == 'import': + # Space after the '.' in an import statement. + return True + if (lval == '=' and rval in {'.', ',,,'} and + subtypes.DEFAULT_OR_NAMED_ASSIGN not in left.subtypes): + # Space between equal and '.' as in "X = ...". + return True + if lval == ':' and rval in {'.', '...'}: + # Space between : and ... + return True + if ((right.is_keyword or right.is_name) and + (left.is_keyword or left.is_name)): + # Don't merge two keywords/identifiers. + return True + if (subtypes.SUBSCRIPT_COLON in left.subtypes or + subtypes.SUBSCRIPT_COLON in right.subtypes): + # A subscript shouldn't have spaces separating its colons. + return False + if (subtypes.TYPED_NAME in left.subtypes or + subtypes.TYPED_NAME in right.subtypes): + # A typed argument should have a space after the colon. + return True + if left.is_string: + if (rval == '=' and + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in right.subtypes): + # If there is a type hint, then we don't want to add a space between the + # equal sign and the hint. + return False + if rval not in '[)]}.' and not right.is_binary_op: + # A string followed by something other than a subscript, closing bracket, + # dot, or a binary op should have a space after it. + return True if right.ClosesScope(): - # Don't separate the closing bracket from the last item, unless enabled - # by SPACE_INSIDE_BRACKETS. - # FIXME(morbo): This might be too permissive. - return style.Get( 'SPACE_INSIDE_BRACKETS' ) - if lval == 'print' and rval == '(': - # Special support for the 'print' function. - return False - if left.OpensScope() and _IsUnaryOperator( right ): - # Don't separate a unary operator from the opening bracket, unless enabled - # by SPACE_INSIDE_BRACKETS. - return style.Get( 'SPACE_INSIDE_BRACKETS' ) - if ( left.OpensScope() and ( subtypes.VARARGS_STAR in right.subtypes or - subtypes.KWARGS_STAR_STAR in right.subtypes ) ): - # Don't separate a '*' or '**' from the opening bracket, unless enabled - # by SPACE_INSIDE_BRACKETS. - return style.Get( 'SPACE_INSIDE_BRACKETS' ) - if rval == ';': - # Avoid spaces before a semicolon. (Why is there a semicolon?!) - return False - if lval == '(' and rval == 'await': - # Special support for the 'await' keyword. Don't separate the 'await' - # keyword from an opening paren, unless enabled by SPACE_INSIDE_BRACKETS. - return style.Get( 'SPACE_INSIDE_BRACKETS' ) + # A string followed by closing brackets should have a space after it + # depending on SPACE_INSIDE_BRACKETS. A string followed by opening + # brackets, however, should not. + return style.Get('SPACE_INSIDE_BRACKETS') + if subtypes.SUBSCRIPT_BRACKET in right.subtypes: + # It's legal to do this in Python: 'hello'[a] + return False + if left.is_binary_op and lval != '**' and _IsUnaryOperator(right): + # Space between the binary operator and the unary operator. return True - - -def _MustBreakBefore( prev_token, cur_token ): - """Return True if a line break is required before the current token.""" - if prev_token.is_comment or ( prev_token.previous_token and prev_token.is_pseudo and - prev_token.previous_token.is_comment ): - # Must break if the previous token was a comment. - return True - if ( cur_token.is_string and prev_token.is_string and - IsSurroundedByBrackets( cur_token ) ): - # We want consecutive strings to be on separate lines. This is a - # reasonable assumption, because otherwise they should have written them - # all on the same line, or with a '+'. - return True - return cur_token.must_break_before - - -def _CanBreakBefore( prev_token, cur_token ): - """Return True if a line break may occur before the current token.""" - pval = prev_token.value - cval = cur_token.value - if py3compat.PY3: - if pval == 'yield' and cval == 'from': - # Don't break before a yield argument. - return False - if pval in { 'async', 'await' } and cval in { 'def', 'with', 'for' }: - # Don't break after sync keywords. - return False - if cur_token.split_penalty >= split_penalty.UNBREAKABLE: - return False - if pval == '@': - # Don't break right after the beginning of a decorator. - return False - if cval == ':': - # Don't break before the start of a block of code. - return False - if cval == ',': - # Don't break before a comma. - return False - if prev_token.is_name and cval == '(': - # Don't break in the middle of a function definition or call. - return False - if prev_token.is_name and cval == '[': - # Don't break in the middle of an array dereference. - return False - if cur_token.is_comment and prev_token.lineno == cur_token.lineno: - # Don't break a comment at the end of the line. - return False - if subtypes.UNARY_OPERATOR in prev_token.subtypes: - # Don't break after a unary token. - return False - if not style.Get( 'ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS' ): - if ( subtypes.DEFAULT_OR_NAMED_ASSIGN in cur_token.subtypes or - subtypes.DEFAULT_OR_NAMED_ASSIGN in prev_token.subtypes ): - return False + if left.is_keyword and _IsUnaryOperator(right): + # Handle things like "not -3 < x". return True - - -def IsSurroundedByBrackets( tok ): - """Return True if the token is surrounded by brackets.""" - paren_count = 0 - brace_count = 0 - sq_bracket_count = 0 - previous_token = tok.previous_token - while previous_token: - if previous_token.value == ')': - paren_count -= 1 - elif previous_token.value == '}': - brace_count -= 1 - elif previous_token.value == ']': - sq_bracket_count -= 1 - - if previous_token.value == '(': - if paren_count == 0: - return previous_token - paren_count += 1 - elif previous_token.value == '{': - if brace_count == 0: - return previous_token - brace_count += 1 - elif previous_token.value == '[': - if sq_bracket_count == 0: - return previous_token - sq_bracket_count += 1 - - previous_token = previous_token.previous_token - return None - - -def _IsDictListTupleDelimiterTok( tok, is_opening ): - assert tok - - if tok.matching_bracket is None: - return False - - if is_opening: - open_tok = tok - close_tok = tok.matching_bracket - else: - open_tok = tok.matching_bracket - close_tok = tok - - # There must be something in between the tokens - if open_tok.next_token == close_tok: + if _IsUnaryOperator(left) and _IsUnaryOperator(right): + # No space between two unary operators. + return False + if left.is_binary_op or right.is_binary_op: + if lval == '**' or rval == '**': + # Space around the "power" operator. + return style.Get('SPACES_AROUND_POWER_OPERATOR') + # Enforce spaces around binary operators except the blocked ones. + block_list = style.Get('NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS') + if lval in block_list or rval in block_list: + return False + if style.Get('ARITHMETIC_PRECEDENCE_INDICATION'): + if _PriorityIndicatingNoSpace(left) or _PriorityIndicatingNoSpace(right): return False - - assert open_tok.next_token.node - assert open_tok.next_token.node.parent - - return open_tok.next_token.node.parent.type in [ - python_symbols.dictsetmaker, - python_symbols.listmaker, - python_symbols.testlist_gexp, - ] - - -_LOGICAL_OPERATORS = frozenset( { 'and', 'or' } ) -_BITWISE_OPERATORS = frozenset( { '&', '|', '^' } ) -_ARITHMETIC_OPERATORS = frozenset( { '+', '-', '*', '/', '%', '//', '@' } ) - - -def _SplitPenalty( prev_token, cur_token ): - """Return the penalty for breaking the line before the current token.""" - pval = prev_token.value - cval = cur_token.value - if pval == 'not': - return split_penalty.UNBREAKABLE - - if cur_token.node_split_penalty > 0: - return cur_token.node_split_penalty - - if style.Get( 'SPLIT_BEFORE_LOGICAL_OPERATOR' ): - # Prefer to split before 'and' and 'or'. - if pval in _LOGICAL_OPERATORS: - return style.Get( 'SPLIT_PENALTY_LOGICAL_OPERATOR' ) - if cval in _LOGICAL_OPERATORS: - return 0 - else: - # Prefer to split after 'and' and 'or'. - if pval in _LOGICAL_OPERATORS: - return 0 - if cval in _LOGICAL_OPERATORS: - return style.Get( 'SPLIT_PENALTY_LOGICAL_OPERATOR' ) - - if style.Get( 'SPLIT_BEFORE_BITWISE_OPERATOR' ): - # Prefer to split before '&', '|', and '^'. - if pval in _BITWISE_OPERATORS: - return style.Get( 'SPLIT_PENALTY_BITWISE_OPERATOR' ) - if cval in _BITWISE_OPERATORS: - return 0 + else: + return True else: - # Prefer to split after '&', '|', and '^'. - if pval in _BITWISE_OPERATORS: - return 0 - if cval in _BITWISE_OPERATORS: - return style.Get( 'SPLIT_PENALTY_BITWISE_OPERATOR' ) - - if ( subtypes.COMP_FOR in cur_token.subtypes or - subtypes.COMP_IF in cur_token.subtypes ): - # We don't mind breaking before the 'for' or 'if' of a list comprehension. - return 0 - if subtypes.UNARY_OPERATOR in prev_token.subtypes: - # Try not to break after a unary operator. - return style.Get( 'SPLIT_PENALTY_AFTER_UNARY_OPERATOR' ) - if pval == ',': - # Breaking after a comma is fine, if need be. - return 0 - if pval == '**' or cval == '**': - return split_penalty.STRONGLY_CONNECTED - if ( subtypes.VARARGS_STAR in prev_token.subtypes or - subtypes.KWARGS_STAR_STAR in prev_token.subtypes ): - # Don't split after a varargs * or kwargs **. - return split_penalty.UNBREAKABLE - if prev_token.OpensScope() and cval != '(': - # Slightly prefer - return style.Get( 'SPLIT_PENALTY_AFTER_OPENING_BRACKET' ) - if cval == ':': - # Don't split before a colon. - return split_penalty.UNBREAKABLE - if cval == '=': - # Don't split before an assignment. - return split_penalty.UNBREAKABLE - if ( subtypes.DEFAULT_OR_NAMED_ASSIGN in prev_token.subtypes or - subtypes.DEFAULT_OR_NAMED_ASSIGN in cur_token.subtypes ): - # Don't break before or after an default or named assignment. - return split_penalty.UNBREAKABLE - if cval == '==': - # We would rather not split before an equality operator. - return split_penalty.STRONGLY_CONNECTED - if cur_token.ClosesScope(): - # Give a slight penalty for splitting before the closing scope. - return 100 + return True + if (_IsUnaryOperator(left) and lval != 'not' and + (right.is_name or right.is_number or rval == '(')): + # The previous token was a unary op. No space is desired between it and + # the current token. + return False + if (subtypes.DEFAULT_OR_NAMED_ASSIGN in left.subtypes and + subtypes.TYPED_NAME not in right.subtypes): + # A named argument or default parameter shouldn't have spaces around it. + return style.Get('SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN') + if (subtypes.DEFAULT_OR_NAMED_ASSIGN in right.subtypes and + subtypes.TYPED_NAME not in left.subtypes): + # A named argument or default parameter shouldn't have spaces around it. + return style.Get('SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN') + if (subtypes.VARARGS_LIST in left.subtypes or + subtypes.VARARGS_LIST in right.subtypes): + return False + if (subtypes.VARARGS_STAR in left.subtypes or + subtypes.KWARGS_STAR_STAR in left.subtypes): + # Don't add a space after a vararg's star or a keyword's star-star. + return False + if lval == '@' and subtypes.DECORATOR in left.subtypes: + # Decorators shouldn't be separated from the 'at' sign. + return False + if left.is_keyword and rval == '.': + # Add space between keywords and dots. + return lval not in {'None', 'print'} + if lval == '.' and right.is_keyword: + # Add space between keywords and dots. + return rval not in {'None', 'print'} + if lval == '.' or rval == '.': + # Don't place spaces between dots. + return False + if ((lval == '(' and rval == ')') or (lval == '[' and rval == ']') or + (lval == '{' and rval == '}')): + # Empty objects shouldn't be separated by spaces. + return False + if not is_line_disabled and (left.OpensScope() or right.ClosesScope()): + if (style.GetOrDefault('SPACES_AROUND_DICT_DELIMITERS', False) and ( + (lval == '{' and _IsDictListTupleDelimiterTok(left, is_opening=True)) or + (rval == '}' and + _IsDictListTupleDelimiterTok(right, is_opening=False)))): + return True + if (style.GetOrDefault('SPACES_AROUND_LIST_DELIMITERS', False) and ( + (lval == '[' and _IsDictListTupleDelimiterTok(left, is_opening=True)) or + (rval == ']' and + _IsDictListTupleDelimiterTok(right, is_opening=False)))): + return True + if (style.GetOrDefault('SPACES_AROUND_TUPLE_DELIMITERS', False) and ( + (lval == '(' and _IsDictListTupleDelimiterTok(left, is_opening=True)) or + (rval == ')' and + _IsDictListTupleDelimiterTok(right, is_opening=False)))): + return True + if left.OpensScope() and right.OpensScope(): + # Nested objects' opening brackets shouldn't be separated, unless enabled + # by SPACE_INSIDE_BRACKETS. + return style.Get('SPACE_INSIDE_BRACKETS') + if left.ClosesScope() and right.ClosesScope(): + # Nested objects' closing brackets shouldn't be separated, unless enabled + # by SPACE_INSIDE_BRACKETS. + return style.Get('SPACE_INSIDE_BRACKETS') + if left.ClosesScope() and rval in '([': + # A call, set, dictionary, or subscript that has a call or subscript after + # it shouldn't have a space between them. + return False + if left.OpensScope() and _IsIdNumberStringToken(right): + # Don't separate the opening bracket from the first item, unless enabled + # by SPACE_INSIDE_BRACKETS. + return style.Get('SPACE_INSIDE_BRACKETS') + if left.is_name and rval in '([': + # Don't separate a call or array access from the name. + return False + if right.ClosesScope(): + # Don't separate the closing bracket from the last item, unless enabled + # by SPACE_INSIDE_BRACKETS. + # FIXME(morbo): This might be too permissive. + return style.Get('SPACE_INSIDE_BRACKETS') + if lval == 'print' and rval == '(': + # Special support for the 'print' function. + return False + if left.OpensScope() and _IsUnaryOperator(right): + # Don't separate a unary operator from the opening bracket, unless enabled + # by SPACE_INSIDE_BRACKETS. + return style.Get('SPACE_INSIDE_BRACKETS') + if (left.OpensScope() and (subtypes.VARARGS_STAR in right.subtypes or + subtypes.KWARGS_STAR_STAR in right.subtypes)): + # Don't separate a '*' or '**' from the opening bracket, unless enabled + # by SPACE_INSIDE_BRACKETS. + return style.Get('SPACE_INSIDE_BRACKETS') + if rval == ';': + # Avoid spaces before a semicolon. (Why is there a semicolon?!) + return False + if lval == '(' and rval == 'await': + # Special support for the 'await' keyword. Don't separate the 'await' + # keyword from an opening paren, unless enabled by SPACE_INSIDE_BRACKETS. + return style.Get('SPACE_INSIDE_BRACKETS') + return True + + +def _MustBreakBefore(prev_token, cur_token): + """Return True if a line break is required before the current token.""" + if prev_token.is_comment or (prev_token.previous_token and + prev_token.is_pseudo and + prev_token.previous_token.is_comment): + # Must break if the previous token was a comment. + return True + if (cur_token.is_string and prev_token.is_string and + IsSurroundedByBrackets(cur_token)): + # We want consecutive strings to be on separate lines. This is a + # reasonable assumption, because otherwise they should have written them + # all on the same line, or with a '+'. + return True + return cur_token.must_break_before + + +def _CanBreakBefore(prev_token, cur_token): + """Return True if a line break may occur before the current token.""" + pval = prev_token.value + cval = cur_token.value + if py3compat.PY3: + if pval == 'yield' and cval == 'from': + # Don't break before a yield argument. + return False + if pval in {'async', 'await'} and cval in {'def', 'with', 'for'}: + # Don't break after sync keywords. + return False + if cur_token.split_penalty >= split_penalty.UNBREAKABLE: + return False + if pval == '@': + # Don't break right after the beginning of a decorator. + return False + if cval == ':': + # Don't break before the start of a block of code. + return False + if cval == ',': + # Don't break before a comma. + return False + if prev_token.is_name and cval == '(': + # Don't break in the middle of a function definition or call. + return False + if prev_token.is_name and cval == '[': + # Don't break in the middle of an array dereference. + return False + if cur_token.is_comment and prev_token.lineno == cur_token.lineno: + # Don't break a comment at the end of the line. + return False + if subtypes.UNARY_OPERATOR in prev_token.subtypes: + # Don't break after a unary token. + return False + if not style.Get('ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS'): + if (subtypes.DEFAULT_OR_NAMED_ASSIGN in cur_token.subtypes or + subtypes.DEFAULT_OR_NAMED_ASSIGN in prev_token.subtypes): + return False + return True + + +def IsSurroundedByBrackets(tok): + """Return True if the token is surrounded by brackets.""" + paren_count = 0 + brace_count = 0 + sq_bracket_count = 0 + previous_token = tok.previous_token + while previous_token: + if previous_token.value == ')': + paren_count -= 1 + elif previous_token.value == '}': + brace_count -= 1 + elif previous_token.value == ']': + sq_bracket_count -= 1 + + if previous_token.value == '(': + if paren_count == 0: + return previous_token + paren_count += 1 + elif previous_token.value == '{': + if brace_count == 0: + return previous_token + brace_count += 1 + elif previous_token.value == '[': + if sq_bracket_count == 0: + return previous_token + sq_bracket_count += 1 + + previous_token = previous_token.previous_token + return None + + +def _IsDictListTupleDelimiterTok(tok, is_opening): + assert tok + + if tok.matching_bracket is None: + return False + + if is_opening: + open_tok = tok + close_tok = tok.matching_bracket + else: + open_tok = tok.matching_bracket + close_tok = tok + + # There must be something in between the tokens + if open_tok.next_token == close_tok: + return False + + assert open_tok.next_token.node + assert open_tok.next_token.node.parent + + return open_tok.next_token.node.parent.type in [ + python_symbols.dictsetmaker, + python_symbols.listmaker, + python_symbols.testlist_gexp, + ] + + +_LOGICAL_OPERATORS = frozenset({'and', 'or'}) +_BITWISE_OPERATORS = frozenset({'&', '|', '^'}) +_ARITHMETIC_OPERATORS = frozenset({'+', '-', '*', '/', '%', '//', '@'}) + + +def _SplitPenalty(prev_token, cur_token): + """Return the penalty for breaking the line before the current token.""" + pval = prev_token.value + cval = cur_token.value + if pval == 'not': + return split_penalty.UNBREAKABLE + + if cur_token.node_split_penalty > 0: + return cur_token.node_split_penalty + + if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'): + # Prefer to split before 'and' and 'or'. + if pval in _LOGICAL_OPERATORS: + return style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR') + if cval in _LOGICAL_OPERATORS: + return 0 + else: + # Prefer to split after 'and' and 'or'. + if pval in _LOGICAL_OPERATORS: + return 0 + if cval in _LOGICAL_OPERATORS: + return style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR') + + if style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'): + # Prefer to split before '&', '|', and '^'. + if pval in _BITWISE_OPERATORS: + return style.Get('SPLIT_PENALTY_BITWISE_OPERATOR') + if cval in _BITWISE_OPERATORS: + return 0 + else: + # Prefer to split after '&', '|', and '^'. + if pval in _BITWISE_OPERATORS: + return 0 + if cval in _BITWISE_OPERATORS: + return style.Get('SPLIT_PENALTY_BITWISE_OPERATOR') + + if (subtypes.COMP_FOR in cur_token.subtypes or + subtypes.COMP_IF in cur_token.subtypes): + # We don't mind breaking before the 'for' or 'if' of a list comprehension. + return 0 + if subtypes.UNARY_OPERATOR in prev_token.subtypes: + # Try not to break after a unary operator. + return style.Get('SPLIT_PENALTY_AFTER_UNARY_OPERATOR') + if pval == ',': + # Breaking after a comma is fine, if need be. return 0 + if pval == '**' or cval == '**': + return split_penalty.STRONGLY_CONNECTED + if (subtypes.VARARGS_STAR in prev_token.subtypes or + subtypes.KWARGS_STAR_STAR in prev_token.subtypes): + # Don't split after a varargs * or kwargs **. + return split_penalty.UNBREAKABLE + if prev_token.OpensScope() and cval != '(': + # Slightly prefer + return style.Get('SPLIT_PENALTY_AFTER_OPENING_BRACKET') + if cval == ':': + # Don't split before a colon. + return split_penalty.UNBREAKABLE + if cval == '=': + # Don't split before an assignment. + return split_penalty.UNBREAKABLE + if (subtypes.DEFAULT_OR_NAMED_ASSIGN in prev_token.subtypes or + subtypes.DEFAULT_OR_NAMED_ASSIGN in cur_token.subtypes): + # Don't break before or after an default or named assignment. + return split_penalty.UNBREAKABLE + if cval == '==': + # We would rather not split before an equality operator. + return split_penalty.STRONGLY_CONNECTED + if cur_token.ClosesScope(): + # Give a slight penalty for splitting before the closing scope. + return 100 + return 0 diff --git a/yapf/yapflib/object_state.py b/yapf/yapflib/object_state.py index 58dd6fe18..0afdb6041 100644 --- a/yapf/yapflib/object_state.py +++ b/yapf/yapflib/object_state.py @@ -27,8 +27,8 @@ from yapf.yapflib import subtypes -class ComprehensionState( object ): - """Maintains the state of list comprehension formatting decisions. +class ComprehensionState(object): + """Maintains the state of list comprehension formatting decisions. A stack of ComprehensionState objects are kept to ensure that list comprehensions are wrapped with well-defined rules. @@ -44,53 +44,53 @@ class ComprehensionState( object ): That is, a split somewhere after expr_token or before closing_bracket. """ - def __init__( self, expr_token ): - self.expr_token = expr_token - self.for_token = None - self.has_split_at_for = False - self.has_interior_split = False + def __init__(self, expr_token): + self.expr_token = expr_token + self.for_token = None + self.has_split_at_for = False + self.has_interior_split = False - def HasTrivialExpr( self ): - """Returns whether the comp_expr is "trivial" i.e. is a single token.""" - return self.expr_token.next_token.value == 'for' + def HasTrivialExpr(self): + """Returns whether the comp_expr is "trivial" i.e. is a single token.""" + return self.expr_token.next_token.value == 'for' - @property - def opening_bracket( self ): - return self.expr_token.previous_token + @property + def opening_bracket(self): + return self.expr_token.previous_token - @property - def closing_bracket( self ): - return self.opening_bracket.matching_bracket + @property + def closing_bracket(self): + return self.opening_bracket.matching_bracket - def Clone( self ): - clone = ComprehensionState( self.expr_token ) - clone.for_token = self.for_token - clone.has_split_at_for = self.has_split_at_for - clone.has_interior_split = self.has_interior_split - return clone + def Clone(self): + clone = ComprehensionState(self.expr_token) + clone.for_token = self.for_token + clone.has_split_at_for = self.has_split_at_for + clone.has_interior_split = self.has_interior_split + return clone - def __repr__( self ): - return ( - '[opening_bracket::%s, for_token::%s, has_split_at_for::%s,' - ' has_interior_split::%s, has_trivial_expr::%s]' % ( - self.opening_bracket, self.for_token, self.has_split_at_for, - self.has_interior_split, self.HasTrivialExpr() ) ) + def __repr__(self): + return ( + '[opening_bracket::%s, for_token::%s, has_split_at_for::%s,' + ' has_interior_split::%s, has_trivial_expr::%s]' % ( + self.opening_bracket, self.for_token, self.has_split_at_for, + self.has_interior_split, self.HasTrivialExpr())) - def __eq__( self, other ): - return hash( self ) == hash( other ) + def __eq__(self, other): + return hash(self) == hash(other) - def __ne__( self, other ): - return not self == other + def __ne__(self, other): + return not self == other - def __hash__( self, *args, **kwargs ): - return hash( - ( - self.expr_token, self.for_token, self.has_split_at_for, - self.has_interior_split ) ) + def __hash__(self, *args, **kwargs): + return hash( + ( + self.expr_token, self.for_token, self.has_split_at_for, + self.has_interior_split)) -class ParameterListState( object ): - """Maintains the state of function parameter list formatting decisions. +class ParameterListState(object): + """Maintains the state of function parameter list formatting decisions. Attributes: opening_bracket: The opening bracket of the parameter list. @@ -107,97 +107,97 @@ class ParameterListState( object ): needed if the indentation would collide. """ - def __init__( self, opening_bracket, newline, opening_column ): - self.opening_bracket = opening_bracket - self.has_split_before_first_param = newline - self.opening_column = opening_column - self.parameters = opening_bracket.parameters - self.split_before_closing_bracket = False - - @property - def closing_bracket( self ): - return self.opening_bracket.matching_bracket - - @property - def has_typed_return( self ): - return self.closing_bracket.next_token.value == '->' - - @property - @py3compat.lru_cache() - def has_default_values( self ): - return any( param.has_default_value for param in self.parameters ) - - @property - @py3compat.lru_cache() - def ends_in_comma( self ): - if not self.parameters: - return False - return self.parameters[ -1 ].last_token.next_token.value == ',' - - @property - @py3compat.lru_cache() - def last_token( self ): - token = self.opening_bracket.matching_bracket - while not token.is_comment and token.next_token: - token = token.next_token - return token - - @py3compat.lru_cache() - def LastParamFitsOnLine( self, indent ): - """Return true if the last parameter fits on a single line.""" - if not self.has_typed_return: - return False - if not self.parameters: - return True - total_length = self.last_token.total_length - last_param = self.parameters[ -1 ].first_token - total_length -= last_param.total_length - len( last_param.value ) - return total_length + indent <= style.Get( 'COLUMN_LIMIT' ) - - @py3compat.lru_cache() - def SplitBeforeClosingBracket( self, indent ): - """Return true if there's a split before the closing bracket.""" - if style.Get( 'DEDENT_CLOSING_BRACKETS' ): - return True - if self.ends_in_comma: - return True - if not self.parameters: - return False - total_length = self.last_token.total_length - last_param = self.parameters[ -1 ].first_token - total_length -= last_param.total_length - len( last_param.value ) - return total_length + indent > style.Get( 'COLUMN_LIMIT' ) - - def Clone( self ): - clone = ParameterListState( + def __init__(self, opening_bracket, newline, opening_column): + self.opening_bracket = opening_bracket + self.has_split_before_first_param = newline + self.opening_column = opening_column + self.parameters = opening_bracket.parameters + self.split_before_closing_bracket = False + + @property + def closing_bracket(self): + return self.opening_bracket.matching_bracket + + @property + def has_typed_return(self): + return self.closing_bracket.next_token.value == '->' + + @property + @py3compat.lru_cache() + def has_default_values(self): + return any(param.has_default_value for param in self.parameters) + + @property + @py3compat.lru_cache() + def ends_in_comma(self): + if not self.parameters: + return False + return self.parameters[-1].last_token.next_token.value == ',' + + @property + @py3compat.lru_cache() + def last_token(self): + token = self.opening_bracket.matching_bracket + while not token.is_comment and token.next_token: + token = token.next_token + return token + + @py3compat.lru_cache() + def LastParamFitsOnLine(self, indent): + """Return true if the last parameter fits on a single line.""" + if not self.has_typed_return: + return False + if not self.parameters: + return True + total_length = self.last_token.total_length + last_param = self.parameters[-1].first_token + total_length -= last_param.total_length - len(last_param.value) + return total_length + indent <= style.Get('COLUMN_LIMIT') + + @py3compat.lru_cache() + def SplitBeforeClosingBracket(self, indent): + """Return true if there's a split before the closing bracket.""" + if style.Get('DEDENT_CLOSING_BRACKETS'): + return True + if self.ends_in_comma: + return True + if not self.parameters: + return False + total_length = self.last_token.total_length + last_param = self.parameters[-1].first_token + total_length -= last_param.total_length - len(last_param.value) + return total_length + indent > style.Get('COLUMN_LIMIT') + + def Clone(self): + clone = ParameterListState( + self.opening_bracket, self.has_split_before_first_param, + self.opening_column) + clone.split_before_closing_bracket = self.split_before_closing_bracket + clone.parameters = [param.Clone() for param in self.parameters] + return clone + + def __repr__(self): + return ( + '[opening_bracket::%s, has_split_before_first_param::%s, ' + 'opening_column::%d]' % ( self.opening_bracket, self.has_split_before_first_param, - self.opening_column ) - clone.split_before_closing_bracket = self.split_before_closing_bracket - clone.parameters = [ param.Clone() for param in self.parameters ] - return clone + self.opening_column)) - def __repr__( self ): - return ( - '[opening_bracket::%s, has_split_before_first_param::%s, ' - 'opening_column::%d]' % ( - self.opening_bracket, self.has_split_before_first_param, - self.opening_column ) ) + def __eq__(self, other): + return hash(self) == hash(other) - def __eq__( self, other ): - return hash( self ) == hash( other ) + def __ne__(self, other): + return not self == other - def __ne__( self, other ): - return not self == other - - def __hash__( self, *args, **kwargs ): - return hash( - ( - self.opening_bracket, self.has_split_before_first_param, - self.opening_column, ( hash( param ) for param in self.parameters ) ) ) + def __hash__(self, *args, **kwargs): + return hash( + ( + self.opening_bracket, self.has_split_before_first_param, + self.opening_column, (hash(param) for param in self.parameters))) -class Parameter( object ): - """A parameter in a parameter list. +class Parameter(object): + """A parameter in a parameter list. Attributes: first_token: (format_token.FormatToken) First token of parameter. @@ -205,33 +205,33 @@ class Parameter( object ): has_default_value: (boolean) True if the parameter has a default value """ - def __init__( self, first_token, last_token ): - self.first_token = first_token - self.last_token = last_token + def __init__(self, first_token, last_token): + self.first_token = first_token + self.last_token = last_token - @property - @py3compat.lru_cache() - def has_default_value( self ): - """Returns true if the parameter has a default value.""" - tok = self.first_token - while tok != self.last_token: - if subtypes.DEFAULT_OR_NAMED_ASSIGN in tok.subtypes: - return True - tok = tok.matching_bracket if tok.OpensScope() else tok.next_token - return False + @property + @py3compat.lru_cache() + def has_default_value(self): + """Returns true if the parameter has a default value.""" + tok = self.first_token + while tok != self.last_token: + if subtypes.DEFAULT_OR_NAMED_ASSIGN in tok.subtypes: + return True + tok = tok.matching_bracket if tok.OpensScope() else tok.next_token + return False - def Clone( self ): - return Parameter( self.first_token, self.last_token ) + def Clone(self): + return Parameter(self.first_token, self.last_token) - def __repr__( self ): - return '[first_token::%s, last_token:%s]' % ( - self.first_token, self.last_token ) + def __repr__(self): + return '[first_token::%s, last_token:%s]' % ( + self.first_token, self.last_token) - def __eq__( self, other ): - return hash( self ) == hash( other ) + def __eq__(self, other): + return hash(self) == hash(other) - def __ne__( self, other ): - return not self == other + def __ne__(self, other): + return not self == other - def __hash__( self, *args, **kwargs ): - return hash( ( self.first_token, self.last_token ) ) + def __hash__(self, *args, **kwargs): + return hash((self.first_token, self.last_token)) diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py index 143a13c3e..2ea5910d1 100644 --- a/yapf/yapflib/py3compat.py +++ b/yapf/yapflib/py3compat.py @@ -18,75 +18,75 @@ import os import sys -PY3 = sys.version_info[ 0 ] >= 3 -PY36 = sys.version_info[ 0 ] >= 3 and sys.version_info[ 1 ] >= 6 -PY37 = sys.version_info[ 0 ] >= 3 and sys.version_info[ 1 ] >= 7 -PY38 = sys.version_info[ 0 ] >= 3 and sys.version_info[ 1 ] >= 8 +PY3 = sys.version_info[0] >= 3 +PY36 = sys.version_info[0] >= 3 and sys.version_info[1] >= 6 +PY37 = sys.version_info[0] >= 3 and sys.version_info[1] >= 7 +PY38 = sys.version_info[0] >= 3 and sys.version_info[1] >= 8 if PY3: - StringIO = io.StringIO - BytesIO = io.BytesIO + StringIO = io.StringIO + BytesIO = io.BytesIO - import codecs # noqa: F811 + import codecs # noqa: F811 - def open_with_encoding( filename, mode, encoding, newline = '' ): # pylint: disable=unused-argument # noqa - return codecs.open( filename, mode = mode, encoding = encoding ) + def open_with_encoding(filename, mode, encoding, newline=''): # pylint: disable=unused-argument # noqa + return codecs.open(filename, mode=mode, encoding=encoding) - import functools - lru_cache = functools.lru_cache + import functools + lru_cache = functools.lru_cache - range = range - ifilter = filter + range = range + ifilter = filter - def raw_input(): - wrapper = io.TextIOWrapper( sys.stdin.buffer, encoding = 'utf-8' ) - return wrapper.buffer.raw.readall().decode( 'utf-8' ) + def raw_input(): + wrapper = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8') + return wrapper.buffer.raw.readall().decode('utf-8') - import configparser + import configparser - # Mappings from strings to booleans (such as '1' to True, 'false' to False, - # etc.) - CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser.BOOLEAN_STATES + # Mappings from strings to booleans (such as '1' to True, 'false' to False, + # etc.) + CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser.BOOLEAN_STATES - import tokenize - detect_encoding = tokenize.detect_encoding - TokenInfo = tokenize.TokenInfo + import tokenize + detect_encoding = tokenize.detect_encoding + TokenInfo = tokenize.TokenInfo else: - import __builtin__ - import cStringIO - from itertools import ifilter + import __builtin__ + import cStringIO + from itertools import ifilter - StringIO = BytesIO = cStringIO.StringIO + StringIO = BytesIO = cStringIO.StringIO - open_with_encoding = io.open + open_with_encoding = io.open - # Python 2.7 doesn't have a native LRU cache, so do nothing. - def lru_cache( maxsize = 128, typed = False ): + # Python 2.7 doesn't have a native LRU cache, so do nothing. + def lru_cache(maxsize=128, typed=False): - def fake_wrapper( user_function ): - return user_function + def fake_wrapper(user_function): + return user_function - return fake_wrapper + return fake_wrapper - range = xrange # noqa: F821 + range = xrange # noqa: F821 - raw_input = raw_input + raw_input = raw_input - import ConfigParser as configparser - CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser._boolean_states # pylint: disable=protected-access # noqa + import ConfigParser as configparser + CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser._boolean_states # pylint: disable=protected-access # noqa - from lib2to3.pgen2 import tokenize - detect_encoding = tokenize.detect_encoding + from lib2to3.pgen2 import tokenize + detect_encoding = tokenize.detect_encoding - import collections + import collections - class TokenInfo( collections.namedtuple( 'TokenInfo', - 'type string start end line' ) ): - pass + class TokenInfo(collections.namedtuple('TokenInfo', + 'type string start end line')): + pass -def EncodeAndWriteToStdout( s, encoding = 'utf-8' ): - """Encode the given string and emit to stdout. +def EncodeAndWriteToStdout(s, encoding='utf-8'): + """Encode the given string and emit to stdout. The string may contain non-ascii characters. This is a problem when stdout is redirected, because then Python doesn't know the encoding and we may get a @@ -96,50 +96,50 @@ def EncodeAndWriteToStdout( s, encoding = 'utf-8' ): s: (string) The string to encode. encoding: (string) The encoding of the string. """ - if PY3: - sys.stdout.buffer.write( s.encode( encoding ) ) - elif sys.platform == 'win32': - # On python 2 and Windows universal newline transformation will be in - # effect on stdout. Python 2 will not let us avoid the easily because - # it happens based on whether the file handle is opened in O_BINARY or - # O_TEXT state. However we can tell Windows itself to change the current - # mode, and python 2 will follow suit. However we must take care to change - # the mode on the actual external stdout not just the current sys.stdout - # which may have been monkey-patched inside the python environment. - import msvcrt # pylint: disable=g-import-not-at-top - if sys.__stdout__ is sys.stdout: - msvcrt.setmode( sys.stdout.fileno(), os.O_BINARY ) - sys.stdout.write( s.encode( encoding ) ) - else: - sys.stdout.write( s.encode( encoding ) ) + if PY3: + sys.stdout.buffer.write(s.encode(encoding)) + elif sys.platform == 'win32': + # On python 2 and Windows universal newline transformation will be in + # effect on stdout. Python 2 will not let us avoid the easily because + # it happens based on whether the file handle is opened in O_BINARY or + # O_TEXT state. However we can tell Windows itself to change the current + # mode, and python 2 will follow suit. However we must take care to change + # the mode on the actual external stdout not just the current sys.stdout + # which may have been monkey-patched inside the python environment. + import msvcrt # pylint: disable=g-import-not-at-top + if sys.__stdout__ is sys.stdout: + msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) + sys.stdout.write(s.encode(encoding)) + else: + sys.stdout.write(s.encode(encoding)) if PY3: - basestring = str - unicode = str # pylint: disable=redefined-builtin,invalid-name + basestring = str + unicode = str # pylint: disable=redefined-builtin,invalid-name else: - basestring = basestring + basestring = basestring - def unicode( s ): # pylint: disable=invalid-name - """Force conversion of s to unicode.""" - return __builtin__.unicode( s, 'utf-8' ) + def unicode(s): # pylint: disable=invalid-name + """Force conversion of s to unicode.""" + return __builtin__.unicode(s, 'utf-8') # In Python 3.2+, readfp is deprecated in favor of read_file, which doesn't # exist in Python 2 yet. To avoid deprecation warnings, subclass ConfigParser to # fix this - now read_file works across all Python versions we care about. -class ConfigParser( configparser.ConfigParser ): - if not PY3: +class ConfigParser(configparser.ConfigParser): + if not PY3: - def read_file( self, fp, source = None ): - self.readfp( fp, filename = source ) + def read_file(self, fp, source=None): + self.readfp(fp, filename=source) -def removeBOM( source ): - """Remove any Byte-order-Mark bytes from the beginning of a file.""" - bom = codecs.BOM_UTF8 - if PY3: - bom = bom.decode( 'utf-8' ) - if source.startswith( bom ): - return source[ len( bom ): ] - return source +def removeBOM(source): + """Remove any Byte-order-Mark bytes from the beginning of a file.""" + bom = codecs.BOM_UTF8 + if PY3: + bom = bom.decode('utf-8') + if source.startswith(bom): + return source[len(bom):] + return source diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 7e0fdf344..ec196d8b3 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -37,8 +37,8 @@ from yapf.yapflib import verifier -def Reformat( llines, verify = False, lines = None ): - """Reformat the logical lines. +def Reformat(llines, verify=False, lines=None): + """Reformat the logical lines. Arguments: llines: (list of logical_line.LogicalLine) Lines we want to format. @@ -49,138 +49,139 @@ def Reformat( llines, verify = False, lines = None ): Returns: A string representing the reformatted code. """ - final_lines = [] - prev_line = None # The previous line. - indent_width = style.Get( 'INDENT_WIDTH' ) - - for lline in _SingleOrMergedLines( llines ): - first_token = lline.first - _FormatFirstToken( first_token, lline.depth, prev_line, final_lines ) - - indent_amt = indent_width * lline.depth - state = format_decision_state.FormatDecisionState( lline, indent_amt ) - state.MoveStateToNextToken() - - if not lline.disable: - if lline.first.is_comment: - lline.first.value = lline.first.value.rstrip() - elif lline.last.is_comment: - lline.last.value = lline.last.value.rstrip() - if prev_line and prev_line.disable: - # Keep the vertical spacing between a disabled and enabled formatting - # region. - _RetainRequiredVerticalSpacingBetweenTokens( - lline.first, prev_line.last, lines ) - if any( tok.is_comment for tok in lline.tokens ): - _RetainVerticalSpacingBeforeComments( lline ) - - if lline.disable or _LineHasContinuationMarkers( lline ): - _RetainHorizontalSpacing( lline ) - _RetainRequiredVerticalSpacing( lline, prev_line, lines ) - _EmitLineUnformatted( state ) - - elif ( _LineContainsPylintDisableLineTooLong( lline ) or - _LineContainsI18n( lline ) ): - # Don't modify vertical spacing, but fix any horizontal spacing issues. - _RetainRequiredVerticalSpacing( lline, prev_line, lines ) - _EmitLineUnformatted( state ) - - elif _CanPlaceOnSingleLine( lline ) and not any( tok.must_break_before - for tok in lline.tokens ): - # The logical line fits on one line. - while state.next_token: - state.AddTokenToState( newline = False, dry_run = False ) - - elif not _AnalyzeSolutionSpace( state ): - # Failsafe mode. If there isn't a solution to the line, then just emit - # it as is. - state = format_decision_state.FormatDecisionState( lline, indent_amt ) - state.MoveStateToNextToken() - _RetainHorizontalSpacing( lline ) - _RetainRequiredVerticalSpacing( lline, prev_line, None ) - _EmitLineUnformatted( state ) - - final_lines.append( lline ) - prev_line = lline - - if style.Get( 'ALIGN_ASSIGNMENT' ): - _AlignAssignment( final_lines ) - - _AlignTrailingComments( final_lines ) - return _FormatFinalLines( final_lines, verify ) - - -def _RetainHorizontalSpacing( line ): - """Retain all horizontal spacing between tokens.""" - for tok in line.tokens: - tok.RetainHorizontalSpacing( line.first.column, line.depth ) - - -def _RetainRequiredVerticalSpacing( cur_line, prev_line, lines ): - """Retain all vertical spacing between lines.""" - prev_tok = None - if prev_line is not None: - prev_tok = prev_line.last - - if cur_line.disable: - # After the first token we are acting on a single line. So if it is - # disabled we must not reformat. - lines = set() - - for cur_tok in cur_line.tokens: - _RetainRequiredVerticalSpacingBetweenTokens( cur_tok, prev_tok, lines ) - prev_tok = cur_tok - - -def _RetainRequiredVerticalSpacingBetweenTokens( cur_tok, prev_tok, lines ): - """Retain vertical spacing between two tokens if not in editable range.""" - if prev_tok is None: - return - - if prev_tok.is_string: - prev_lineno = prev_tok.lineno + prev_tok.value.count( '\n' ) - elif prev_tok.is_pseudo: - if not prev_tok.previous_token.is_multiline_string: - prev_lineno = prev_tok.previous_token.lineno - else: - prev_lineno = prev_tok.lineno + final_lines = [] + prev_line = None # The previous line. + indent_width = style.Get('INDENT_WIDTH') + + for lline in _SingleOrMergedLines(llines): + first_token = lline.first + _FormatFirstToken(first_token, lline.depth, prev_line, final_lines) + + indent_amt = indent_width * lline.depth + state = format_decision_state.FormatDecisionState(lline, indent_amt) + state.MoveStateToNextToken() + + if not lline.disable: + if lline.first.is_comment: + lline.first.value = lline.first.value.rstrip() + elif lline.last.is_comment: + lline.last.value = lline.last.value.rstrip() + if prev_line and prev_line.disable: + # Keep the vertical spacing between a disabled and enabled formatting + # region. + _RetainRequiredVerticalSpacingBetweenTokens( + lline.first, prev_line.last, lines) + if any(tok.is_comment for tok in lline.tokens): + _RetainVerticalSpacingBeforeComments(lline) + + if lline.disable or _LineHasContinuationMarkers(lline): + _RetainHorizontalSpacing(lline) + _RetainRequiredVerticalSpacing(lline, prev_line, lines) + _EmitLineUnformatted(state) + + elif (_LineContainsPylintDisableLineTooLong(lline) or + _LineContainsI18n(lline)): + # Don't modify vertical spacing, but fix any horizontal spacing issues. + _RetainRequiredVerticalSpacing(lline, prev_line, lines) + _EmitLineUnformatted(state) + + elif _CanPlaceOnSingleLine(lline) and not any(tok.must_break_before + for tok in lline.tokens): + # The logical line fits on one line. + while state.next_token: + state.AddTokenToState(newline=False, dry_run=False) + + elif not _AnalyzeSolutionSpace(state): + # Failsafe mode. If there isn't a solution to the line, then just emit + # it as is. + state = format_decision_state.FormatDecisionState(lline, indent_amt) + state.MoveStateToNextToken() + _RetainHorizontalSpacing(lline) + _RetainRequiredVerticalSpacing(lline, prev_line, None) + _EmitLineUnformatted(state) + + final_lines.append(lline) + prev_line = lline + + if style.Get('ALIGN_ASSIGNMENT'): + _AlignAssignment(final_lines) + + _AlignTrailingComments(final_lines) + return _FormatFinalLines(final_lines, verify) + + +def _RetainHorizontalSpacing(line): + """Retain all horizontal spacing between tokens.""" + for tok in line.tokens: + tok.RetainHorizontalSpacing(line.first.column, line.depth) + + +def _RetainRequiredVerticalSpacing(cur_line, prev_line, lines): + """Retain all vertical spacing between lines.""" + prev_tok = None + if prev_line is not None: + prev_tok = prev_line.last + + if cur_line.disable: + # After the first token we are acting on a single line. So if it is + # disabled we must not reformat. + lines = set() + + for cur_tok in cur_line.tokens: + _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines) + prev_tok = cur_tok + + +def _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines): + """Retain vertical spacing between two tokens if not in editable range.""" + if prev_tok is None: + return + + if prev_tok.is_string: + prev_lineno = prev_tok.lineno + prev_tok.value.count('\n') + elif prev_tok.is_pseudo: + if not prev_tok.previous_token.is_multiline_string: + prev_lineno = prev_tok.previous_token.lineno else: - prev_lineno = prev_tok.lineno + prev_lineno = prev_tok.lineno + else: + prev_lineno = prev_tok.lineno - if cur_tok.is_comment: - cur_lineno = cur_tok.lineno - cur_tok.value.count( '\n' ) - else: - cur_lineno = cur_tok.lineno + if cur_tok.is_comment: + cur_lineno = cur_tok.lineno - cur_tok.value.count('\n') + else: + cur_lineno = cur_tok.lineno - if not prev_tok.is_comment and prev_tok.value.endswith( '\\' ): - prev_lineno += prev_tok.value.count( '\n' ) + if not prev_tok.is_comment and prev_tok.value.endswith('\\'): + prev_lineno += prev_tok.value.count('\n') - required_newlines = cur_lineno - prev_lineno - if cur_tok.is_comment and not prev_tok.is_comment: - # Don't adjust between a comment and non-comment. - pass - elif lines and lines.intersection( range( prev_lineno, cur_lineno + 1 ) ): - desired_newlines = cur_tok.whitespace_prefix.count( '\n' ) - whitespace_lines = range( prev_lineno + 1, cur_lineno ) - deletable_lines = len( lines.intersection( whitespace_lines ) ) - required_newlines = max( required_newlines - deletable_lines, desired_newlines ) + required_newlines = cur_lineno - prev_lineno + if cur_tok.is_comment and not prev_tok.is_comment: + # Don't adjust between a comment and non-comment. + pass + elif lines and lines.intersection(range(prev_lineno, cur_lineno + 1)): + desired_newlines = cur_tok.whitespace_prefix.count('\n') + whitespace_lines = range(prev_lineno + 1, cur_lineno) + deletable_lines = len(lines.intersection(whitespace_lines)) + required_newlines = max( + required_newlines - deletable_lines, desired_newlines) - cur_tok.AdjustNewlinesBefore( required_newlines ) + cur_tok.AdjustNewlinesBefore(required_newlines) -def _RetainVerticalSpacingBeforeComments( line ): - """Retain vertical spacing before comments.""" - prev_token = None - for tok in line.tokens: - if tok.is_comment and prev_token: - if tok.lineno - tok.value.count( '\n' ) - prev_token.lineno > 1: - tok.AdjustNewlinesBefore( ONE_BLANK_LINE ) +def _RetainVerticalSpacingBeforeComments(line): + """Retain vertical spacing before comments.""" + prev_token = None + for tok in line.tokens: + if tok.is_comment and prev_token: + if tok.lineno - tok.value.count('\n') - prev_token.lineno > 1: + tok.AdjustNewlinesBefore(ONE_BLANK_LINE) - prev_token = tok + prev_token = tok -def _EmitLineUnformatted( state ): - """Emit the line without formatting. +def _EmitLineUnformatted(state): + """Emit the line without formatting. The line contains code that if reformatted would break a non-syntactic convention. E.g., i18n comments and function calls are tightly bound by @@ -191,23 +192,23 @@ def _EmitLineUnformatted( state ): state: (format_decision_state.FormatDecisionState) The format decision state. """ - while state.next_token: - previous_token = state.next_token.previous_token - previous_lineno = previous_token.lineno + while state.next_token: + previous_token = state.next_token.previous_token + previous_lineno = previous_token.lineno - if previous_token.is_multiline_string or previous_token.is_string: - previous_lineno += previous_token.value.count( '\n' ) + if previous_token.is_multiline_string or previous_token.is_string: + previous_lineno += previous_token.value.count('\n') - if previous_token.is_continuation: - newline = False - else: - newline = state.next_token.lineno > previous_lineno + if previous_token.is_continuation: + newline = False + else: + newline = state.next_token.lineno > previous_lineno - state.AddTokenToState( newline = newline, dry_run = False ) + state.AddTokenToState(newline=newline, dry_run=False) -def _LineContainsI18n( line ): - """Return true if there are i18n comments or function calls in the line. +def _LineContainsI18n(line): + """Return true if there are i18n comments or function calls in the line. I18n comments and pseudo-function calls are closely related. They cannot be moved apart without breaking i18n. @@ -218,33 +219,33 @@ def _LineContainsI18n( line ): Returns: True if the line contains i18n comments or function calls. False otherwise. """ - if style.Get( 'I18N_COMMENT' ): - for tok in line.tokens: - if tok.is_comment and re.match( style.Get( 'I18N_COMMENT' ), tok.value ): - # Contains an i18n comment. - return True - - if style.Get( 'I18N_FUNCTION_CALL' ): - length = len( line.tokens ) - for index in range( length - 1 ): - if ( line.tokens[ index + 1 ].value == '(' and - line.tokens[ index ].value in style.Get( 'I18N_FUNCTION_CALL' ) ): - return True - return False + if style.Get('I18N_COMMENT'): + for tok in line.tokens: + if tok.is_comment and re.match(style.Get('I18N_COMMENT'), tok.value): + # Contains an i18n comment. + return True + + if style.Get('I18N_FUNCTION_CALL'): + length = len(line.tokens) + for index in range(length - 1): + if (line.tokens[index + 1].value == '(' and + line.tokens[index].value in style.Get('I18N_FUNCTION_CALL')): + return True + return False -def _LineContainsPylintDisableLineTooLong( line ): - """Return true if there is a "pylint: disable=line-too-long" comment.""" - return re.search( r'\bpylint:\s+disable=line-too-long\b', line.last.value ) +def _LineContainsPylintDisableLineTooLong(line): + """Return true if there is a "pylint: disable=line-too-long" comment.""" + return re.search(r'\bpylint:\s+disable=line-too-long\b', line.last.value) -def _LineHasContinuationMarkers( line ): - """Return true if the line has continuation markers in it.""" - return any( tok.is_continuation for tok in line.tokens ) +def _LineHasContinuationMarkers(line): + """Return true if the line has continuation markers in it.""" + return any(tok.is_continuation for tok in line.tokens) -def _CanPlaceOnSingleLine( line ): - """Determine if the logical line can go on a single line. +def _CanPlaceOnSingleLine(line): + """Determine if the logical line can go on a single line. Arguments: line: (logical_line.LogicalLine) The line currently being formatted. @@ -252,359 +253,342 @@ def _CanPlaceOnSingleLine( line ): Returns: True if the line can or should be added to a single line. False otherwise. """ - token_names = [ x.name for x in line.tokens ] - if ( style.Get( 'FORCE_MULTILINE_DICT' ) and 'LBRACE' in token_names ): - return False - indent_amt = style.Get( 'INDENT_WIDTH' ) * line.depth - last = line.last - last_index = -1 - if ( last.is_pylint_comment or last.is_pytype_comment or last.is_copybara_comment ): - last = last.previous_token - last_index = -2 - if last is None: - return True - return ( - last.total_length + indent_amt <= style.Get( 'COLUMN_LIMIT' ) and - not any( tok.is_comment for tok in line.tokens[ : last_index ] ) ) - - -def _AlignTrailingComments( final_lines ): - """Align trailing comments to the same column.""" - final_lines_index = 0 - while final_lines_index < len( final_lines ): - line = final_lines[ final_lines_index ] - assert line.tokens - - processed_content = False - - for tok in line.tokens: - if ( tok.is_comment and isinstance( tok.spaces_required_before, list ) and - tok.value.startswith( '#' ) ): - # All trailing comments and comments that appear on a line by themselves - # in this block should be indented at the same level. The block is - # terminated by an empty line or EOF. Enumerate through each line in - # the block and calculate the max line length. Once complete, use the - # first col value greater than that value and create the necessary for - # each line accordingly. - all_pc_line_lengths = [] # All pre-comment line lengths - max_line_length = 0 - - while True: - # EOF - if final_lines_index + len( all_pc_line_lengths ) == len( - final_lines ): - break - - this_line = final_lines[ final_lines_index + - len( all_pc_line_lengths ) ] - - # Blank line - note that content is preformatted so we don't need to - # worry about spaces/tabs; a blank line will always be '\n\n'. - assert this_line.tokens - if ( all_pc_line_lengths and - this_line.tokens[ 0 ].formatted_whitespace_prefix.startswith( - '\n\n' ) ): - break - - if this_line.disable: - all_pc_line_lengths.append( [] ) - continue - - # Calculate the length of each line in this logical line. - line_content = '' - pc_line_lengths = [] - - for line_tok in this_line.tokens: - whitespace_prefix = line_tok.formatted_whitespace_prefix - - newline_index = whitespace_prefix.rfind( '\n' ) - if newline_index != -1: - max_line_length = max( - max_line_length, len( line_content ) ) - line_content = '' - - whitespace_prefix = whitespace_prefix[ newline_index + 1 : ] - - if line_tok.is_comment: - pc_line_lengths.append( len( line_content ) ) - else: - line_content += '{}{}'.format( - whitespace_prefix, line_tok.value ) - - if pc_line_lengths: - max_line_length = max( max_line_length, max( pc_line_lengths ) ) - - all_pc_line_lengths.append( pc_line_lengths ) - - # Calculate the aligned column value - max_line_length += 2 - - aligned_col = None - for potential_col in tok.spaces_required_before: - if potential_col > max_line_length: - aligned_col = potential_col - break - - if aligned_col is None: - aligned_col = max_line_length - - # Update the comment token values based on the aligned values - for all_pc_line_lengths_index, pc_line_lengths in enumerate( - all_pc_line_lengths ): - if not pc_line_lengths: - continue - - this_line = final_lines[ final_lines_index + - all_pc_line_lengths_index ] - - pc_line_length_index = 0 - for line_tok in this_line.tokens: - if line_tok.is_comment: - assert pc_line_length_index < len( pc_line_lengths ) - assert pc_line_lengths[ pc_line_length_index ] < aligned_col - - # Note that there may be newlines embedded in the comments, so - # we need to apply a whitespace prefix to each line. - whitespace = ' ' * ( - aligned_col - pc_line_lengths[ pc_line_length_index ] - - 1 ) - pc_line_length_index += 1 - - line_content = [] - - for comment_line_index, comment_line in enumerate( - line_tok.value.split( '\n' ) ): - line_content.append( - '{}{}'.format( whitespace, comment_line.strip() ) ) - - if comment_line_index == 0: - whitespace = ' ' * ( aligned_col - 1 ) - - line_content = '\n'.join( line_content ) - - # Account for initial whitespace already slated for the - # beginning of the line. - existing_whitespace_prefix = \ - line_tok.formatted_whitespace_prefix.lstrip('\n') + token_names = [x.name for x in line.tokens] + if (style.Get('FORCE_MULTILINE_DICT') and 'LBRACE' in token_names): + return False + indent_amt = style.Get('INDENT_WIDTH') * line.depth + last = line.last + last_index = -1 + if (last.is_pylint_comment or last.is_pytype_comment or + last.is_copybara_comment): + last = last.previous_token + last_index = -2 + if last is None: + return True + return ( + last.total_length + indent_amt <= style.Get('COLUMN_LIMIT') and + not any(tok.is_comment for tok in line.tokens[:last_index])) - if line_content.startswith( existing_whitespace_prefix ): - line_content = line_content[ - len( existing_whitespace_prefix ): ] - line_tok.value = line_content +def _AlignTrailingComments(final_lines): + """Align trailing comments to the same column.""" + final_lines_index = 0 + while final_lines_index < len(final_lines): + line = final_lines[final_lines_index] + assert line.tokens - assert pc_line_length_index == len( pc_line_lengths ) + processed_content = False - final_lines_index += len( all_pc_line_lengths ) + for tok in line.tokens: + if (tok.is_comment and isinstance(tok.spaces_required_before, list) and + tok.value.startswith('#')): + # All trailing comments and comments that appear on a line by themselves + # in this block should be indented at the same level. The block is + # terminated by an empty line or EOF. Enumerate through each line in + # the block and calculate the max line length. Once complete, use the + # first col value greater than that value and create the necessary for + # each line accordingly. + all_pc_line_lengths = [] # All pre-comment line lengths + max_line_length = 0 + + while True: + # EOF + if final_lines_index + len(all_pc_line_lengths) == len(final_lines): + break - processed_content = True - break + this_line = final_lines[final_lines_index + len(all_pc_line_lengths)] + + # Blank line - note that content is preformatted so we don't need to + # worry about spaces/tabs; a blank line will always be '\n\n'. + assert this_line.tokens + if (all_pc_line_lengths and + this_line.tokens[0].formatted_whitespace_prefix.startswith('\n\n') + ): + break + + if this_line.disable: + all_pc_line_lengths.append([]) + continue + + # Calculate the length of each line in this logical line. + line_content = '' + pc_line_lengths = [] + + for line_tok in this_line.tokens: + whitespace_prefix = line_tok.formatted_whitespace_prefix + + newline_index = whitespace_prefix.rfind('\n') + if newline_index != -1: + max_line_length = max(max_line_length, len(line_content)) + line_content = '' + + whitespace_prefix = whitespace_prefix[newline_index + 1:] + + if line_tok.is_comment: + pc_line_lengths.append(len(line_content)) + else: + line_content += '{}{}'.format(whitespace_prefix, line_tok.value) + + if pc_line_lengths: + max_line_length = max(max_line_length, max(pc_line_lengths)) + + all_pc_line_lengths.append(pc_line_lengths) + + # Calculate the aligned column value + max_line_length += 2 + + aligned_col = None + for potential_col in tok.spaces_required_before: + if potential_col > max_line_length: + aligned_col = potential_col + break + + if aligned_col is None: + aligned_col = max_line_length + + # Update the comment token values based on the aligned values + for all_pc_line_lengths_index, pc_line_lengths in enumerate( + all_pc_line_lengths): + if not pc_line_lengths: + continue + + this_line = final_lines[final_lines_index + all_pc_line_lengths_index] + + pc_line_length_index = 0 + for line_tok in this_line.tokens: + if line_tok.is_comment: + assert pc_line_length_index < len(pc_line_lengths) + assert pc_line_lengths[pc_line_length_index] < aligned_col + + # Note that there may be newlines embedded in the comments, so + # we need to apply a whitespace prefix to each line. + whitespace = ' ' * ( + aligned_col - pc_line_lengths[pc_line_length_index] - 1) + pc_line_length_index += 1 + + line_content = [] + + for comment_line_index, comment_line in enumerate( + line_tok.value.split('\n')): + line_content.append( + '{}{}'.format(whitespace, comment_line.strip())) + + if comment_line_index == 0: + whitespace = ' ' * (aligned_col - 1) + + line_content = '\n'.join(line_content) + + # Account for initial whitespace already slated for the + # beginning of the line. + existing_whitespace_prefix = \ + line_tok.formatted_whitespace_prefix.lstrip('\n') + + if line_content.startswith(existing_whitespace_prefix): + line_content = line_content[len(existing_whitespace_prefix):] + + line_tok.value = line_content + + assert pc_line_length_index == len(pc_line_lengths) + + final_lines_index += len(all_pc_line_lengths) + + processed_content = True + break + + if not processed_content: + final_lines_index += 1 - if not processed_content: - final_lines_index += 1 - - -def _AlignAssignment( final_lines ): - """Align assignment operators and augmented assignment operators to the same column""" - - final_lines_index = 0 - while final_lines_index < len( final_lines ): - line = final_lines[ final_lines_index ] - - assert line.tokens - process_content = False - - for tok in line.tokens: - if tok.is_assign or tok.is_augassign: - # all pre assignment variable lengths in one block of lines - all_pa_variables_lengths = [] - max_variables_length = 0 - - while True: - # EOF - if final_lines_index + len( all_pa_variables_lengths ) == len( - final_lines ): - break - - this_line_index = final_lines_index + len( - all_pa_variables_lengths ) - this_line = final_lines[ this_line_index ] - - next_line = None - if this_line_index < len( final_lines ) - 1: - next_line = final_lines[ final_lines_index + - len( all_pa_variables_lengths ) + 1 ] - - assert this_line.tokens, next_line.tokens - - # align them differently when there is a blank line in between - if ( all_pa_variables_lengths and - this_line.tokens[ 0 ].formatted_whitespace_prefix.startswith( - '\n\n' ) ): - break - - # if there is a standalone comment or keyword statement line - # or other lines without assignment in between, break - elif ( all_pa_variables_lengths and - True not in [ tok.is_assign or tok.is_augassign - for tok in this_line.tokens ] ): - if this_line.tokens[ 0 ].is_comment: - if style.Get( 'NEW_ALIGNMENT_AFTER_COMMENTLINE' ): - break - else: - break - - if this_line.disable: - all_pa_variables_lengths.append( [] ) - continue - - variables_content = '' - pa_variables_lengths = [] - contain_object = False - line_tokens = this_line.tokens - # only one assignment expression is on each line - for index in range( len( line_tokens ) ): - line_tok = line_tokens[ index ] - - prefix = line_tok.formatted_whitespace_prefix - newline_index = prefix.rfind( '\n' ) - if newline_index != -1: - variables_content = '' - prefix = prefix[ newline_index + 1 : ] - - if line_tok.is_assign or line_tok.is_augassign: - next_toks = [ - line_tokens[ i ] - for i in range( index + 1, len( line_tokens ) ) - ] - # if there is object(list/tuple/dict) with newline entries, break, - # update the alignment so far and start to calulate new alignment - for tok in next_toks: - if tok.value in [ '(', '[', '{' ] and tok.next_token: - if ( - tok.next_token.formatted_whitespace_prefix - .startswith( '\n' ) or - ( tok.next_token.is_comment and - tok.next_token.next_token. - formatted_whitespace_prefix.startswith( '\n' ) - ) ): - pa_variables_lengths.append( - len( variables_content ) ) - contain_object = True - break - if not contain_object: - if line_tok.is_assign: - pa_variables_lengths.append( - len( variables_content ) ) - # if augassign, add the extra augmented part to the max length caculation - elif line_tok.is_augassign: - pa_variables_lengths.append( - len( variables_content ) + - len( line_tok.value ) - 1 ) - # don't add the tokens - # after the assignment operator - break - else: - variables_content += '{}{}'.format( prefix, line_tok.value ) - - if pa_variables_lengths: - max_variables_length = max( - max_variables_length, max( pa_variables_lengths ) ) - - all_pa_variables_lengths.append( pa_variables_lengths ) - - # after saving this line's max variable length, - # we check if next line has the same depth as this line, - # if not, we don't want to calculate their max variable length together - # so we break the while loop, update alignment so far, and - # then go to next line that has '=' - if next_line: - if this_line.depth != next_line.depth: - break - # if this line contains objects with newline entries, - # start new block alignment - if contain_object: - break - - # if no update of max_length, just go to the next block - if max_variables_length == 0: - continue - - max_variables_length += 2 - - # Update the assignment token values based on the max variable length - for all_pa_variables_lengths_index, pa_variables_lengths in enumerate( - all_pa_variables_lengths ): - if not pa_variables_lengths: - continue - this_line = final_lines[ final_lines_index + - all_pa_variables_lengths_index ] - - # only the first assignment operator on each line - pa_variables_lengths_index = 0 - for line_tok in this_line.tokens: - if line_tok.is_assign or line_tok.is_augassign: - assert pa_variables_lengths[ 0 ] < max_variables_length - - if pa_variables_lengths_index < len( pa_variables_lengths ): - whitespace = ' ' * ( - max_variables_length - pa_variables_lengths[ 0 ] - - 1 ) - - assign_content = '{}{}'.format( - whitespace, line_tok.value.strip() ) - - existing_whitespace_prefix = \ - line_tok.formatted_whitespace_prefix.lstrip('\n') - - # in case the existing spaces are larger than padded spaces - if ( len( whitespace ) == 1 or len( whitespace ) > 1 and - len( existing_whitespace_prefix ) - > len( whitespace ) ): - line_tok.whitespace_prefix = '' - elif assign_content.startswith( - existing_whitespace_prefix ): - assign_content = assign_content[ - len( existing_whitespace_prefix ): ] - - # update the assignment operator value - line_tok.value = assign_content - - pa_variables_lengths_index += 1 - - final_lines_index += len( all_pa_variables_lengths ) - - process_content = True + +def _AlignAssignment(final_lines): + """Align assignment operators and augmented assignment operators to the same column""" + + final_lines_index = 0 + while final_lines_index < len(final_lines): + line = final_lines[final_lines_index] + + assert line.tokens + process_content = False + + for tok in line.tokens: + if tok.is_assign or tok.is_augassign: + # all pre assignment variable lengths in one block of lines + all_pa_variables_lengths = [] + max_variables_length = 0 + + while True: + # EOF + if final_lines_index + len(all_pa_variables_lengths) == len( + final_lines): + break + + this_line_index = final_lines_index + len(all_pa_variables_lengths) + this_line = final_lines[this_line_index] + + next_line = None + if this_line_index < len(final_lines) - 1: + next_line = final_lines[final_lines_index + + len(all_pa_variables_lengths) + 1] + + assert this_line.tokens, next_line.tokens + + # align them differently when there is a blank line in between + if (all_pa_variables_lengths and + this_line.tokens[0].formatted_whitespace_prefix.startswith('\n\n') + ): + break + + # if there is a standalone comment or keyword statement line + # or other lines without assignment in between, break + elif (all_pa_variables_lengths and + True not in [tok.is_assign or tok.is_augassign + for tok in this_line.tokens]): + if this_line.tokens[0].is_comment: + if style.Get('NEW_ALIGNMENT_AFTER_COMMENTLINE'): break + else: + break + + if this_line.disable: + all_pa_variables_lengths.append([]) + continue + + variables_content = '' + pa_variables_lengths = [] + contain_object = False + line_tokens = this_line.tokens + # only one assignment expression is on each line + for index in range(len(line_tokens)): + line_tok = line_tokens[index] + + prefix = line_tok.formatted_whitespace_prefix + newline_index = prefix.rfind('\n') + if newline_index != -1: + variables_content = '' + prefix = prefix[newline_index + 1:] + + if line_tok.is_assign or line_tok.is_augassign: + next_toks = [ + line_tokens[i] for i in range(index + 1, len(line_tokens)) + ] + # if there is object(list/tuple/dict) with newline entries, break, + # update the alignment so far and start to calulate new alignment + for tok in next_toks: + if tok.value in ['(', '[', '{'] and tok.next_token: + if (tok.next_token.formatted_whitespace_prefix.startswith( + '\n') or + (tok.next_token.is_comment and tok.next_token.next_token + .formatted_whitespace_prefix.startswith('\n'))): + pa_variables_lengths.append(len(variables_content)) + contain_object = True + break + if not contain_object: + if line_tok.is_assign: + pa_variables_lengths.append(len(variables_content)) + # if augassign, add the extra augmented part to the max length caculation + elif line_tok.is_augassign: + pa_variables_lengths.append( + len(variables_content) + len(line_tok.value) - 1) + # don't add the tokens + # after the assignment operator + break + else: + variables_content += '{}{}'.format(prefix, line_tok.value) + + if pa_variables_lengths: + max_variables_length = max( + max_variables_length, max(pa_variables_lengths)) + + all_pa_variables_lengths.append(pa_variables_lengths) + + # after saving this line's max variable length, + # we check if next line has the same depth as this line, + # if not, we don't want to calculate their max variable length together + # so we break the while loop, update alignment so far, and + # then go to next line that has '=' + if next_line: + if this_line.depth != next_line.depth: + break + # if this line contains objects with newline entries, + # start new block alignment + if contain_object: + break + + # if no update of max_length, just go to the next block + if max_variables_length == 0: + continue + + max_variables_length += 2 + + # Update the assignment token values based on the max variable length + for all_pa_variables_lengths_index, pa_variables_lengths in enumerate( + all_pa_variables_lengths): + if not pa_variables_lengths: + continue + this_line = final_lines[final_lines_index + + all_pa_variables_lengths_index] + + # only the first assignment operator on each line + pa_variables_lengths_index = 0 + for line_tok in this_line.tokens: + if line_tok.is_assign or line_tok.is_augassign: + assert pa_variables_lengths[0] < max_variables_length + + if pa_variables_lengths_index < len(pa_variables_lengths): + whitespace = ' ' * ( + max_variables_length - pa_variables_lengths[0] - 1) + + assign_content = '{}{}'.format( + whitespace, line_tok.value.strip()) + + existing_whitespace_prefix = \ + line_tok.formatted_whitespace_prefix.lstrip('\n') + + # in case the existing spaces are larger than padded spaces + if (len(whitespace) == 1 or len(whitespace) > 1 and + len(existing_whitespace_prefix) > len(whitespace)): + line_tok.whitespace_prefix = '' + elif assign_content.startswith(existing_whitespace_prefix): + assign_content = assign_content[ + len(existing_whitespace_prefix):] - if not process_content: - final_lines_index += 1 + # update the assignment operator value + line_tok.value = assign_content + pa_variables_lengths_index += 1 -def _FormatFinalLines( final_lines, verify ): - """Compose the final output from the finalized lines.""" - formatted_code = [] - for line in final_lines: - formatted_line = [] - for tok in line.tokens: - if not tok.is_pseudo: - formatted_line.append( tok.formatted_whitespace_prefix ) - formatted_line.append( tok.value ) - elif ( not tok.next_token.whitespace_prefix.startswith( '\n' ) and - not tok.next_token.whitespace_prefix.startswith( ' ' ) ): - if ( tok.previous_token.value == ':' or - tok.next_token.value not in ',}])' ): - formatted_line.append( ' ' ) + final_lines_index += len(all_pa_variables_lengths) - formatted_code.append( ''.join( formatted_line ) ) - if verify: - verifier.VerifyCode( formatted_code[ -1 ] ) + process_content = True + break - return ''.join( formatted_code ) + '\n' + if not process_content: + final_lines_index += 1 -class _StateNode( object ): - """An edge in the solution space from 'previous.state' to 'state'. +def _FormatFinalLines(final_lines, verify): + """Compose the final output from the finalized lines.""" + formatted_code = [] + for line in final_lines: + formatted_line = [] + for tok in line.tokens: + if not tok.is_pseudo: + formatted_line.append(tok.formatted_whitespace_prefix) + formatted_line.append(tok.value) + elif (not tok.next_token.whitespace_prefix.startswith('\n') and + not tok.next_token.whitespace_prefix.startswith(' ')): + if (tok.previous_token.value == ':' or + tok.next_token.value not in ',}])'): + formatted_line.append(' ') + + formatted_code.append(''.join(formatted_line)) + if verify: + verifier.VerifyCode(formatted_code[-1]) + + return ''.join(formatted_code) + '\n' + + +class _StateNode(object): + """An edge in the solution space from 'previous.state' to 'state'. Attributes: state: (format_decision_state.FormatDecisionState) The format decision state @@ -614,31 +598,32 @@ class _StateNode( object ): previous: (_StateNode) The previous state node in the graph. """ - # TODO(morbo): Add a '__cmp__' method. + # TODO(morbo): Add a '__cmp__' method. - def __init__( self, state, newline, previous ): - self.state = state.Clone() - self.newline = newline - self.previous = previous + def __init__(self, state, newline, previous): + self.state = state.Clone() + self.newline = newline + self.previous = previous - def __repr__( self ): # pragma: no cover - return 'StateNode(state=[\n{0}\n], newline={1})'.format( - self.state, self.newline ) + def __repr__(self): # pragma: no cover + return 'StateNode(state=[\n{0}\n], newline={1})'.format( + self.state, self.newline) # A tuple of (penalty, count) that is used to prioritize the BFS. In case of # equal penalties, we prefer states that were inserted first. During state # generation, we make sure that we insert states first that break the line as # late as possible. -_OrderedPenalty = collections.namedtuple( 'OrderedPenalty', [ 'penalty', 'count' ] ) +_OrderedPenalty = collections.namedtuple('OrderedPenalty', ['penalty', 'count']) # An item in the prioritized BFS search queue. The 'StateNode's 'state' has # the given '_OrderedPenalty'. -_QueueItem = collections.namedtuple( 'QueueItem', [ 'ordered_penalty', 'state_node' ] ) +_QueueItem = collections.namedtuple( + 'QueueItem', ['ordered_penalty', 'state_node']) -def _AnalyzeSolutionSpace( initial_state ): - """Analyze the entire solution space starting from initial_state. +def _AnalyzeSolutionSpace(initial_state): + """Analyze the entire solution space starting from initial_state. This implements a variant of Dijkstra's algorithm on the graph that spans the solution space (LineStates are the nodes). The algorithm tries to find @@ -652,49 +637,49 @@ def _AnalyzeSolutionSpace( initial_state ): Returns: True if a formatting solution was found. False otherwise. """ - count = 0 - seen = set() - p_queue = [] - - # Insert start element. - node = _StateNode( initial_state, False, None ) - heapq.heappush( p_queue, _QueueItem( _OrderedPenalty( 0, count ), node ) ) - - count += 1 - while p_queue: - item = p_queue[ 0 ] - penalty = item.ordered_penalty.penalty - node = item.state_node - if not node.state.next_token: - break - heapq.heappop( p_queue ) - - if count > 10000: - node.state.ignore_stack_for_comparison = True - - # Unconditionally add the state and check if it was present to avoid having - # to hash it twice in the common case (state hashing is expensive). - before_seen_count = len( seen ) - seen.add( node.state ) - # If seen didn't change size, the state was already present. - if before_seen_count == len( seen ): - continue - - # FIXME(morbo): Add a 'decision' element? - - count = _AddNextStateToQueue( penalty, node, False, count, p_queue ) - count = _AddNextStateToQueue( penalty, node, True, count, p_queue ) - - if not p_queue: - # We weren't able to find a solution. Do nothing. - return False + count = 0 + seen = set() + p_queue = [] + + # Insert start element. + node = _StateNode(initial_state, False, None) + heapq.heappush(p_queue, _QueueItem(_OrderedPenalty(0, count), node)) + + count += 1 + while p_queue: + item = p_queue[0] + penalty = item.ordered_penalty.penalty + node = item.state_node + if not node.state.next_token: + break + heapq.heappop(p_queue) + + if count > 10000: + node.state.ignore_stack_for_comparison = True + + # Unconditionally add the state and check if it was present to avoid having + # to hash it twice in the common case (state hashing is expensive). + before_seen_count = len(seen) + seen.add(node.state) + # If seen didn't change size, the state was already present. + if before_seen_count == len(seen): + continue + + # FIXME(morbo): Add a 'decision' element? + + count = _AddNextStateToQueue(penalty, node, False, count, p_queue) + count = _AddNextStateToQueue(penalty, node, True, count, p_queue) + + if not p_queue: + # We weren't able to find a solution. Do nothing. + return False - _ReconstructPath( initial_state, heapq.heappop( p_queue ).state_node ) - return True + _ReconstructPath(initial_state, heapq.heappop(p_queue).state_node) + return True -def _AddNextStateToQueue( penalty, previous_node, newline, count, p_queue ): - """Add the following state to the analysis queue. +def _AddNextStateToQueue(penalty, previous_node, newline, count, p_queue): + """Add the following state to the analysis queue. Assume the current state is 'previous_node' and has been reached with a penalty of 'penalty'. Insert a line break if 'newline' is True. @@ -710,23 +695,23 @@ def _AddNextStateToQueue( penalty, previous_node, newline, count, p_queue ): Returns: The updated number of elements in the queue. """ - must_split = previous_node.state.MustSplit() - if newline and not previous_node.state.CanSplit( must_split ): - # Don't add a newline if the token cannot be split. - return count - if not newline and must_split: - # Don't add a token we must split but where we aren't splitting. - return count + must_split = previous_node.state.MustSplit() + if newline and not previous_node.state.CanSplit(must_split): + # Don't add a newline if the token cannot be split. + return count + if not newline and must_split: + # Don't add a token we must split but where we aren't splitting. + return count - node = _StateNode( previous_node.state, newline, previous_node ) - penalty += node.state.AddTokenToState( - newline = newline, dry_run = True, must_split = must_split ) - heapq.heappush( p_queue, _QueueItem( _OrderedPenalty( penalty, count ), node ) ) - return count + 1 + node = _StateNode(previous_node.state, newline, previous_node) + penalty += node.state.AddTokenToState( + newline=newline, dry_run=True, must_split=must_split) + heapq.heappush(p_queue, _QueueItem(_OrderedPenalty(penalty, count), node)) + return count + 1 -def _ReconstructPath( initial_state, current ): - """Reconstruct the path through the queue with lowest penalty. +def _ReconstructPath(initial_state, current): + """Reconstruct the path through the queue with lowest penalty. Arguments: initial_state: (format_decision_state.FormatDecisionState) The initial state @@ -734,21 +719,21 @@ def _ReconstructPath( initial_state, current ): current: (_StateNode) The node in the decision graph that is the end point of the path with the least penalty. """ - path = collections.deque() + path = collections.deque() - while current.previous: - path.appendleft( current ) - current = current.previous + while current.previous: + path.appendleft(current) + current = current.previous - for node in path: - initial_state.AddTokenToState( newline = node.newline, dry_run = False ) + for node in path: + initial_state.AddTokenToState(newline=node.newline, dry_run=False) NESTED_DEPTH = [] -def _FormatFirstToken( first_token, indent_depth, prev_line, final_lines ): - """Format the first token in the logical line. +def _FormatFirstToken(first_token, indent_depth, prev_line, final_lines): + """Format the first token in the logical line. Add a newline and the required indent before the first token of the logical line. @@ -761,22 +746,22 @@ def _FormatFirstToken( first_token, indent_depth, prev_line, final_lines ): final_lines: (list of logical_line.LogicalLine) The logical lines that have already been processed. """ - global NESTED_DEPTH - while NESTED_DEPTH and NESTED_DEPTH[ -1 ] > indent_depth: - NESTED_DEPTH.pop() + global NESTED_DEPTH + while NESTED_DEPTH and NESTED_DEPTH[-1] > indent_depth: + NESTED_DEPTH.pop() - first_nested = False - if _IsClassOrDef( first_token ): - if not NESTED_DEPTH: - NESTED_DEPTH = [ indent_depth ] - elif NESTED_DEPTH[ -1 ] < indent_depth: - first_nested = True - NESTED_DEPTH.append( indent_depth ) + first_nested = False + if _IsClassOrDef(first_token): + if not NESTED_DEPTH: + NESTED_DEPTH = [indent_depth] + elif NESTED_DEPTH[-1] < indent_depth: + first_nested = True + NESTED_DEPTH.append(indent_depth) - first_token.AddWhitespacePrefix( - _CalculateNumberOfNewlines( - first_token, indent_depth, prev_line, final_lines, first_nested ), - indent_level = indent_depth ) + first_token.AddWhitespacePrefix( + _CalculateNumberOfNewlines( + first_token, indent_depth, prev_line, final_lines, first_nested), + indent_level=indent_depth) NO_BLANK_LINES = 1 @@ -784,15 +769,16 @@ def _FormatFirstToken( first_token, indent_depth, prev_line, final_lines ): TWO_BLANK_LINES = 3 -def _IsClassOrDef( tok ): - if tok.value in { 'class', 'def', '@' }: - return True - return ( tok.next_token and tok.value == 'async' and tok.next_token.value == 'def' ) +def _IsClassOrDef(tok): + if tok.value in {'class', 'def', '@'}: + return True + return ( + tok.next_token and tok.value == 'async' and tok.next_token.value == 'def') def _CalculateNumberOfNewlines( - first_token, indent_depth, prev_line, final_lines, first_nested ): - """Calculate the number of newlines we need to add. + first_token, indent_depth, prev_line, final_lines, first_nested): + """Calculate the number of newlines we need to add. Arguments: first_token: (format_token.FormatToken) The first token in the logical @@ -807,103 +793,102 @@ def _CalculateNumberOfNewlines( Returns: The number of newlines needed before the first token. """ - # TODO(morbo): Special handling for imports. - # TODO(morbo): Create a knob that can tune these. - if prev_line is None: - # The first line in the file. Don't add blank lines. - # FIXME(morbo): Is this correct? - if first_token.newlines is not None: + # TODO(morbo): Special handling for imports. + # TODO(morbo): Create a knob that can tune these. + if prev_line is None: + # The first line in the file. Don't add blank lines. + # FIXME(morbo): Is this correct? + if first_token.newlines is not None: + first_token.newlines = None + return 0 + + if first_token.is_docstring: + if (prev_line.first.value == 'class' and + style.Get('BLANK_LINE_BEFORE_CLASS_DOCSTRING')): + # Enforce a blank line before a class's docstring. + return ONE_BLANK_LINE + elif (prev_line.first.value.startswith('#') and + style.Get('BLANK_LINE_BEFORE_MODULE_DOCSTRING')): + # Enforce a blank line before a module's docstring. + return ONE_BLANK_LINE + # The docstring shouldn't have a newline before it. + return NO_BLANK_LINES + + if first_token.is_name and not indent_depth: + if prev_line.first.value in {'from', 'import'}: + # Support custom number of blank lines between top-level imports and + # variable definitions. + return 1 + style.Get( + 'BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES') + + prev_last_token = prev_line.last + if prev_last_token.is_docstring: + if (not indent_depth and first_token.value in {'class', 'def', 'async'}): + # Separate a class or function from the module-level docstring with + # appropriate number of blank lines. + return 1 + style.Get('BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION') + if (first_nested and + not style.Get('BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF') and + _IsClassOrDef(first_token)): + first_token.newlines = None + return NO_BLANK_LINES + if _NoBlankLinesBeforeCurrentToken(prev_last_token.value, first_token, + prev_last_token): + return NO_BLANK_LINES + else: + return ONE_BLANK_LINE + + if _IsClassOrDef(first_token): + # TODO(morbo): This can go once the blank line calculator is more + # sophisticated. + if not indent_depth: + # This is a top-level class or function. + is_inline_comment = prev_last_token.whitespace_prefix.count('\n') == 0 + if (not prev_line.disable and prev_last_token.is_comment and + not is_inline_comment): + # This token follows a non-inline comment. + if _NoBlankLinesBeforeCurrentToken(prev_last_token.value, first_token, + prev_last_token): + # Assume that the comment is "attached" to the current line. + # Therefore, we want two blank lines before the comment. + index = len(final_lines) - 1 + while index > 0: + if not final_lines[index - 1].is_comment: + break + index -= 1 + if final_lines[index - 1].first.value == '@': + final_lines[index].first.AdjustNewlinesBefore(NO_BLANK_LINES) + else: + prev_last_token.AdjustNewlinesBefore( + 1 + style.Get('BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION')) + if first_token.newlines is not None: first_token.newlines = None - return 0 - - if first_token.is_docstring: - if ( prev_line.first.value == 'class' and - style.Get( 'BLANK_LINE_BEFORE_CLASS_DOCSTRING' ) ): - # Enforce a blank line before a class's docstring. - return ONE_BLANK_LINE - elif ( prev_line.first.value.startswith( '#' ) and - style.Get( 'BLANK_LINE_BEFORE_MODULE_DOCSTRING' ) ): - # Enforce a blank line before a module's docstring. - return ONE_BLANK_LINE - # The docstring shouldn't have a newline before it. + return NO_BLANK_LINES + elif _IsClassOrDef(prev_line.first): + if first_nested and not style.Get( + 'BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'): + first_token.newlines = None return NO_BLANK_LINES - if first_token.is_name and not indent_depth: - if prev_line.first.value in { 'from', 'import' }: - # Support custom number of blank lines between top-level imports and - # variable definitions. - return 1 + style.Get( - 'BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES' ) - - prev_last_token = prev_line.last - if prev_last_token.is_docstring: - if ( not indent_depth and first_token.value in { 'class', 'def', 'async' } ): - # Separate a class or function from the module-level docstring with - # appropriate number of blank lines. - return 1 + style.Get( 'BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION' ) - if ( first_nested and - not style.Get( 'BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF' ) and - _IsClassOrDef( first_token ) ): - first_token.newlines = None - return NO_BLANK_LINES - if _NoBlankLinesBeforeCurrentToken( prev_last_token.value, first_token, - prev_last_token ): - return NO_BLANK_LINES - else: - return ONE_BLANK_LINE - - if _IsClassOrDef( first_token ): - # TODO(morbo): This can go once the blank line calculator is more - # sophisticated. - if not indent_depth: - # This is a top-level class or function. - is_inline_comment = prev_last_token.whitespace_prefix.count( '\n' ) == 0 - if ( not prev_line.disable and prev_last_token.is_comment and - not is_inline_comment ): - # This token follows a non-inline comment. - if _NoBlankLinesBeforeCurrentToken( prev_last_token.value, first_token, - prev_last_token ): - # Assume that the comment is "attached" to the current line. - # Therefore, we want two blank lines before the comment. - index = len( final_lines ) - 1 - while index > 0: - if not final_lines[ index - 1 ].is_comment: - break - index -= 1 - if final_lines[ index - 1 ].first.value == '@': - final_lines[ index ].first.AdjustNewlinesBefore( - NO_BLANK_LINES ) - else: - prev_last_token.AdjustNewlinesBefore( - 1 + style.Get( 'BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION' ) ) - if first_token.newlines is not None: - first_token.newlines = None - return NO_BLANK_LINES - elif _IsClassOrDef( prev_line.first ): - if first_nested and not style.Get( - 'BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF' ): - first_token.newlines = None - return NO_BLANK_LINES - - # Calculate how many newlines were between the original lines. We want to - # retain that formatting if it doesn't violate one of the style guide rules. - if first_token.is_comment: - first_token_lineno = first_token.lineno - first_token.value.count( '\n' ) - else: - first_token_lineno = first_token.lineno + # Calculate how many newlines were between the original lines. We want to + # retain that formatting if it doesn't violate one of the style guide rules. + if first_token.is_comment: + first_token_lineno = first_token.lineno - first_token.value.count('\n') + else: + first_token_lineno = first_token.lineno - prev_last_token_lineno = prev_last_token.lineno - if prev_last_token.is_multiline_string: - prev_last_token_lineno += prev_last_token.value.count( '\n' ) + prev_last_token_lineno = prev_last_token.lineno + if prev_last_token.is_multiline_string: + prev_last_token_lineno += prev_last_token.value.count('\n') - if first_token_lineno - prev_last_token_lineno > 1: - return ONE_BLANK_LINE + if first_token_lineno - prev_last_token_lineno > 1: + return ONE_BLANK_LINE - return NO_BLANK_LINES + return NO_BLANK_LINES -def _SingleOrMergedLines( lines ): - """Generate the lines we want to format. +def _SingleOrMergedLines(lines): + """Generate the lines we want to format. Arguments: lines: (list of logical_line.LogicalLine) Lines we want to format. @@ -912,49 +897,46 @@ def _SingleOrMergedLines( lines ): Either a single line, if the current line cannot be merged with the succeeding line, or the next two lines merged into one line. """ - index = 0 - last_was_merged = False - while index < len( lines ): - if lines[ index ].disable: - line = lines[ index ] - index += 1 - while index < len( lines ): - column = line.last.column + 2 - if lines[ index ].lineno != line.lineno: - break - if line.last.value != ':': - leaf = pytree.Leaf( - type = token.SEMI, - value = ';', - context = ( '', ( line.lineno, column ) ) ) - line.AppendToken( - format_token.FormatToken( leaf, - pytree_utils.NodeName( leaf ) ) ) - for tok in lines[ index ].tokens: - line.AppendToken( tok ) - index += 1 - yield line - elif line_joiner.CanMergeMultipleLines( lines[ index : ], last_was_merged ): - # TODO(morbo): This splice is potentially very slow. Come up with a more - # performance-friendly way of determining if two lines can be merged. - next_line = lines[ index + 1 ] - for tok in next_line.tokens: - lines[ index ].AppendToken( tok ) - if ( len( next_line.tokens ) == 1 and next_line.first.is_multiline_string ): - # This may be a multiline shebang. In that case, we want to retain the - # formatting. Otherwise, it could mess up the shell script's syntax. - lines[ index ].disable = True - yield lines[ index ] - index += 2 - last_was_merged = True - else: - yield lines[ index ] - index += 1 - last_was_merged = False - - -def _NoBlankLinesBeforeCurrentToken( text, cur_token, prev_token ): - """Determine if there are no blank lines before the current token. + index = 0 + last_was_merged = False + while index < len(lines): + if lines[index].disable: + line = lines[index] + index += 1 + while index < len(lines): + column = line.last.column + 2 + if lines[index].lineno != line.lineno: + break + if line.last.value != ':': + leaf = pytree.Leaf( + type=token.SEMI, value=';', context=('', (line.lineno, column))) + line.AppendToken( + format_token.FormatToken(leaf, pytree_utils.NodeName(leaf))) + for tok in lines[index].tokens: + line.AppendToken(tok) + index += 1 + yield line + elif line_joiner.CanMergeMultipleLines(lines[index:], last_was_merged): + # TODO(morbo): This splice is potentially very slow. Come up with a more + # performance-friendly way of determining if two lines can be merged. + next_line = lines[index + 1] + for tok in next_line.tokens: + lines[index].AppendToken(tok) + if (len(next_line.tokens) == 1 and next_line.first.is_multiline_string): + # This may be a multiline shebang. In that case, we want to retain the + # formatting. Otherwise, it could mess up the shell script's syntax. + lines[index].disable = True + yield lines[index] + index += 2 + last_was_merged = True + else: + yield lines[index] + index += 1 + last_was_merged = False + + +def _NoBlankLinesBeforeCurrentToken(text, cur_token, prev_token): + """Determine if there are no blank lines before the current token. The previous token is a docstring or comment. The prev_token_lineno is the start of the text of that token. Counting the number of newlines in its text @@ -972,8 +954,8 @@ def _NoBlankLinesBeforeCurrentToken( text, cur_token, prev_token ): Returns: True if there is no blank line before the current token. """ - cur_token_lineno = cur_token.lineno - if cur_token.is_comment: - cur_token_lineno -= cur_token.value.count( '\n' ) - num_newlines = text.count( '\n' ) if not prev_token.is_comment else 0 - return prev_token.lineno + num_newlines == cur_token_lineno - 1 + cur_token_lineno = cur_token.lineno + if cur_token.is_comment: + cur_token_lineno -= cur_token.value.count('\n') + num_newlines = text.count('\n') if not prev_token.is_comment else 0 + return prev_token.lineno + num_newlines == cur_token_lineno - 1 diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 684bfb274..820952492 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -21,53 +21,53 @@ from yapf.yapflib import py3compat -class StyleConfigError( errors.YapfError ): - """Raised when there's a problem reading the style configuration.""" - pass +class StyleConfigError(errors.YapfError): + """Raised when there's a problem reading the style configuration.""" + pass -def Get( setting_name ): - """Get a style setting.""" - return _style[ setting_name ] +def Get(setting_name): + """Get a style setting.""" + return _style[setting_name] -def GetOrDefault( setting_name, default_value ): - """Get a style setting or default value if the setting does not exist.""" - return _style.get( setting_name, default_value ) +def GetOrDefault(setting_name, default_value): + """Get a style setting or default value if the setting does not exist.""" + return _style.get(setting_name, default_value) def Help(): - """Return dict mapping style names to help strings.""" - return _STYLE_HELP + """Return dict mapping style names to help strings.""" + return _STYLE_HELP -def SetGlobalStyle( style ): - """Set a style dict.""" - global _style - global _GLOBAL_STYLE_FACTORY - factory = _GetStyleFactory( style ) - if factory: - _GLOBAL_STYLE_FACTORY = factory - _style = style +def SetGlobalStyle(style): + """Set a style dict.""" + global _style + global _GLOBAL_STYLE_FACTORY + factory = _GetStyleFactory(style) + if factory: + _GLOBAL_STYLE_FACTORY = factory + _style = style _STYLE_HELP = dict( - ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT = textwrap.dedent( + ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=textwrap.dedent( """\ - Align closing bracket with visual indentation.""" ), - ALIGN_ASSIGNMENT = textwrap.dedent( + Align closing bracket with visual indentation."""), + ALIGN_ASSIGNMENT=textwrap.dedent( """\ Align assignment or augmented assignment operators. If there is a blank line or newline comment or objects with newline entries in between, - it will start new block alignment.""" ), - NEW_ALIGNMENT_AFTER_COMMENTLINE = textwrap.dedent( + it will start new block alignment."""), + NEW_ALIGNMENT_AFTER_COMMENTLINE=textwrap.dedent( """\ Start new assignment or colon alignment when there is a newline comment in between.""" ), - ALLOW_MULTILINE_LAMBDAS = textwrap.dedent( + ALLOW_MULTILINE_LAMBDAS=textwrap.dedent( """\ - Allow lambdas to be formatted on more than one line.""" ), - ALLOW_MULTILINE_DICTIONARY_KEYS = textwrap.dedent( + Allow lambdas to be formatted on more than one line."""), + ALLOW_MULTILINE_DICTIONARY_KEYS=textwrap.dedent( """\ Allow dictionary keys to exist on multiple lines. For example: @@ -75,15 +75,15 @@ def SetGlobalStyle( style ): ('this is the first element of a tuple', 'this is the second element of a tuple'): value, - }""" ), - ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS = textwrap.dedent( + }"""), + ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=textwrap.dedent( """\ Allow splitting before a default / named assignment in an argument list. - """ ), - ALLOW_SPLIT_BEFORE_DICT_VALUE = textwrap.dedent( + """), + ALLOW_SPLIT_BEFORE_DICT_VALUE=textwrap.dedent( """\ - Allow splits before the dictionary value.""" ), - ARITHMETIC_PRECEDENCE_INDICATION = textwrap.dedent( + Allow splits before the dictionary value."""), + ARITHMETIC_PRECEDENCE_INDICATION=textwrap.dedent( """\ Let spacing indicate operator precedence. For example: @@ -103,8 +103,8 @@ def SetGlobalStyle( style ): e = 1*2 - 3 f = 1 + 2 + 3 + 4 - """ ), - BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF = textwrap.dedent( + """), + BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=textwrap.dedent( """\ Insert a blank line before a 'def' or 'class' immediately nested within another 'def' or 'class'. For example: @@ -112,22 +112,22 @@ def SetGlobalStyle( style ): class Foo: # <------ this blank line def method(): - ...""" ), - BLANK_LINE_BEFORE_CLASS_DOCSTRING = textwrap.dedent( + ..."""), + BLANK_LINE_BEFORE_CLASS_DOCSTRING=textwrap.dedent( """\ - Insert a blank line before a class-level docstring.""" ), - BLANK_LINE_BEFORE_MODULE_DOCSTRING = textwrap.dedent( + Insert a blank line before a class-level docstring."""), + BLANK_LINE_BEFORE_MODULE_DOCSTRING=textwrap.dedent( """\ - Insert a blank line before a module docstring.""" ), - BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION = textwrap.dedent( + Insert a blank line before a module docstring."""), + BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=textwrap.dedent( """\ Number of blank lines surrounding top-level function and class - definitions.""" ), - BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES = textwrap.dedent( + definitions."""), + BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES=textwrap.dedent( """\ Number of blank lines between top-level imports and variable - definitions.""" ), - COALESCE_BRACKETS = textwrap.dedent( + definitions."""), + COALESCE_BRACKETS=textwrap.dedent( """\ Do not split consecutive brackets. Only relevant when dedent_closing_brackets is set. For example: @@ -144,10 +144,10 @@ def method(): call_func_that_takes_a_dict({ 'key1': 'value1', 'key2': 'value2', - })""" ), - COLUMN_LIMIT = textwrap.dedent( """\ - The column limit.""" ), - CONTINUATION_ALIGN_STYLE = textwrap.dedent( + })"""), + COLUMN_LIMIT=textwrap.dedent("""\ + The column limit."""), + CONTINUATION_ALIGN_STYLE=textwrap.dedent( """\ The style for continuation alignment. Possible values are: @@ -157,11 +157,11 @@ def method(): CONTINUATION_INDENT_WIDTH spaces) for continuation alignment. - VALIGN-RIGHT: Vertically align continuation lines to multiple of INDENT_WIDTH columns. Slightly right (one tab or a few spaces) if - cannot vertically align continuation lines with indent characters.""" ), - CONTINUATION_INDENT_WIDTH = textwrap.dedent( + cannot vertically align continuation lines with indent characters."""), + CONTINUATION_INDENT_WIDTH=textwrap.dedent( """\ - Indent width used for line continuations.""" ), - DEDENT_CLOSING_BRACKETS = textwrap.dedent( + Indent width used for line continuations."""), + DEDENT_CLOSING_BRACKETS=textwrap.dedent( """\ Put closing brackets on a separate line, dedented, if the bracketed expression can't fit in a single line. Applies to all kinds of brackets, @@ -179,33 +179,33 @@ def method(): start_ts=now()-timedelta(days=3), end_ts=now(), ) # <--- this bracket is dedented and on a separate line - """ ), - DISABLE_ENDING_COMMA_HEURISTIC = textwrap.dedent( + """), + DISABLE_ENDING_COMMA_HEURISTIC=textwrap.dedent( """\ Disable the heuristic which places each list element on a separate line - if the list is comma-terminated.""" ), - EACH_DICT_ENTRY_ON_SEPARATE_LINE = textwrap.dedent( + if the list is comma-terminated."""), + EACH_DICT_ENTRY_ON_SEPARATE_LINE=textwrap.dedent( """\ - Place each dictionary entry onto its own line.""" ), - FORCE_MULTILINE_DICT = textwrap.dedent( + Place each dictionary entry onto its own line."""), + FORCE_MULTILINE_DICT=textwrap.dedent( """\ Require multiline dictionary even if it would normally fit on one line. For example: config = { 'key1': 'value1' - }""" ), - I18N_COMMENT = textwrap.dedent( + }"""), + I18N_COMMENT=textwrap.dedent( """\ The regex for an i18n comment. The presence of this comment stops reformatting of that line, because the comments are required to be - next to the string they translate.""" ), - I18N_FUNCTION_CALL = textwrap.dedent( + next to the string they translate."""), + I18N_FUNCTION_CALL=textwrap.dedent( """\ The i18n function call names. The presence of this function stops reformattting on that line, because the string it has cannot be moved - away from the i18n comment.""" ), - INDENT_CLOSING_BRACKETS = textwrap.dedent( + away from the i18n comment."""), + INDENT_CLOSING_BRACKETS=textwrap.dedent( """\ Put closing brackets on a separate line, indented, if the bracketed expression can't fit in a single line. Applies to all kinds of brackets, @@ -223,8 +223,8 @@ def method(): start_ts=now()-timedelta(days=3), end_ts=now(), ) # <--- this bracket is indented and on a separate line - """ ), - INDENT_DICTIONARY_VALUE = textwrap.dedent( + """), + INDENT_DICTIONARY_VALUE=textwrap.dedent( """\ Indent the dictionary value if it cannot fit on the same line as the dictionary key. For example: @@ -235,16 +235,16 @@ def method(): 'key2': value1 + value2, } - """ ), - INDENT_WIDTH = textwrap.dedent( + """), + INDENT_WIDTH=textwrap.dedent( """\ - The number of columns to use for indentation.""" ), - INDENT_BLANK_LINES = textwrap.dedent( """\ - Indent blank lines.""" ), - JOIN_MULTIPLE_LINES = textwrap.dedent( + The number of columns to use for indentation."""), + INDENT_BLANK_LINES=textwrap.dedent("""\ + Indent blank lines."""), + JOIN_MULTIPLE_LINES=textwrap.dedent( """\ - Join short lines into one line. E.g., single line 'if' statements.""" ), - NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS = textwrap.dedent( + Join short lines into one line. E.g., single line 'if' statements."""), + NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=textwrap.dedent( """\ Do not include spaces around selected binary operators. For example: @@ -253,26 +253,26 @@ def method(): will be formatted as follows when configured with "*,/": 1 + 2*3 - 4/5 - """ ), - SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET = textwrap.dedent( + """), + SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=textwrap.dedent( """\ Insert a space between the ending comma and closing bracket of a list, - etc.""" ), - SPACE_INSIDE_BRACKETS = textwrap.dedent( + etc."""), + SPACE_INSIDE_BRACKETS=textwrap.dedent( """\ Use spaces inside brackets, braces, and parentheses. For example: method_call( 1 ) my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] my_set = { 1, 2, 3 } - """ ), - SPACES_AROUND_POWER_OPERATOR = textwrap.dedent( + """), + SPACES_AROUND_POWER_OPERATOR=textwrap.dedent( """\ - Use spaces around the power operator.""" ), - SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN = textwrap.dedent( + Use spaces around the power operator."""), + SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=textwrap.dedent( """\ - Use spaces around default or named assigns.""" ), - SPACES_AROUND_DICT_DELIMITERS = textwrap.dedent( + Use spaces around default or named assigns."""), + SPACES_AROUND_DICT_DELIMITERS=textwrap.dedent( """\ Adds a space after the opening '{' and before the ending '}' dict delimiters. @@ -282,8 +282,8 @@ def method(): will be formatted as: { 1: 2 } - """ ), - SPACES_AROUND_LIST_DELIMITERS = textwrap.dedent( + """), + SPACES_AROUND_LIST_DELIMITERS=textwrap.dedent( """\ Adds a space after the opening '[' and before the ending ']' list delimiters. @@ -293,14 +293,14 @@ def method(): will be formatted as: [ 1, 2 ] - """ ), - SPACES_AROUND_SUBSCRIPT_COLON = textwrap.dedent( + """), + SPACES_AROUND_SUBSCRIPT_COLON=textwrap.dedent( """\ Use spaces around the subscript / slice operator. For example: my_list[1 : 10 : 2] - """ ), - SPACES_AROUND_TUPLE_DELIMITERS = textwrap.dedent( + """), + SPACES_AROUND_TUPLE_DELIMITERS=textwrap.dedent( """\ Adds a space after the opening '(' and before the ending ')' tuple delimiters. @@ -310,8 +310,8 @@ def method(): will be formatted as: ( 1, 2, 3 ) - """ ), - SPACES_BEFORE_COMMENT = textwrap.dedent( + """), + SPACES_BEFORE_COMMENT=textwrap.dedent( """\ The number of spaces required before a trailing comment. This can be a single value (representing the number of spaces @@ -353,31 +353,31 @@ def method(): a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length short # This is a shorter statement - """ ), # noqa - SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED = textwrap.dedent( + """), # noqa + SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=textwrap.dedent( """\ Split before arguments if the argument list is terminated by a - comma.""" ), - SPLIT_ALL_COMMA_SEPARATED_VALUES = textwrap.dedent( + comma."""), + SPLIT_ALL_COMMA_SEPARATED_VALUES=textwrap.dedent( """\ - Split before arguments""" ), - SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES = textwrap.dedent( + Split before arguments"""), + SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=textwrap.dedent( """\ Split before arguments, but do not split all subexpressions recursively - (unless needed).""" ), - SPLIT_BEFORE_ARITHMETIC_OPERATOR = textwrap.dedent( + (unless needed)."""), + SPLIT_BEFORE_ARITHMETIC_OPERATOR=textwrap.dedent( """\ Set to True to prefer splitting before '+', '-', '*', '/', '//', or '@' - rather than after.""" ), - SPLIT_BEFORE_BITWISE_OPERATOR = textwrap.dedent( + rather than after."""), + SPLIT_BEFORE_BITWISE_OPERATOR=textwrap.dedent( """\ Set to True to prefer splitting before '&', '|' or '^' rather than - after.""" ), - SPLIT_BEFORE_CLOSING_BRACKET = textwrap.dedent( + after."""), + SPLIT_BEFORE_CLOSING_BRACKET=textwrap.dedent( """\ Split before the closing bracket if a list or dict literal doesn't fit on - a single line.""" ), - SPLIT_BEFORE_DICT_SET_GENERATOR = textwrap.dedent( + a single line."""), + SPLIT_BEFORE_DICT_SET_GENERATOR=textwrap.dedent( """\ Split before a dictionary or set generator (comp_for). For example, note the split before the 'for': @@ -385,8 +385,8 @@ def method(): foo = { variable: 'Hello world, have a nice day!' for variable in bar if variable != 42 - }""" ), - SPLIT_BEFORE_DOT = textwrap.dedent( + }"""), + SPLIT_BEFORE_DOT=textwrap.dedent( """\ Split before the '.' if we need to split a longer expression: @@ -396,24 +396,24 @@ def method(): foo = ('This is a really long string: {}, {}, {}, {}' .format(a, b, c, d)) - """ ), # noqa - SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN = textwrap.dedent( + """), # noqa + SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=textwrap.dedent( """\ Split after the opening paren which surrounds an expression if it doesn't fit on a single line. - """ ), - SPLIT_BEFORE_FIRST_ARGUMENT = textwrap.dedent( + """), + SPLIT_BEFORE_FIRST_ARGUMENT=textwrap.dedent( """\ If an argument / parameter list is going to be split, then split before - the first argument.""" ), - SPLIT_BEFORE_LOGICAL_OPERATOR = textwrap.dedent( + the first argument."""), + SPLIT_BEFORE_LOGICAL_OPERATOR=textwrap.dedent( """\ Set to True to prefer splitting before 'and' or 'or' rather than - after.""" ), - SPLIT_BEFORE_NAMED_ASSIGNS = textwrap.dedent( + after."""), + SPLIT_BEFORE_NAMED_ASSIGNS=textwrap.dedent( """\ - Split named assignments onto individual lines.""" ), - SPLIT_COMPLEX_COMPREHENSION = textwrap.dedent( + Split named assignments onto individual lines."""), + SPLIT_COMPLEX_COMPREHENSION=textwrap.dedent( """\ Set to True to split list comprehensions and generators that have non-trivial expressions and multiple clauses before each of these @@ -429,36 +429,36 @@ def method(): a_long_var + 100 for a_long_var in xrange(1000) if a_long_var % 10] - """ ), - SPLIT_PENALTY_AFTER_OPENING_BRACKET = textwrap.dedent( + """), + SPLIT_PENALTY_AFTER_OPENING_BRACKET=textwrap.dedent( """\ - The penalty for splitting right after the opening bracket.""" ), - SPLIT_PENALTY_AFTER_UNARY_OPERATOR = textwrap.dedent( + The penalty for splitting right after the opening bracket."""), + SPLIT_PENALTY_AFTER_UNARY_OPERATOR=textwrap.dedent( """\ - The penalty for splitting the line after a unary operator.""" ), - SPLIT_PENALTY_ARITHMETIC_OPERATOR = textwrap.dedent( + The penalty for splitting the line after a unary operator."""), + SPLIT_PENALTY_ARITHMETIC_OPERATOR=textwrap.dedent( """\ The penalty of splitting the line around the '+', '-', '*', '/', '//', - ``%``, and '@' operators.""" ), - SPLIT_PENALTY_BEFORE_IF_EXPR = textwrap.dedent( + ``%``, and '@' operators."""), + SPLIT_PENALTY_BEFORE_IF_EXPR=textwrap.dedent( """\ - The penalty for splitting right before an if expression.""" ), - SPLIT_PENALTY_BITWISE_OPERATOR = textwrap.dedent( + The penalty for splitting right before an if expression."""), + SPLIT_PENALTY_BITWISE_OPERATOR=textwrap.dedent( """\ The penalty of splitting the line around the '&', '|', and '^' - operators.""" ), - SPLIT_PENALTY_COMPREHENSION = textwrap.dedent( + operators."""), + SPLIT_PENALTY_COMPREHENSION=textwrap.dedent( """\ The penalty for splitting a list comprehension or generator - expression.""" ), - SPLIT_PENALTY_EXCESS_CHARACTER = textwrap.dedent( + expression."""), + SPLIT_PENALTY_EXCESS_CHARACTER=textwrap.dedent( """\ - The penalty for characters over the column limit.""" ), - SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT = textwrap.dedent( + The penalty for characters over the column limit."""), + SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=textwrap.dedent( """\ The penalty incurred by adding a line split to the logical line. The - more line splits added the higher the penalty.""" ), - SPLIT_PENALTY_IMPORT_NAMES = textwrap.dedent( + more line splits added the higher the penalty."""), + SPLIT_PENALTY_IMPORT_NAMES=textwrap.dedent( """\ The penalty of splitting a list of "import as" names. For example: @@ -470,200 +470,201 @@ def method(): from a_very_long_or_indented_module_name_yada_yad import ( long_argument_1, long_argument_2, long_argument_3) - """ ), # noqa - SPLIT_PENALTY_LOGICAL_OPERATOR = textwrap.dedent( + """), # noqa + SPLIT_PENALTY_LOGICAL_OPERATOR=textwrap.dedent( """\ The penalty of splitting the line around the 'and' and 'or' - operators.""" ), - USE_TABS = textwrap.dedent( """\ - Use the Tab character for indentation.""" ), - # BASED_ON_STYLE='Which predefined style this style is based on', + operators."""), + USE_TABS=textwrap.dedent( + """\ + Use the Tab character for indentation."""), + # BASED_ON_STYLE='Which predefined style this style is based on', ) def CreatePEP8Style(): - """Create the PEP8 formatting style.""" - return dict( - ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT = True, - ALIGN_ASSIGNMENT = False, - NEW_ALIGNMENT_AFTER_COMMENTLINE = False, - ALLOW_MULTILINE_LAMBDAS = False, - ALLOW_MULTILINE_DICTIONARY_KEYS = False, - ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS = True, - ALLOW_SPLIT_BEFORE_DICT_VALUE = True, - ARITHMETIC_PRECEDENCE_INDICATION = False, - BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF = True, - BLANK_LINE_BEFORE_CLASS_DOCSTRING = False, - BLANK_LINE_BEFORE_MODULE_DOCSTRING = False, - BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION = 2, - BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES = 1, - COALESCE_BRACKETS = False, - COLUMN_LIMIT = 79, - CONTINUATION_ALIGN_STYLE = 'SPACE', - CONTINUATION_INDENT_WIDTH = 4, - DEDENT_CLOSING_BRACKETS = False, - INDENT_CLOSING_BRACKETS = False, - DISABLE_ENDING_COMMA_HEURISTIC = False, - EACH_DICT_ENTRY_ON_SEPARATE_LINE = True, - FORCE_MULTILINE_DICT = False, - I18N_COMMENT = '', - I18N_FUNCTION_CALL = '', - INDENT_DICTIONARY_VALUE = False, - INDENT_WIDTH = 4, - INDENT_BLANK_LINES = False, - JOIN_MULTIPLE_LINES = True, - NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS = set(), - SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET = True, - SPACE_INSIDE_BRACKETS = False, - SPACES_AROUND_POWER_OPERATOR = False, - SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN = False, - SPACES_AROUND_DICT_DELIMITERS = False, - SPACES_AROUND_LIST_DELIMITERS = False, - SPACES_AROUND_SUBSCRIPT_COLON = False, - SPACES_AROUND_TUPLE_DELIMITERS = False, - SPACES_BEFORE_COMMENT = 2, - SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED = False, - SPLIT_ALL_COMMA_SEPARATED_VALUES = False, - SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES = False, - SPLIT_BEFORE_ARITHMETIC_OPERATOR = False, - SPLIT_BEFORE_BITWISE_OPERATOR = True, - SPLIT_BEFORE_CLOSING_BRACKET = True, - SPLIT_BEFORE_DICT_SET_GENERATOR = True, - SPLIT_BEFORE_DOT = False, - SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN = False, - SPLIT_BEFORE_FIRST_ARGUMENT = False, - SPLIT_BEFORE_LOGICAL_OPERATOR = True, - SPLIT_BEFORE_NAMED_ASSIGNS = True, - SPLIT_COMPLEX_COMPREHENSION = False, - SPLIT_PENALTY_AFTER_OPENING_BRACKET = 300, - SPLIT_PENALTY_AFTER_UNARY_OPERATOR = 10000, - SPLIT_PENALTY_ARITHMETIC_OPERATOR = 300, - SPLIT_PENALTY_BEFORE_IF_EXPR = 0, - SPLIT_PENALTY_BITWISE_OPERATOR = 300, - SPLIT_PENALTY_COMPREHENSION = 80, - SPLIT_PENALTY_EXCESS_CHARACTER = 7000, - SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT = 30, - SPLIT_PENALTY_IMPORT_NAMES = 0, - SPLIT_PENALTY_LOGICAL_OPERATOR = 300, - USE_TABS = False, - ) + """Create the PEP8 formatting style.""" + return dict( + ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=True, + ALIGN_ASSIGNMENT=False, + NEW_ALIGNMENT_AFTER_COMMENTLINE=False, + ALLOW_MULTILINE_LAMBDAS=False, + ALLOW_MULTILINE_DICTIONARY_KEYS=False, + ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=True, + ALLOW_SPLIT_BEFORE_DICT_VALUE=True, + ARITHMETIC_PRECEDENCE_INDICATION=False, + BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=True, + BLANK_LINE_BEFORE_CLASS_DOCSTRING=False, + BLANK_LINE_BEFORE_MODULE_DOCSTRING=False, + BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=2, + BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES=1, + COALESCE_BRACKETS=False, + COLUMN_LIMIT=79, + CONTINUATION_ALIGN_STYLE='SPACE', + CONTINUATION_INDENT_WIDTH=4, + DEDENT_CLOSING_BRACKETS=False, + INDENT_CLOSING_BRACKETS=False, + DISABLE_ENDING_COMMA_HEURISTIC=False, + EACH_DICT_ENTRY_ON_SEPARATE_LINE=True, + FORCE_MULTILINE_DICT=False, + I18N_COMMENT='', + I18N_FUNCTION_CALL='', + INDENT_DICTIONARY_VALUE=False, + INDENT_WIDTH=4, + INDENT_BLANK_LINES=False, + JOIN_MULTIPLE_LINES=True, + NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=set(), + SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=True, + SPACE_INSIDE_BRACKETS=False, + SPACES_AROUND_POWER_OPERATOR=False, + SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=False, + SPACES_AROUND_DICT_DELIMITERS=False, + SPACES_AROUND_LIST_DELIMITERS=False, + SPACES_AROUND_SUBSCRIPT_COLON=False, + SPACES_AROUND_TUPLE_DELIMITERS=False, + SPACES_BEFORE_COMMENT=2, + SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False, + SPLIT_ALL_COMMA_SEPARATED_VALUES=False, + SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=False, + SPLIT_BEFORE_ARITHMETIC_OPERATOR=False, + SPLIT_BEFORE_BITWISE_OPERATOR=True, + SPLIT_BEFORE_CLOSING_BRACKET=True, + SPLIT_BEFORE_DICT_SET_GENERATOR=True, + SPLIT_BEFORE_DOT=False, + SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=False, + SPLIT_BEFORE_FIRST_ARGUMENT=False, + SPLIT_BEFORE_LOGICAL_OPERATOR=True, + SPLIT_BEFORE_NAMED_ASSIGNS=True, + SPLIT_COMPLEX_COMPREHENSION=False, + SPLIT_PENALTY_AFTER_OPENING_BRACKET=300, + SPLIT_PENALTY_AFTER_UNARY_OPERATOR=10000, + SPLIT_PENALTY_ARITHMETIC_OPERATOR=300, + SPLIT_PENALTY_BEFORE_IF_EXPR=0, + SPLIT_PENALTY_BITWISE_OPERATOR=300, + SPLIT_PENALTY_COMPREHENSION=80, + SPLIT_PENALTY_EXCESS_CHARACTER=7000, + SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=30, + SPLIT_PENALTY_IMPORT_NAMES=0, + SPLIT_PENALTY_LOGICAL_OPERATOR=300, + USE_TABS=False, + ) def CreateGoogleStyle(): - """Create the Google formatting style.""" - style = CreatePEP8Style() - style[ 'ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT' ] = False - style[ 'COLUMN_LIMIT' ] = 80 - style[ 'INDENT_DICTIONARY_VALUE' ] = True - style[ 'INDENT_WIDTH' ] = 4 - style[ 'I18N_COMMENT' ] = r'#\..*' - style[ 'I18N_FUNCTION_CALL' ] = [ 'N_', '_' ] - style[ 'JOIN_MULTIPLE_LINES' ] = False - style[ 'SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET' ] = False - style[ 'SPLIT_BEFORE_BITWISE_OPERATOR' ] = False - style[ 'SPLIT_BEFORE_DICT_SET_GENERATOR' ] = False - style[ 'SPLIT_BEFORE_LOGICAL_OPERATOR' ] = False - style[ 'SPLIT_COMPLEX_COMPREHENSION' ] = True - style[ 'SPLIT_PENALTY_COMPREHENSION' ] = 2100 - return style + """Create the Google formatting style.""" + style = CreatePEP8Style() + style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False + style['COLUMN_LIMIT'] = 80 + style['INDENT_DICTIONARY_VALUE'] = True + style['INDENT_WIDTH'] = 4 + style['I18N_COMMENT'] = r'#\..*' + style['I18N_FUNCTION_CALL'] = ['N_', '_'] + style['JOIN_MULTIPLE_LINES'] = False + style['SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET'] = False + style['SPLIT_BEFORE_BITWISE_OPERATOR'] = False + style['SPLIT_BEFORE_DICT_SET_GENERATOR'] = False + style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False + style['SPLIT_COMPLEX_COMPREHENSION'] = True + style['SPLIT_PENALTY_COMPREHENSION'] = 2100 + return style def CreateYapfStyle(): - """Create the YAPF formatting style.""" - style = CreateGoogleStyle() - style[ 'ALLOW_MULTILINE_DICTIONARY_KEYS' ] = True - style[ 'ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS' ] = False - style[ 'INDENT_WIDTH' ] = 2 - style[ 'SPLIT_BEFORE_BITWISE_OPERATOR' ] = True - style[ 'SPLIT_BEFORE_DOT' ] = True - style[ 'SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN' ] = True - return style + """Create the YAPF formatting style.""" + style = CreateGoogleStyle() + style['ALLOW_MULTILINE_DICTIONARY_KEYS'] = True + style['ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS'] = False + style['INDENT_WIDTH'] = 2 + style['SPLIT_BEFORE_BITWISE_OPERATOR'] = True + style['SPLIT_BEFORE_DOT'] = True + style['SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN'] = True + return style def CreateFacebookStyle(): - """Create the Facebook formatting style.""" - style = CreatePEP8Style() - style[ 'ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT' ] = False - style[ 'BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF' ] = False - style[ 'COLUMN_LIMIT' ] = 80 - style[ 'DEDENT_CLOSING_BRACKETS' ] = True - style[ 'INDENT_CLOSING_BRACKETS' ] = False - style[ 'INDENT_DICTIONARY_VALUE' ] = True - style[ 'JOIN_MULTIPLE_LINES' ] = False - style[ 'SPACES_BEFORE_COMMENT' ] = 2 - style[ 'SPLIT_PENALTY_AFTER_OPENING_BRACKET' ] = 0 - style[ 'SPLIT_PENALTY_BEFORE_IF_EXPR' ] = 30 - style[ 'SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT' ] = 30 - style[ 'SPLIT_BEFORE_LOGICAL_OPERATOR' ] = False - style[ 'SPLIT_BEFORE_BITWISE_OPERATOR' ] = False - return style + """Create the Facebook formatting style.""" + style = CreatePEP8Style() + style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False + style['BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'] = False + style['COLUMN_LIMIT'] = 80 + style['DEDENT_CLOSING_BRACKETS'] = True + style['INDENT_CLOSING_BRACKETS'] = False + style['INDENT_DICTIONARY_VALUE'] = True + style['JOIN_MULTIPLE_LINES'] = False + style['SPACES_BEFORE_COMMENT'] = 2 + style['SPLIT_PENALTY_AFTER_OPENING_BRACKET'] = 0 + style['SPLIT_PENALTY_BEFORE_IF_EXPR'] = 30 + style['SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT'] = 30 + style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False + style['SPLIT_BEFORE_BITWISE_OPERATOR'] = False + return style _STYLE_NAME_TO_FACTORY = dict( - pep8 = CreatePEP8Style, - google = CreateGoogleStyle, - facebook = CreateFacebookStyle, - yapf = CreateYapfStyle, + pep8=CreatePEP8Style, + google=CreateGoogleStyle, + facebook=CreateFacebookStyle, + yapf=CreateYapfStyle, ) _DEFAULT_STYLE_TO_FACTORY = [ - ( CreateFacebookStyle(), CreateFacebookStyle ), - ( CreateGoogleStyle(), CreateGoogleStyle ), - ( CreatePEP8Style(), CreatePEP8Style ), - ( CreateYapfStyle(), CreateYapfStyle ), + (CreateFacebookStyle(), CreateFacebookStyle), + (CreateGoogleStyle(), CreateGoogleStyle), + (CreatePEP8Style(), CreatePEP8Style), + (CreateYapfStyle(), CreateYapfStyle), ] -def _GetStyleFactory( style ): - for def_style, factory in _DEFAULT_STYLE_TO_FACTORY: - if style == def_style: - return factory - return None +def _GetStyleFactory(style): + for def_style, factory in _DEFAULT_STYLE_TO_FACTORY: + if style == def_style: + return factory + return None -def _ContinuationAlignStyleStringConverter( s ): - """Option value converter for a continuation align style string.""" - accepted_styles = ( 'SPACE', 'FIXED', 'VALIGN-RIGHT' ) - if s: - r = s.strip( '"\'' ).replace( '_', '-' ).upper() - if r not in accepted_styles: - raise ValueError( 'unknown continuation align style: %r' % ( s,) ) - else: - r = accepted_styles[ 0 ] - return r +def _ContinuationAlignStyleStringConverter(s): + """Option value converter for a continuation align style string.""" + accepted_styles = ('SPACE', 'FIXED', 'VALIGN-RIGHT') + if s: + r = s.strip('"\'').replace('_', '-').upper() + if r not in accepted_styles: + raise ValueError('unknown continuation align style: %r' % (s,)) + else: + r = accepted_styles[0] + return r -def _StringListConverter( s ): - """Option value converter for a comma-separated list of strings.""" - return [ part.strip() for part in s.split( ',' ) ] +def _StringListConverter(s): + """Option value converter for a comma-separated list of strings.""" + return [part.strip() for part in s.split(',')] -def _StringSetConverter( s ): - """Option value converter for a comma-separated set of strings.""" - if len( s ) > 2 and s[ 0 ] in '"\'': - s = s[ 1 :-1 ] - return { part.strip() for part in s.split( ',' ) } +def _StringSetConverter(s): + """Option value converter for a comma-separated set of strings.""" + if len(s) > 2 and s[0] in '"\'': + s = s[1:-1] + return {part.strip() for part in s.split(',')} -def _BoolConverter( s ): - """Option value converter for a boolean.""" - return py3compat.CONFIGPARSER_BOOLEAN_STATES[ s.lower() ] +def _BoolConverter(s): + """Option value converter for a boolean.""" + return py3compat.CONFIGPARSER_BOOLEAN_STATES[s.lower()] -def _IntListConverter( s ): - """Option value converter for a comma-separated list of integers.""" - s = s.strip() - if s.startswith( '[' ) and s.endswith( ']' ): - s = s[ 1 :-1 ] +def _IntListConverter(s): + """Option value converter for a comma-separated list of integers.""" + s = s.strip() + if s.startswith('[') and s.endswith(']'): + s = s[1:-1] - return [ int( part.strip() ) for part in s.split( ',' ) if part.strip() ] + return [int(part.strip()) for part in s.split(',') if part.strip()] -def _IntOrIntListConverter( s ): - """Option value converter for an integer or list of integers.""" - if len( s ) > 2 and s[ 0 ] in '"\'': - s = s[ 1 :-1 ] - return _IntListConverter( s ) if ',' in s else int( s ) +def _IntOrIntListConverter(s): + """Option value converter for an integer or list of integers.""" + if len(s) > 2 and s[0] in '"\'': + s = s[1:-1] + return _IntListConverter(s) if ',' in s else int(s) # Different style options need to have their values interpreted differently when @@ -674,73 +675,73 @@ def _IntOrIntListConverter( s ): # # Note: this dict has to map all the supported style options. _STYLE_OPTION_VALUE_CONVERTER = dict( - ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT = _BoolConverter, - ALIGN_ASSIGNMENT = _BoolConverter, - NEW_ALIGNMENT_AFTER_COMMENTLINE = _BoolConverter, - ALLOW_MULTILINE_LAMBDAS = _BoolConverter, - ALLOW_MULTILINE_DICTIONARY_KEYS = _BoolConverter, - ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS = _BoolConverter, - ALLOW_SPLIT_BEFORE_DICT_VALUE = _BoolConverter, - ARITHMETIC_PRECEDENCE_INDICATION = _BoolConverter, - BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF = _BoolConverter, - BLANK_LINE_BEFORE_CLASS_DOCSTRING = _BoolConverter, - BLANK_LINE_BEFORE_MODULE_DOCSTRING = _BoolConverter, - BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION = int, - BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES = int, - COALESCE_BRACKETS = _BoolConverter, - COLUMN_LIMIT = int, - CONTINUATION_ALIGN_STYLE = _ContinuationAlignStyleStringConverter, - CONTINUATION_INDENT_WIDTH = int, - DEDENT_CLOSING_BRACKETS = _BoolConverter, - INDENT_CLOSING_BRACKETS = _BoolConverter, - DISABLE_ENDING_COMMA_HEURISTIC = _BoolConverter, - EACH_DICT_ENTRY_ON_SEPARATE_LINE = _BoolConverter, - FORCE_MULTILINE_DICT = _BoolConverter, - I18N_COMMENT = str, - I18N_FUNCTION_CALL = _StringListConverter, - INDENT_DICTIONARY_VALUE = _BoolConverter, - INDENT_WIDTH = int, - INDENT_BLANK_LINES = _BoolConverter, - JOIN_MULTIPLE_LINES = _BoolConverter, - NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS = _StringSetConverter, - SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET = _BoolConverter, - SPACE_INSIDE_BRACKETS = _BoolConverter, - SPACES_AROUND_POWER_OPERATOR = _BoolConverter, - SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN = _BoolConverter, - SPACES_AROUND_DICT_DELIMITERS = _BoolConverter, - SPACES_AROUND_LIST_DELIMITERS = _BoolConverter, - SPACES_AROUND_SUBSCRIPT_COLON = _BoolConverter, - SPACES_AROUND_TUPLE_DELIMITERS = _BoolConverter, - SPACES_BEFORE_COMMENT = _IntOrIntListConverter, - SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED = _BoolConverter, - SPLIT_ALL_COMMA_SEPARATED_VALUES = _BoolConverter, - SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES = _BoolConverter, - SPLIT_BEFORE_ARITHMETIC_OPERATOR = _BoolConverter, - SPLIT_BEFORE_BITWISE_OPERATOR = _BoolConverter, - SPLIT_BEFORE_CLOSING_BRACKET = _BoolConverter, - SPLIT_BEFORE_DICT_SET_GENERATOR = _BoolConverter, - SPLIT_BEFORE_DOT = _BoolConverter, - SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN = _BoolConverter, - SPLIT_BEFORE_FIRST_ARGUMENT = _BoolConverter, - SPLIT_BEFORE_LOGICAL_OPERATOR = _BoolConverter, - SPLIT_BEFORE_NAMED_ASSIGNS = _BoolConverter, - SPLIT_COMPLEX_COMPREHENSION = _BoolConverter, - SPLIT_PENALTY_AFTER_OPENING_BRACKET = int, - SPLIT_PENALTY_AFTER_UNARY_OPERATOR = int, - SPLIT_PENALTY_ARITHMETIC_OPERATOR = int, - SPLIT_PENALTY_BEFORE_IF_EXPR = int, - SPLIT_PENALTY_BITWISE_OPERATOR = int, - SPLIT_PENALTY_COMPREHENSION = int, - SPLIT_PENALTY_EXCESS_CHARACTER = int, - SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT = int, - SPLIT_PENALTY_IMPORT_NAMES = int, - SPLIT_PENALTY_LOGICAL_OPERATOR = int, - USE_TABS = _BoolConverter, + ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=_BoolConverter, + ALIGN_ASSIGNMENT=_BoolConverter, + NEW_ALIGNMENT_AFTER_COMMENTLINE=_BoolConverter, + ALLOW_MULTILINE_LAMBDAS=_BoolConverter, + ALLOW_MULTILINE_DICTIONARY_KEYS=_BoolConverter, + ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=_BoolConverter, + ALLOW_SPLIT_BEFORE_DICT_VALUE=_BoolConverter, + ARITHMETIC_PRECEDENCE_INDICATION=_BoolConverter, + BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=_BoolConverter, + BLANK_LINE_BEFORE_CLASS_DOCSTRING=_BoolConverter, + BLANK_LINE_BEFORE_MODULE_DOCSTRING=_BoolConverter, + BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=int, + BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES=int, + COALESCE_BRACKETS=_BoolConverter, + COLUMN_LIMIT=int, + CONTINUATION_ALIGN_STYLE=_ContinuationAlignStyleStringConverter, + CONTINUATION_INDENT_WIDTH=int, + DEDENT_CLOSING_BRACKETS=_BoolConverter, + INDENT_CLOSING_BRACKETS=_BoolConverter, + DISABLE_ENDING_COMMA_HEURISTIC=_BoolConverter, + EACH_DICT_ENTRY_ON_SEPARATE_LINE=_BoolConverter, + FORCE_MULTILINE_DICT=_BoolConverter, + I18N_COMMENT=str, + I18N_FUNCTION_CALL=_StringListConverter, + INDENT_DICTIONARY_VALUE=_BoolConverter, + INDENT_WIDTH=int, + INDENT_BLANK_LINES=_BoolConverter, + JOIN_MULTIPLE_LINES=_BoolConverter, + NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=_StringSetConverter, + SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=_BoolConverter, + SPACE_INSIDE_BRACKETS=_BoolConverter, + SPACES_AROUND_POWER_OPERATOR=_BoolConverter, + SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=_BoolConverter, + SPACES_AROUND_DICT_DELIMITERS=_BoolConverter, + SPACES_AROUND_LIST_DELIMITERS=_BoolConverter, + SPACES_AROUND_SUBSCRIPT_COLON=_BoolConverter, + SPACES_AROUND_TUPLE_DELIMITERS=_BoolConverter, + SPACES_BEFORE_COMMENT=_IntOrIntListConverter, + SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter, + SPLIT_ALL_COMMA_SEPARATED_VALUES=_BoolConverter, + SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=_BoolConverter, + SPLIT_BEFORE_ARITHMETIC_OPERATOR=_BoolConverter, + SPLIT_BEFORE_BITWISE_OPERATOR=_BoolConverter, + SPLIT_BEFORE_CLOSING_BRACKET=_BoolConverter, + SPLIT_BEFORE_DICT_SET_GENERATOR=_BoolConverter, + SPLIT_BEFORE_DOT=_BoolConverter, + SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=_BoolConverter, + SPLIT_BEFORE_FIRST_ARGUMENT=_BoolConverter, + SPLIT_BEFORE_LOGICAL_OPERATOR=_BoolConverter, + SPLIT_BEFORE_NAMED_ASSIGNS=_BoolConverter, + SPLIT_COMPLEX_COMPREHENSION=_BoolConverter, + SPLIT_PENALTY_AFTER_OPENING_BRACKET=int, + SPLIT_PENALTY_AFTER_UNARY_OPERATOR=int, + SPLIT_PENALTY_ARITHMETIC_OPERATOR=int, + SPLIT_PENALTY_BEFORE_IF_EXPR=int, + SPLIT_PENALTY_BITWISE_OPERATOR=int, + SPLIT_PENALTY_COMPREHENSION=int, + SPLIT_PENALTY_EXCESS_CHARACTER=int, + SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=int, + SPLIT_PENALTY_IMPORT_NAMES=int, + SPLIT_PENALTY_LOGICAL_OPERATOR=int, + USE_TABS=_BoolConverter, ) -def CreateStyleFromConfig( style_config ): - """Create a style dict from the given config. +def CreateStyleFromConfig(style_config): + """Create a style dict from the given config. Arguments: style_config: either a style name or a file name. The file is expected to @@ -756,108 +757,107 @@ def CreateStyleFromConfig( style_config ): StyleConfigError: if an unknown style option was encountered. """ - def GlobalStyles(): - for style, _ in _DEFAULT_STYLE_TO_FACTORY: - yield style - - def_style = False - if style_config is None: - for style in GlobalStyles(): - if _style == style: - def_style = True - break - if not def_style: - return _style - return _GLOBAL_STYLE_FACTORY() - - if isinstance( style_config, dict ): - config = _CreateConfigParserFromConfigDict( style_config ) - elif isinstance( style_config, py3compat.basestring ): - style_factory = _STYLE_NAME_TO_FACTORY.get( style_config.lower() ) - if style_factory is not None: - return style_factory() - if style_config.startswith( '{' ): - # Most likely a style specification from the command line. - config = _CreateConfigParserFromConfigString( style_config ) - else: - # Unknown config name: assume it's a file name then. - config = _CreateConfigParserFromConfigFile( style_config ) - return _CreateStyleFromConfigParser( config ) - - -def _CreateConfigParserFromConfigDict( config_dict ): + def GlobalStyles(): + for style, _ in _DEFAULT_STYLE_TO_FACTORY: + yield style + + def_style = False + if style_config is None: + for style in GlobalStyles(): + if _style == style: + def_style = True + break + if not def_style: + return _style + return _GLOBAL_STYLE_FACTORY() + + if isinstance(style_config, dict): + config = _CreateConfigParserFromConfigDict(style_config) + elif isinstance(style_config, py3compat.basestring): + style_factory = _STYLE_NAME_TO_FACTORY.get(style_config.lower()) + if style_factory is not None: + return style_factory() + if style_config.startswith('{'): + # Most likely a style specification from the command line. + config = _CreateConfigParserFromConfigString(style_config) + else: + # Unknown config name: assume it's a file name then. + config = _CreateConfigParserFromConfigFile(style_config) + return _CreateStyleFromConfigParser(config) + + +def _CreateConfigParserFromConfigDict(config_dict): + config = py3compat.ConfigParser() + config.add_section('style') + for key, value in config_dict.items(): + config.set('style', key, str(value)) + return config + + +def _CreateConfigParserFromConfigString(config_string): + """Given a config string from the command line, return a config parser.""" + if config_string[0] != '{' or config_string[-1] != '}': + raise StyleConfigError( + "Invalid style dict syntax: '{}'.".format(config_string)) + config = py3compat.ConfigParser() + config.add_section('style') + for key, value, _ in re.findall( + r'([a-zA-Z0-9_]+)\s*[:=]\s*' + r'(?:' + r'((?P[\'"]).*?(?P=quote)|' + r'[a-zA-Z0-9_]+)' + r')', config_string): # yapf: disable + config.set('style', key, value) + return config + + +def _CreateConfigParserFromConfigFile(config_filename): + """Read the file and return a ConfigParser object.""" + if not os.path.exists(config_filename): + # Provide a more meaningful error here. + raise StyleConfigError( + '"{0}" is not a valid style or file path'.format(config_filename)) + with open(config_filename) as style_file: config = py3compat.ConfigParser() - config.add_section( 'style' ) - for key, value in config_dict.items(): - config.set( 'style', key, str( value ) ) - return config - + if config_filename.endswith(PYPROJECT_TOML): + try: + import toml + except ImportError: + raise errors.YapfError( + "toml package is needed for using pyproject.toml as a " + "configuration file") + + pyproject_toml = toml.load(style_file) + style_dict = pyproject_toml.get("tool", {}).get("yapf", None) + if style_dict is None: + raise StyleConfigError( + 'Unable to find section [tool.yapf] in {0}'.format(config_filename)) + config.add_section('style') + for k, v in style_dict.items(): + config.set('style', k, str(v)) + return config + + config.read_file(style_file) + if config_filename.endswith(SETUP_CONFIG): + if not config.has_section('yapf'): + raise StyleConfigError( + 'Unable to find section [yapf] in {0}'.format(config_filename)) + return config -def _CreateConfigParserFromConfigString( config_string ): - """Given a config string from the command line, return a config parser.""" - if config_string[ 0 ] != '{' or config_string[ -1 ] != '}': + if config_filename.endswith(LOCAL_STYLE): + if not config.has_section('style'): raise StyleConfigError( - "Invalid style dict syntax: '{}'.".format( config_string ) ) - config = py3compat.ConfigParser() - config.add_section( 'style' ) - for key, value, _ in re.findall( - r'([a-zA-Z0-9_]+)\s*[:=]\s*' - r'(?:' - r'((?P[\'"]).*?(?P=quote)|' - r'[a-zA-Z0-9_]+)' - r')', config_string): # yapf: disable - config.set( 'style', key, value ) + 'Unable to find section [style] in {0}'.format(config_filename)) + return config + + if not config.has_section('style'): + raise StyleConfigError( + 'Unable to find section [style] in {0}'.format(config_filename)) return config -def _CreateConfigParserFromConfigFile( config_filename ): - """Read the file and return a ConfigParser object.""" - if not os.path.exists( config_filename ): - # Provide a more meaningful error here. - raise StyleConfigError( - '"{0}" is not a valid style or file path'.format( config_filename ) ) - with open( config_filename ) as style_file: - config = py3compat.ConfigParser() - if config_filename.endswith( PYPROJECT_TOML ): - try: - import toml - except ImportError: - raise errors.YapfError( - "toml package is needed for using pyproject.toml as a " - "configuration file" ) - - pyproject_toml = toml.load( style_file ) - style_dict = pyproject_toml.get( "tool", {} ).get( "yapf", None ) - if style_dict is None: - raise StyleConfigError( - 'Unable to find section [tool.yapf] in {0}'.format( - config_filename ) ) - config.add_section( 'style' ) - for k, v in style_dict.items(): - config.set( 'style', k, str( v ) ) - return config - - config.read_file( style_file ) - if config_filename.endswith( SETUP_CONFIG ): - if not config.has_section( 'yapf' ): - raise StyleConfigError( - 'Unable to find section [yapf] in {0}'.format( config_filename ) ) - return config - - if config_filename.endswith( LOCAL_STYLE ): - if not config.has_section( 'style' ): - raise StyleConfigError( - 'Unable to find section [style] in {0}'.format( config_filename ) ) - return config - - if not config.has_section( 'style' ): - raise StyleConfigError( - 'Unable to find section [style] in {0}'.format( config_filename ) ) - return config - - -def _CreateStyleFromConfigParser( config ): - """Create a style dict from a configuration file. +def _CreateStyleFromConfigParser(config): + """Create a style dict from a configuration file. Arguments: config: a ConfigParser object. @@ -868,32 +868,32 @@ def _CreateStyleFromConfigParser( config ): Raises: StyleConfigError: if an unknown style option was encountered. """ - # Initialize the base style. - section = 'yapf' if config.has_section( 'yapf' ) else 'style' - if config.has_option( 'style', 'based_on_style' ): - based_on = config.get( 'style', 'based_on_style' ).lower() - base_style = _STYLE_NAME_TO_FACTORY[ based_on ]() - elif config.has_option( 'yapf', 'based_on_style' ): - based_on = config.get( 'yapf', 'based_on_style' ).lower() - base_style = _STYLE_NAME_TO_FACTORY[ based_on ]() - else: - base_style = _GLOBAL_STYLE_FACTORY() - - # Read all options specified in the file and update the style. - for option, value in config.items( section ): - if option.lower() == 'based_on_style': - # Now skip this one - we've already handled it and it's not one of the - # recognized style options. - continue - option = option.upper() - if option not in _STYLE_OPTION_VALUE_CONVERTER: - raise StyleConfigError( 'Unknown style option "{0}"'.format( option ) ) - try: - base_style[ option ] = _STYLE_OPTION_VALUE_CONVERTER[ option ]( value ) - except ValueError: - raise StyleConfigError( - "'{}' is not a valid setting for {}.".format( value, option ) ) - return base_style + # Initialize the base style. + section = 'yapf' if config.has_section('yapf') else 'style' + if config.has_option('style', 'based_on_style'): + based_on = config.get('style', 'based_on_style').lower() + base_style = _STYLE_NAME_TO_FACTORY[based_on]() + elif config.has_option('yapf', 'based_on_style'): + based_on = config.get('yapf', 'based_on_style').lower() + base_style = _STYLE_NAME_TO_FACTORY[based_on]() + else: + base_style = _GLOBAL_STYLE_FACTORY() + + # Read all options specified in the file and update the style. + for option, value in config.items(section): + if option.lower() == 'based_on_style': + # Now skip this one - we've already handled it and it's not one of the + # recognized style options. + continue + option = option.upper() + if option not in _STYLE_OPTION_VALUE_CONVERTER: + raise StyleConfigError('Unknown style option "{0}"'.format(option)) + try: + base_style[option] = _STYLE_OPTION_VALUE_CONVERTER[option](value) + except ValueError: + raise StyleConfigError( + "'{}' is not a valid setting for {}.".format(value, option)) + return base_style # The default style - used if yapf is not invoked without specifically @@ -905,8 +905,8 @@ def _CreateStyleFromConfigParser( config ): # The name of the file to use for global style definition. GLOBAL_STYLE = ( os.path.join( - os.getenv( 'XDG_CONFIG_HOME' ) or os.path.expanduser( '~/.config' ), 'yapf', - 'style' ) ) + os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'), 'yapf', + 'style')) # The name of the file to use for directory-local style definition. LOCAL_STYLE = '.style.yapf' @@ -923,4 +923,4 @@ def _CreateStyleFromConfigParser( config ): # Refactor this so that the style is passed around through yapf rather than # being global. _style = None -SetGlobalStyle( _GLOBAL_STYLE_FACTORY() ) +SetGlobalStyle(_GLOBAL_STYLE_FACTORY()) diff --git a/yapf/yapflib/verifier.py b/yapf/yapflib/verifier.py index 80cfebc08..01dccc0b0 100644 --- a/yapf/yapflib/verifier.py +++ b/yapf/yapflib/verifier.py @@ -25,13 +25,13 @@ import textwrap -class InternalError( Exception ): - """Internal error in verifying formatted code.""" - pass +class InternalError(Exception): + """Internal error in verifying formatted code.""" + pass -def VerifyCode( code ): - """Verify that the reformatted code is syntactically correct. +def VerifyCode(code): + """Verify that the reformatted code is syntactically correct. Arguments: code: (unicode) The reformatted code snippet. @@ -39,57 +39,55 @@ def VerifyCode( code ): Raises: SyntaxError if the code was reformatted incorrectly. """ + try: + compile(textwrap.dedent(code).encode('UTF-8'), '', 'exec') + except SyntaxError: try: - compile( textwrap.dedent( code ).encode( 'UTF-8' ), '', 'exec' ) + ast.parse(textwrap.dedent(code.lstrip('\n')).lstrip(), '', 'exec') except SyntaxError: - try: - ast.parse( - textwrap.dedent( code.lstrip( '\n' ) ).lstrip(), '', 'exec' ) - except SyntaxError: - try: - normalized_code = _NormalizeCode( code ) - compile( normalized_code.encode( 'UTF-8' ), '', 'exec' ) - except SyntaxError: - raise InternalError( sys.exc_info()[ 1 ] ) + try: + normalized_code = _NormalizeCode(code) + compile(normalized_code.encode('UTF-8'), '', 'exec') + except SyntaxError: + raise InternalError(sys.exc_info()[1]) -def _NormalizeCode( code ): - """Make sure that the code snippet is compilable.""" - code = textwrap.dedent( code.lstrip( '\n' ) ).lstrip() +def _NormalizeCode(code): + """Make sure that the code snippet is compilable.""" + code = textwrap.dedent(code.lstrip('\n')).lstrip() - # Split the code to lines and get rid of all leading full-comment lines as - # they can mess up the normalization attempt. - lines = code.split( '\n' ) - i = 0 - for i, line in enumerate( lines ): - line = line.strip() - if line and not line.startswith( '#' ): - break - code = '\n'.join( lines[ i : ] ) + '\n' + # Split the code to lines and get rid of all leading full-comment lines as + # they can mess up the normalization attempt. + lines = code.split('\n') + i = 0 + for i, line in enumerate(lines): + line = line.strip() + if line and not line.startswith('#'): + break + code = '\n'.join(lines[i:]) + '\n' - if re.match( r'(if|while|for|with|def|class|async|await)\b', code ): - code += '\n pass' - elif re.match( r'(elif|else)\b', code ): - try: - try_code = 'if True:\n pass\n' + code + '\n pass' - ast.parse( - textwrap.dedent( try_code.lstrip( '\n' ) ).lstrip(), '', - 'exec' ) - code = try_code - except SyntaxError: - # The assumption here is that the code is on a single line. - code = 'if True: pass\n' + code - elif code.startswith( '@' ): - code += '\ndef _():\n pass' - elif re.match( r'try\b', code ): - code += '\n pass\nexcept:\n pass' - elif re.match( r'(except|finally)\b', code ): - code = 'try:\n pass\n' + code + '\n pass' - elif re.match( r'(return|yield)\b', code ): - code = 'def _():\n ' + code - elif re.match( r'(continue|break)\b', code ): - code = 'while True:\n ' + code - elif re.match( r'print\b', code ): - code = 'from __future__ import print_function\n' + code + if re.match(r'(if|while|for|with|def|class|async|await)\b', code): + code += '\n pass' + elif re.match(r'(elif|else)\b', code): + try: + try_code = 'if True:\n pass\n' + code + '\n pass' + ast.parse( + textwrap.dedent(try_code.lstrip('\n')).lstrip(), '', 'exec') + code = try_code + except SyntaxError: + # The assumption here is that the code is on a single line. + code = 'if True: pass\n' + code + elif code.startswith('@'): + code += '\ndef _():\n pass' + elif re.match(r'try\b', code): + code += '\n pass\nexcept:\n pass' + elif re.match(r'(except|finally)\b', code): + code = 'try:\n pass\n' + code + '\n pass' + elif re.match(r'(return|yield)\b', code): + code = 'def _():\n ' + code + elif re.match(r'(continue|break)\b', code): + code = 'while True:\n ' + code + elif re.match(r'print\b', code): + code = 'from __future__ import print_function\n' + code - return code + '\n' + return code + '\n' diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index e8ae26e87..e0098ddd2 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -52,14 +52,14 @@ def FormatFile( - filename, - style_config = None, - lines = None, - print_diff = False, - verify = False, - in_place = False, - logger = None ): - """Format a single Python file and return the formatted code. + filename, + style_config=None, + lines=None, + print_diff=False, + verify=False, + in_place=False, + logger=None): + """Format a single Python file and return the formatted code. Arguments: filename: (unicode) The file to reformat. @@ -85,33 +85,33 @@ def FormatFile( IOError: raised if there was an error reading the file. ValueError: raised if in_place and print_diff are both specified. """ - _CheckPythonVersion() - - if in_place and print_diff: - raise ValueError( 'Cannot pass both in_place and print_diff.' ) - - original_source, newline, encoding = ReadFile( filename, logger ) - reformatted_source, changed = FormatCode( - original_source, - style_config = style_config, - filename = filename, - lines = lines, - print_diff = print_diff, - verify = verify ) - if reformatted_source.rstrip( '\n' ): - lines = reformatted_source.rstrip( '\n' ).split( '\n' ) - reformatted_source = newline.join( iter( lines ) ) + newline - if in_place: - if original_source and original_source != reformatted_source: - file_resources.WriteReformattedCode( - filename, reformatted_source, encoding, in_place ) - return None, encoding, changed - - return reformatted_source, encoding, changed - - -def FormatTree( tree, style_config = None, lines = None, verify = False ): - """Format a parsed lib2to3 pytree. + _CheckPythonVersion() + + if in_place and print_diff: + raise ValueError('Cannot pass both in_place and print_diff.') + + original_source, newline, encoding = ReadFile(filename, logger) + reformatted_source, changed = FormatCode( + original_source, + style_config=style_config, + filename=filename, + lines=lines, + print_diff=print_diff, + verify=verify) + if reformatted_source.rstrip('\n'): + lines = reformatted_source.rstrip('\n').split('\n') + reformatted_source = newline.join(iter(lines)) + newline + if in_place: + if original_source and original_source != reformatted_source: + file_resources.WriteReformattedCode( + filename, reformatted_source, encoding, in_place) + return None, encoding, changed + + return reformatted_source, encoding, changed + + +def FormatTree(tree, style_config=None, lines=None, verify=False): + """Format a parsed lib2to3 pytree. This provides an alternative entry point to YAPF. @@ -129,34 +129,34 @@ def FormatTree( tree, style_config = None, lines = None, verify = False ): Returns: The source formatted according to the given formatting style. """ - _CheckPythonVersion() - style.SetGlobalStyle( style.CreateStyleFromConfig( style_config ) ) + _CheckPythonVersion() + style.SetGlobalStyle(style.CreateStyleFromConfig(style_config)) - # Run passes on the tree, modifying it in place. - comment_splicer.SpliceComments( tree ) - continuation_splicer.SpliceContinuations( tree ) - subtype_assigner.AssignSubtypes( tree ) - identify_container.IdentifyContainers( tree ) - split_penalty.ComputeSplitPenalties( tree ) - blank_line_calculator.CalculateBlankLines( tree ) + # Run passes on the tree, modifying it in place. + comment_splicer.SpliceComments(tree) + continuation_splicer.SpliceContinuations(tree) + subtype_assigner.AssignSubtypes(tree) + identify_container.IdentifyContainers(tree) + split_penalty.ComputeSplitPenalties(tree) + blank_line_calculator.CalculateBlankLines(tree) - llines = pytree_unwrapper.UnwrapPyTree( tree ) - for lline in llines: - lline.CalculateFormattingInformation() + llines = pytree_unwrapper.UnwrapPyTree(tree) + for lline in llines: + lline.CalculateFormattingInformation() - lines = _LineRangesToSet( lines ) - _MarkLinesToFormat( llines, lines ) - return reformatter.Reformat( _SplitSemicolons( llines ), verify, lines ) + lines = _LineRangesToSet(lines) + _MarkLinesToFormat(llines, lines) + return reformatter.Reformat(_SplitSemicolons(llines), verify, lines) def FormatCode( - unformatted_source, - filename = '', - style_config = None, - lines = None, - print_diff = False, - verify = False ): - """Format a string of Python code. + unformatted_source, + filename='', + style_config=None, + lines=None, + print_diff=False, + verify=False): + """Format a string of Python code. This provides an alternative entry point to YAPF. @@ -178,39 +178,39 @@ def FormatCode( Tuple of (reformatted_source, changed). reformatted_source conforms to the desired formatting style. changed is True if the source changed. """ - try: - tree = pytree_utils.ParseCodeToTree( unformatted_source ) - except Exception as e: - e.filename = filename - raise errors.YapfError( errors.FormatErrorMsg( e ) ) + try: + tree = pytree_utils.ParseCodeToTree(unformatted_source) + except Exception as e: + e.filename = filename + raise errors.YapfError(errors.FormatErrorMsg(e)) - reformatted_source = FormatTree( - tree, style_config = style_config, lines = lines, verify = verify ) + reformatted_source = FormatTree( + tree, style_config=style_config, lines=lines, verify=verify) - if unformatted_source == reformatted_source: - return '' if print_diff else reformatted_source, False + if unformatted_source == reformatted_source: + return '' if print_diff else reformatted_source, False - code_diff = _GetUnifiedDiff( - unformatted_source, reformatted_source, filename = filename ) + code_diff = _GetUnifiedDiff( + unformatted_source, reformatted_source, filename=filename) - if print_diff: - return code_diff, code_diff.strip() != '' # pylint: disable=g-explicit-bool-comparison # noqa + if print_diff: + return code_diff, code_diff.strip() != '' # pylint: disable=g-explicit-bool-comparison # noqa - return reformatted_source, True + return reformatted_source, True -def _CheckPythonVersion(): # pragma: no cover - errmsg = 'yapf is only supported for Python 2.7 or 3.6+' - if sys.version_info[ 0 ] == 2: - if sys.version_info[ 1 ] < 7: - raise RuntimeError( errmsg ) - elif sys.version_info[ 0 ] == 3: - if sys.version_info[ 1 ] < 6: - raise RuntimeError( errmsg ) +def _CheckPythonVersion(): # pragma: no cover + errmsg = 'yapf is only supported for Python 2.7 or 3.6+' + if sys.version_info[0] == 2: + if sys.version_info[1] < 7: + raise RuntimeError(errmsg) + elif sys.version_info[0] == 3: + if sys.version_info[1] < 6: + raise RuntimeError(errmsg) -def ReadFile( filename, logger = None ): - """Read the contents of the file. +def ReadFile(filename, logger=None): + """Read the contents of the file. An optional logger can be specified to emit messages to your favorite logging stream. If specified, then no exception is raised. This is external so that it @@ -226,106 +226,102 @@ def ReadFile( filename, logger = None ): Raises: IOError: raised if there was an error reading the file. """ - try: - encoding = file_resources.FileEncoding( filename ) - - # Preserves line endings. - with py3compat.open_with_encoding( filename, mode = 'r', encoding = encoding, - newline = '' ) as fd: - lines = fd.readlines() - - line_ending = file_resources.LineEnding( lines ) - source = '\n'.join( line.rstrip( '\r\n' ) for line in lines ) + '\n' - return source, line_ending, encoding - except IOError as e: # pragma: no cover - if logger: - logger( e ) - e.args = ( - e.args[ 0 ], - ( filename, e.args[ 1 ][ 1 ], e.args[ 1 ][ 2 ], e.args[ 1 ][ 3 ] ) ) - raise - except UnicodeDecodeError as e: # pragma: no cover - if logger: - logger( - 'Could not parse %s! Consider excluding this file with --exclude.', - filename ) - logger( e ) - e.args = ( - e.args[ 0 ], - ( filename, e.args[ 1 ][ 1 ], e.args[ 1 ][ 2 ], e.args[ 1 ][ 3 ] ) ) - raise - - -def _SplitSemicolons( lines ): - res = [] - for line in lines: - res.extend( line.Split() ) - return res + try: + encoding = file_resources.FileEncoding(filename) + + # Preserves line endings. + with py3compat.open_with_encoding(filename, mode='r', encoding=encoding, + newline='') as fd: + lines = fd.readlines() + + line_ending = file_resources.LineEnding(lines) + source = '\n'.join(line.rstrip('\r\n') for line in lines) + '\n' + return source, line_ending, encoding + except IOError as e: # pragma: no cover + if logger: + logger(e) + e.args = (e.args[0], (filename, e.args[1][1], e.args[1][2], e.args[1][3])) + raise + except UnicodeDecodeError as e: # pragma: no cover + if logger: + logger( + 'Could not parse %s! Consider excluding this file with --exclude.', + filename) + logger(e) + e.args = (e.args[0], (filename, e.args[1][1], e.args[1][2], e.args[1][3])) + raise + + +def _SplitSemicolons(lines): + res = [] + for line in lines: + res.extend(line.Split()) + return res DISABLE_PATTERN = r'^#.*\byapf:\s*disable\b' ENABLE_PATTERN = r'^#.*\byapf:\s*enable\b' -def _LineRangesToSet( line_ranges ): - """Return a set of lines in the range.""" - - if line_ranges is None: - return None - - line_set = set() - for low, high in sorted( line_ranges ): - line_set.update( range( low, high + 1 ) ) - - return line_set - - -def _MarkLinesToFormat( llines, lines ): - """Skip sections of code that we shouldn't reformat.""" - if lines: - for uwline in llines: - uwline.disable = not lines.intersection( - range( uwline.lineno, uwline.last.lineno + 1 ) ) - - # Now go through the lines and disable any lines explicitly marked as - # disabled. - index = 0 - while index < len( llines ): - uwline = llines[ index ] - if uwline.is_comment: - if _DisableYAPF( uwline.first.value.strip() ): - index += 1 - while index < len( llines ): - uwline = llines[ index ] - line = uwline.first.value.strip() - if uwline.is_comment and _EnableYAPF( line ): - if not _DisableYAPF( line ): - break - uwline.disable = True - index += 1 - elif re.search( DISABLE_PATTERN, uwline.last.value.strip(), re.IGNORECASE ): - uwline.disable = True - index += 1 +def _LineRangesToSet(line_ranges): + """Return a set of lines in the range.""" + if line_ranges is None: + return None -def _DisableYAPF( line ): - return ( - re.search( DISABLE_PATTERN, - line.split( '\n' )[ 0 ].strip(), re.IGNORECASE ) or - re.search( DISABLE_PATTERN, - line.split( '\n' )[ -1 ].strip(), re.IGNORECASE ) ) + line_set = set() + for low, high in sorted(line_ranges): + line_set.update(range(low, high + 1)) + return line_set -def _EnableYAPF( line ): - return ( - re.search( ENABLE_PATTERN, - line.split( '\n' )[ 0 ].strip(), re.IGNORECASE ) or - re.search( ENABLE_PATTERN, - line.split( '\n' )[ -1 ].strip(), re.IGNORECASE ) ) +def _MarkLinesToFormat(llines, lines): + """Skip sections of code that we shouldn't reformat.""" + if lines: + for uwline in llines: + uwline.disable = not lines.intersection( + range(uwline.lineno, uwline.last.lineno + 1)) -def _GetUnifiedDiff( before, after, filename = 'code' ): - """Get a unified diff of the changes. + # Now go through the lines and disable any lines explicitly marked as + # disabled. + index = 0 + while index < len(llines): + uwline = llines[index] + if uwline.is_comment: + if _DisableYAPF(uwline.first.value.strip()): + index += 1 + while index < len(llines): + uwline = llines[index] + line = uwline.first.value.strip() + if uwline.is_comment and _EnableYAPF(line): + if not _DisableYAPF(line): + break + uwline.disable = True + index += 1 + elif re.search(DISABLE_PATTERN, uwline.last.value.strip(), re.IGNORECASE): + uwline.disable = True + index += 1 + + +def _DisableYAPF(line): + return ( + re.search(DISABLE_PATTERN, + line.split('\n')[0].strip(), re.IGNORECASE) or + re.search(DISABLE_PATTERN, + line.split('\n')[-1].strip(), re.IGNORECASE)) + + +def _EnableYAPF(line): + return ( + re.search(ENABLE_PATTERN, + line.split('\n')[0].strip(), re.IGNORECASE) or + re.search(ENABLE_PATTERN, + line.split('\n')[-1].strip(), re.IGNORECASE)) + + +def _GetUnifiedDiff(before, after, filename='code'): + """Get a unified diff of the changes. Arguments: before: (unicode) The original source code. @@ -335,14 +331,14 @@ def _GetUnifiedDiff( before, after, filename = 'code' ): Returns: The unified diff text. """ - before = before.splitlines() - after = after.splitlines() - return '\n'.join( - difflib.unified_diff( - before, - after, - filename, - filename, - '(original)', - '(reformatted)', - lineterm = '' ) ) + '\n' + before = before.splitlines() + after = after.splitlines() + return '\n'.join( + difflib.unified_diff( + before, + after, + filename, + filename, + '(original)', + '(reformatted)', + lineterm='')) + '\n' diff --git a/yapftests/blank_line_calculator_test.py b/yapftests/blank_line_calculator_test.py index 18fa83e0b..d5d97d794 100644 --- a/yapftests/blank_line_calculator_test.py +++ b/yapftests/blank_line_calculator_test.py @@ -30,13 +30,15 @@ def setUpClass(cls): style.SetGlobalStyle(style.CreateYapfStyle()) def testDecorators(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ @bork() def foo(): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ @bork() def foo(): pass @@ -45,7 +47,8 @@ def foo(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testComplexDecorators(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ import sys @bork() @@ -60,7 +63,8 @@ class moo(object): def method(self): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ import sys @@ -81,7 +85,8 @@ def method(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testCodeAfterFunctionsAndClasses(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo(): pass top_level_code = True @@ -97,7 +102,8 @@ def method_2(self): except Error as error: pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo(): pass @@ -126,7 +132,8 @@ def method_2(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testCommentSpacing(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ # This is the first comment # And it's multiline @@ -155,7 +162,8 @@ def foo(self): # comment pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ # This is the first comment # And it's multiline @@ -192,7 +200,8 @@ def foo(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testCommentBeforeMethod(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class foo(object): # pylint: disable=invalid-name @@ -203,7 +212,8 @@ def f(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentsBeforeClassDefs(self): - code = textwrap.dedent('''\ + code = textwrap.dedent( + '''\ """Test.""" # Comment @@ -216,7 +226,8 @@ class Foo(object): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentsBeforeDecorator(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ # The @foo operator adds bork to a(). @foo() def a(): @@ -225,7 +236,8 @@ def a(): llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ # Hello world @@ -237,7 +249,8 @@ def a(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentsAfterDecorator(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class _(): def _(): @@ -254,7 +267,8 @@ def test_unicode_filename_in_sdist(self, sdist_unicode, tmpdir, monkeypatch): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testInnerClasses(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class DeployAPIClient(object): class Error(Exception): pass @@ -262,7 +276,8 @@ class TaskValidationError(Error): pass class DeployAPIHTTPError(Error): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class DeployAPIClient(object): class Error(Exception): @@ -278,7 +293,8 @@ class DeployAPIHTTPError(Error): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testLinesOnRangeBoundary(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent( + u"""\ def A(): pass @@ -292,7 +308,8 @@ def D(): # 9 def E(): pass """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent( + u"""\ def A(): pass @@ -315,7 +332,8 @@ def E(): self.assertTrue(changed) def testLinesRangeBoundaryNotOutside(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent( + u"""\ def A(): pass @@ -329,7 +347,8 @@ def B(): # 6 def C(): pass """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent( + u"""\ def A(): pass @@ -348,7 +367,8 @@ def C(): self.assertFalse(changed) def testLinesRangeRemove(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent( + u"""\ def A(): pass @@ -363,7 +383,8 @@ def B(): # 6 def C(): pass """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent( + u"""\ def A(): pass @@ -382,7 +403,8 @@ def C(): self.assertTrue(changed) def testLinesRangeRemoveSome(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent( + u"""\ def A(): pass @@ -398,7 +420,8 @@ def B(): # 7 def C(): pass """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent( + u"""\ def A(): pass diff --git a/yapftests/comment_splicer_test.py b/yapftests/comment_splicer_test.py index 2e0141bd4..985ea88b7 100644 --- a/yapftests/comment_splicer_test.py +++ b/yapftests/comment_splicer_test.py @@ -38,9 +38,8 @@ def _AssertNodeIsComment(self, node, text_in_comment=None): self.assertIn(text_in_comment, node_value) def _FindNthChildNamed(self, node, name, n=1): - for i, child in enumerate( - py3compat.ifilter(lambda c: pytree_utils.NodeName(c) == name, - node.pre_order())): + for i, child in enumerate(py3compat.ifilter( + lambda c: pytree_utils.NodeName(c) == name, node.pre_order())): if i == n - 1: return child raise RuntimeError('No Nth child for n={0}'.format(n)) @@ -59,7 +58,8 @@ def testSimpleInline(self): self._AssertNodeIsComment(comment_node, '# and a comment') def testSimpleSeparateLine(self): - code = textwrap.dedent(r''' + code = textwrap.dedent( + r''' foo = 1 # first comment bar = 2 @@ -74,7 +74,8 @@ def testSimpleSeparateLine(self): self._AssertNodeIsComment(comment_node) def testTwoLineComment(self): - code = textwrap.dedent(r''' + code = textwrap.dedent( + r''' foo = 1 # first comment # second comment @@ -88,7 +89,8 @@ def testTwoLineComment(self): self._AssertNodeIsComment(tree.children[1]) def testCommentIsFirstChildInCompound(self): - code = textwrap.dedent(r''' + code = textwrap.dedent( + r''' if x: # a comment foo = 1 @@ -104,7 +106,8 @@ def testCommentIsFirstChildInCompound(self): self._AssertNodeIsComment(if_suite.children[1]) def testCommentIsLastChildInCompound(self): - code = textwrap.dedent(r''' + code = textwrap.dedent( + r''' if x: foo = 1 # a comment @@ -120,7 +123,8 @@ def testCommentIsLastChildInCompound(self): self._AssertNodeIsComment(if_suite.children[-2]) def testInlineAfterSeparateLine(self): - code = textwrap.dedent(r''' + code = textwrap.dedent( + r''' bar = 1 # line comment foo = 1 # inline comment @@ -133,12 +137,13 @@ def testInlineAfterSeparateLine(self): sep_comment_node = tree.children[1] self._AssertNodeIsComment(sep_comment_node, '# line comment') - expr = tree.children[2].children[0] + expr = tree.children[2].children[0] inline_comment_node = expr.children[-1] self._AssertNodeIsComment(inline_comment_node, '# inline comment') def testSeparateLineAfterInline(self): - code = textwrap.dedent(r''' + code = textwrap.dedent( + r''' bar = 1 foo = 1 # inline comment # line comment @@ -151,12 +156,13 @@ def testSeparateLineAfterInline(self): sep_comment_node = tree.children[-2] self._AssertNodeIsComment(sep_comment_node, '# line comment') - expr = tree.children[1].children[0] + expr = tree.children[1].children[0] inline_comment_node = expr.children[-1] self._AssertNodeIsComment(inline_comment_node, '# inline comment') def testCommentBeforeDedent(self): - code = textwrap.dedent(r''' + code = textwrap.dedent( + r''' if bar: z = 1 # a comment @@ -171,7 +177,8 @@ def testCommentBeforeDedent(self): self._AssertNodeType('DEDENT', if_suite.children[-1]) def testCommentBeforeDedentTwoLevel(self): - code = textwrap.dedent(r''' + code = textwrap.dedent( + r''' if foo: if bar: z = 1 @@ -188,7 +195,8 @@ def testCommentBeforeDedentTwoLevel(self): self._AssertNodeType('DEDENT', if_suite.children[-1]) def testCommentBeforeDedentTwoLevelImproperlyIndented(self): - code = textwrap.dedent(r''' + code = textwrap.dedent( + r''' if foo: if bar: z = 1 @@ -208,7 +216,8 @@ def testCommentBeforeDedentTwoLevelImproperlyIndented(self): self._AssertNodeType('DEDENT', if_suite.children[-1]) def testCommentBeforeDedentThreeLevel(self): - code = textwrap.dedent(r''' + code = textwrap.dedent( + r''' if foo: if bar: z = 1 @@ -235,7 +244,8 @@ def testCommentBeforeDedentThreeLevel(self): self._AssertNodeType('DEDENT', if_suite_2.children[-1]) def testCommentsInClass(self): - code = textwrap.dedent(r''' + code = textwrap.dedent( + r''' class Foo: """docstring abc...""" # top-level comment @@ -246,18 +256,19 @@ def foo(): pass tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) - class_suite = tree.children[0].children[3] + class_suite = tree.children[0].children[3] another_comment = class_suite.children[-2] self._AssertNodeIsComment(another_comment, '# another') # It's OK for the comment to be a child of funcdef, as long as it's # the first child and thus comes before the 'def'. - funcdef = class_suite.children[3] + funcdef = class_suite.children[3] toplevel_comment = funcdef.children[0] self._AssertNodeIsComment(toplevel_comment, '# top-level') def testMultipleBlockComments(self): - code = textwrap.dedent(r''' + code = textwrap.dedent( + r''' # Block comment number 1 # Block comment number 2 @@ -268,7 +279,7 @@ def f(): tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) - funcdef = tree.children[0] + funcdef = tree.children[0] block_comment_1 = funcdef.children[0] self._AssertNodeIsComment(block_comment_1, '# Block comment number 1') @@ -276,7 +287,8 @@ def f(): self._AssertNodeIsComment(block_comment_2, '# Block comment number 2') def testCommentsOnDedents(self): - code = textwrap.dedent(r''' + code = textwrap.dedent( + r''' class Foo(object): # A comment for qux. def qux(self): @@ -291,7 +303,7 @@ def mux(self): tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) - classdef = tree.children[0] + classdef = tree.children[0] class_suite = classdef.children[6] qux_comment = class_suite.children[1] self._AssertNodeIsComment(qux_comment, '# A comment for qux.') @@ -300,7 +312,8 @@ def mux(self): self._AssertNodeIsComment(interim_comment, '# Interim comment.') def testExprComments(self): - code = textwrap.dedent(r''' + code = textwrap.dedent( + r''' foo( # Request fractions of an hour. 948.0/3600, 20) ''') @@ -312,7 +325,8 @@ def testExprComments(self): self._AssertNodeIsComment(comment, '# Request fractions of an hour.') def testMultipleCommentsInOneExpr(self): - code = textwrap.dedent(r''' + code = textwrap.dedent( + r''' foo( # com 1 948.0/3600, # com 2 20 + 12 # com 3 diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 31184c4a3..9e8c568ea 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -56,7 +56,7 @@ def tearDown(self): # pylint: disable=g-missing-super-call def test_get_exclude_file_patterns_from_yapfignore(self): local_ignore_file = os.path.join(self.test_tmpdir, '.yapfignore') - ignore_patterns = ['temp/**/*.py', 'temp2/*.py'] + ignore_patterns = ['temp/**/*.py', 'temp2/*.py'] with open(local_ignore_file, 'w') as f: f.writelines('\n'.join(ignore_patterns)) @@ -66,7 +66,7 @@ def test_get_exclude_file_patterns_from_yapfignore(self): def test_get_exclude_file_patterns_from_yapfignore_with_wrong_syntax(self): local_ignore_file = os.path.join(self.test_tmpdir, '.yapfignore') - ignore_patterns = ['temp/**/*.py', './wrong/syntax/*.py'] + ignore_patterns = ['temp/**/*.py', './wrong/syntax/*.py'] with open(local_ignore_file, 'w') as f: f.writelines('\n'.join(ignore_patterns)) @@ -79,7 +79,7 @@ def test_get_exclude_file_patterns_from_pyproject(self): except ImportError: return local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') - ignore_patterns = ['temp/**/*.py', 'temp2/*.py'] + ignore_patterns = ['temp/**/*.py', 'temp2/*.py'] with open(local_ignore_file, 'w') as f: f.write('[tool.yapfignore]\n') f.write('ignore_patterns=[') @@ -97,7 +97,7 @@ def test_get_exclude_file_patterns_from_pyproject_with_wrong_syntax(self): except ImportError: return local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') - ignore_patterns = ['temp/**/*.py', './wrong/syntax/*.py'] + ignore_patterns = ['temp/**/*.py', './wrong/syntax/*.py'] with open(local_ignore_file, 'w') as f: f.write('[tool.yapfignore]\n') f.write('ignore_patterns=[') @@ -113,7 +113,7 @@ def test_get_exclude_file_patterns_from_pyproject_no_ignore_section(self): except ImportError: return local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') - ignore_patterns = [] + ignore_patterns = [] open(local_ignore_file, 'w').close() self.assertEqual( @@ -126,7 +126,7 @@ def test_get_exclude_file_patterns_from_pyproject_ignore_section_empty(self): except ImportError: return local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') - ignore_patterns = [] + ignore_patterns = [] with open(local_ignore_file, 'w') as f: f.write('[tool.yapfignore]\n') @@ -151,12 +151,12 @@ def tearDown(self): # pylint: disable=g-missing-super-call shutil.rmtree(self.test_tmpdir) def test_no_local_style(self): - test_file = os.path.join(self.test_tmpdir, 'file.py') + test_file = os.path.join(self.test_tmpdir, 'file.py') style_name = file_resources.GetDefaultStyleForDir(test_file) self.assertEqual(style_name, 'pep8') def test_no_local_style_custom_default(self): - test_file = os.path.join(self.test_tmpdir, 'file.py') + test_file = os.path.join(self.test_tmpdir, 'file.py') style_name = file_resources.GetDefaultStyleForDir( test_file, default_style='custom-default') self.assertEqual(style_name, 'custom-default') @@ -167,27 +167,27 @@ def test_with_local_style(self): open(style_file, 'w').close() test_filename = os.path.join(self.test_tmpdir, 'file.py') - self.assertEqual(style_file, - file_resources.GetDefaultStyleForDir(test_filename)) + self.assertEqual( + style_file, file_resources.GetDefaultStyleForDir(test_filename)) test_filename = os.path.join(self.test_tmpdir, 'dir1', 'file.py') - self.assertEqual(style_file, - file_resources.GetDefaultStyleForDir(test_filename)) + self.assertEqual( + style_file, file_resources.GetDefaultStyleForDir(test_filename)) def test_setup_config(self): # An empty setup.cfg file should not be used setup_config = os.path.join(self.test_tmpdir, 'setup.cfg') open(setup_config, 'w').close() - test_dir = os.path.join(self.test_tmpdir, 'dir1') + test_dir = os.path.join(self.test_tmpdir, 'dir1') style_name = file_resources.GetDefaultStyleForDir(test_dir) self.assertEqual(style_name, 'pep8') # One with a '[yapf]' section should be used with open(setup_config, 'w') as f: f.write('[yapf]\n') - self.assertEqual(setup_config, - file_resources.GetDefaultStyleForDir(test_dir)) + self.assertEqual( + setup_config, file_resources.GetDefaultStyleForDir(test_dir)) def test_pyproject_toml(self): # An empty pyproject.toml file should not be used @@ -199,20 +199,20 @@ def test_pyproject_toml(self): pyproject_toml = os.path.join(self.test_tmpdir, 'pyproject.toml') open(pyproject_toml, 'w').close() - test_dir = os.path.join(self.test_tmpdir, 'dir1') + test_dir = os.path.join(self.test_tmpdir, 'dir1') style_name = file_resources.GetDefaultStyleForDir(test_dir) self.assertEqual(style_name, 'pep8') # One with a '[tool.yapf]' section should be used with open(pyproject_toml, 'w') as f: f.write('[tool.yapf]\n') - self.assertEqual(pyproject_toml, - file_resources.GetDefaultStyleForDir(test_dir)) + self.assertEqual( + pyproject_toml, file_resources.GetDefaultStyleForDir(test_dir)) def test_local_style_at_root(self): # Test behavior of files located on the root, and under root. - rootdir = os.path.abspath(os.path.sep) - test_dir_at_root = os.path.join(rootdir, 'dir1') + rootdir = os.path.abspath(os.path.sep) + test_dir_at_root = os.path.join(rootdir, 'dir1') test_dir_under_root = os.path.join(rootdir, 'dir1', 'dir2') # Fake placing only a style file at the root by mocking `os.path.exists`. @@ -241,7 +241,7 @@ class GetCommandLineFilesTest(unittest.TestCase): def setUp(self): # pylint: disable=g-missing-super-call self.test_tmpdir = tempfile.mkdtemp() - self.old_dir = os.getcwd() + self.old_dir = os.getcwd() def tearDown(self): # pylint: disable=g-missing-super-call os.chdir(self.old_dir) @@ -260,13 +260,11 @@ def test_find_files_not_dirs(self): _touch_files([file1, file2]) self.assertEqual( - file_resources.GetCommandLineFiles([file1, file2], - recursive=False, - exclude=None), [file1, file2]) + file_resources.GetCommandLineFiles( + [file1, file2], recursive=False, exclude=None), [file1, file2]) self.assertEqual( - file_resources.GetCommandLineFiles([file1, file2], - recursive=True, - exclude=None), [file1, file2]) + file_resources.GetCommandLineFiles( + [file1, file2], recursive=True, exclude=None), [file1, file2]) def test_nonrecursive_find_in_dir(self): tdir1 = self._make_test_dir('test1') @@ -295,9 +293,9 @@ def test_recursive_find_in_dir(self): self.assertEqual( sorted( - file_resources.GetCommandLineFiles([self.test_tmpdir], - recursive=True, - exclude=None)), sorted(files)) + file_resources.GetCommandLineFiles( + [self.test_tmpdir], recursive=True, exclude=None)), + sorted(files)) def test_recursive_find_in_dir_with_exclude(self): tdir1 = self._make_test_dir('test1') @@ -312,13 +310,13 @@ def test_recursive_find_in_dir_with_exclude(self): self.assertEqual( sorted( - file_resources.GetCommandLineFiles([self.test_tmpdir], - recursive=True, - exclude=['*test*3.py'])), - sorted([ - os.path.join(tdir1, 'testfile1.py'), - os.path.join(tdir2, 'testfile2.py'), - ])) + file_resources.GetCommandLineFiles( + [self.test_tmpdir], recursive=True, exclude=['*test*3.py'])), + sorted( + [ + os.path.join(tdir1, 'testfile1.py'), + os.path.join(tdir2, 'testfile2.py'), + ])) def test_find_with_excluded_hidden_dirs(self): tdir1 = self._make_test_dir('.test1') @@ -331,16 +329,16 @@ def test_find_with_excluded_hidden_dirs(self): ] _touch_files(files) - actual = file_resources.GetCommandLineFiles([self.test_tmpdir], - recursive=True, - exclude=['*.test1*']) + actual = file_resources.GetCommandLineFiles( + [self.test_tmpdir], recursive=True, exclude=['*.test1*']) self.assertEqual( sorted(actual), - sorted([ - os.path.join(tdir2, 'testfile2.py'), - os.path.join(tdir3, 'testfile3.py'), - ])) + sorted( + [ + os.path.join(tdir2, 'testfile2.py'), + os.path.join(tdir3, 'testfile3.py'), + ])) def test_find_with_excluded_hidden_dirs_relative(self): """Test find with excluded hidden dirs. @@ -375,14 +373,15 @@ def test_find_with_excluded_hidden_dirs_relative(self): self.assertEqual( sorted(actual), - sorted([ - os.path.join( - os.path.relpath(self.test_tmpdir), os.path.basename(tdir2), - 'testfile2.py'), - os.path.join( - os.path.relpath(self.test_tmpdir), os.path.basename(tdir3), - 'testfile3.py'), - ])) + sorted( + [ + os.path.join( + os.path.relpath(self.test_tmpdir), + os.path.basename(tdir2), 'testfile2.py'), + os.path.join( + os.path.relpath(self.test_tmpdir), + os.path.basename(tdir3), 'testfile3.py'), + ])) def test_find_with_excluded_dirs(self): tdir1 = self._make_test_dir('test1') @@ -398,23 +397,23 @@ def test_find_with_excluded_dirs(self): os.chdir(self.test_tmpdir) found = sorted( - file_resources.GetCommandLineFiles(['test1', 'test2', 'test3'], - recursive=True, - exclude=[ - 'test1', - 'test2/testinner/', - ])) + file_resources.GetCommandLineFiles( + ['test1', 'test2', 'test3'], + recursive=True, + exclude=[ + 'test1', + 'test2/testinner/', + ])) self.assertEqual( found, ['test3/foo/bar/bas/xxx/testfile3.py'.replace("/", os.path.sep)]) found = sorted( - file_resources.GetCommandLineFiles(['.'], - recursive=True, - exclude=[ - 'test1', - 'test3', - ])) + file_resources.GetCommandLineFiles( + ['.'], recursive=True, exclude=[ + 'test1', + 'test3', + ])) self.assertEqual( found, ['./test2/testinner/testfile2.py'.replace("/", os.path.sep)]) @@ -517,7 +516,7 @@ def test_write_to_file(self): self.assertEqual(f2.read(), s) def test_write_to_stdout(self): - s = u'foobar' + s = u'foobar' stream = BufferedByteStream() if py3compat.PY3 else py3compat.StringIO() with utils.stdout_redirector(stream): file_resources.WriteReformattedCode( @@ -525,7 +524,7 @@ def test_write_to_stdout(self): self.assertEqual(stream.getvalue(), s) def test_write_encoded_to_stdout(self): - s = '\ufeff# -*- coding: utf-8 -*-\nresult = "passed"\n' # pylint: disable=anomalous-unicode-escape-in-string # noqa + s = '\ufeff# -*- coding: utf-8 -*-\nresult = "passed"\n' # pylint: disable=anomalous-unicode-escape-in-string # noqa stream = BufferedByteStream() if py3compat.PY3 else py3compat.StringIO() with utils.stdout_redirector(stream): file_resources.WriteReformattedCode( @@ -536,17 +535,17 @@ def test_write_encoded_to_stdout(self): class LineEndingTest(unittest.TestCase): def test_line_ending_linefeed(self): - lines = ['spam\n', 'spam\n'] + lines = ['spam\n', 'spam\n'] actual = file_resources.LineEnding(lines) self.assertEqual(actual, '\n') def test_line_ending_carriage_return(self): - lines = ['spam\r', 'spam\r'] + lines = ['spam\r', 'spam\r'] actual = file_resources.LineEnding(lines) self.assertEqual(actual, '\r') def test_line_ending_combo(self): - lines = ['spam\r\n', 'spam\r\n'] + lines = ['spam\r\n', 'spam\r\n'] actual = file_resources.LineEnding(lines) self.assertEqual(actual, '\r\n') diff --git a/yapftests/format_decision_state_test.py b/yapftests/format_decision_state_test.py index 63961f332..d9cdefe8c 100644 --- a/yapftests/format_decision_state_test.py +++ b/yapftests/format_decision_state_test.py @@ -32,12 +32,12 @@ def setUpClass(cls): style.SetGlobalStyle(style.CreateYapfStyle()) def testSimpleFunctionDefWithNoSplitting(self): - code = textwrap.dedent(r""" + code = textwrap.dedent(r""" def f(a, b): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) - lline = logical_line.LogicalLine(0, _FilterLine(llines[0])) + lline = logical_line.LogicalLine(0, _FilterLine(llines[0])) lline.CalculateFormattingInformation() # Add: 'f' @@ -86,12 +86,12 @@ def f(a, b): self.assertEqual(repr(state), repr(clone)) def testSimpleFunctionDefWithSplitting(self): - code = textwrap.dedent(r""" + code = textwrap.dedent(r""" def f(a, b): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) - lline = logical_line.LogicalLine(0, _FilterLine(llines[0])) + lline = logical_line.LogicalLine(0, _FilterLine(llines[0])) lline.CalculateFormattingInformation() # Add: 'f' diff --git a/yapftests/line_joiner_test.py b/yapftests/line_joiner_test.py index 2eaf16478..ea6186693 100644 --- a/yapftests/line_joiner_test.py +++ b/yapftests/line_joiner_test.py @@ -39,20 +39,23 @@ def _CheckLineJoining(self, code, join_lines): self.assertCodeEqual(line_joiner.CanMergeMultipleLines(llines), join_lines) def testSimpleSingleLineStatement(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent( + u"""\ if isinstance(a, int): continue """) self._CheckLineJoining(code, join_lines=True) def testSimpleMultipleLineStatement(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent( + u"""\ if isinstance(b, int): continue """) self._CheckLineJoining(code, join_lines=False) def testSimpleMultipleLineComplexStatement(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent( + u"""\ if isinstance(c, int): while True: continue @@ -60,19 +63,22 @@ def testSimpleMultipleLineComplexStatement(self): self._CheckLineJoining(code, join_lines=False) def testSimpleMultipleLineStatementWithComment(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent( + u"""\ if isinstance(d, int): continue # We're pleased that d's an int. """) self._CheckLineJoining(code, join_lines=True) def testSimpleMultipleLineStatementWithLargeIndent(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent( + u"""\ if isinstance(e, int): continue """) self._CheckLineJoining(code, join_lines=True) def testOverColumnLimit(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent( + u"""\ if instance(bbbbbbbbbbbbbbbbbbbbbbbbb, int): cccccccccccccccccccccccccc = ddddddddddddddddddddd """) # noqa self._CheckLineJoining(code, join_lines=False) diff --git a/yapftests/logical_line_test.py b/yapftests/logical_line_test.py index d18262a7c..695f88bd5 100644 --- a/yapftests/logical_line_test.py +++ b/yapftests/logical_line_test.py @@ -29,25 +29,29 @@ class LogicalLineBasicTest(unittest.TestCase): def testConstruction(self): - toks = _MakeFormatTokenList([(token.DOT, '.', 'DOT'), - (token.VBAR, '|', 'VBAR')]) + toks = _MakeFormatTokenList( + [(token.DOT, '.', 'DOT'), (token.VBAR, '|', 'VBAR')]) lline = logical_line.LogicalLine(20, toks) self.assertEqual(20, lline.depth) self.assertEqual(['DOT', 'VBAR'], [tok.name for tok in lline.tokens]) def testFirstLast(self): - toks = _MakeFormatTokenList([(token.DOT, '.', 'DOT'), - (token.LPAR, '(', 'LPAR'), - (token.VBAR, '|', 'VBAR')]) + toks = _MakeFormatTokenList( + [ + (token.DOT, '.', 'DOT'), (token.LPAR, '(', 'LPAR'), + (token.VBAR, '|', 'VBAR') + ]) lline = logical_line.LogicalLine(20, toks) self.assertEqual(20, lline.depth) self.assertEqual('DOT', lline.first.name) self.assertEqual('VBAR', lline.last.name) def testAsCode(self): - toks = _MakeFormatTokenList([(token.DOT, '.', 'DOT'), - (token.LPAR, '(', 'LPAR'), - (token.VBAR, '|', 'VBAR')]) + toks = _MakeFormatTokenList( + [ + (token.DOT, '.', 'DOT'), (token.LPAR, '(', 'LPAR'), + (token.VBAR, '|', 'VBAR') + ]) lline = logical_line.LogicalLine(2, toks) self.assertEqual(' . ( |', lline.AsCode()) @@ -61,7 +65,7 @@ def testAppendToken(self): class LogicalLineFormattingInformationTest(yapf_test_helper.YAPFTest): def testFuncDef(self): - code = textwrap.dedent(r""" + code = textwrap.dedent(r""" def f(a, b): pass """) diff --git a/yapftests/main_test.py b/yapftests/main_test.py index c83b8b66a..ea6892f5a 100644 --- a/yapftests/main_test.py +++ b/yapftests/main_test.py @@ -78,7 +78,7 @@ def patch_raw_input(lines=lines()): return next(lines) try: - orig_raw_import = yapf.py3compat.raw_input + orig_raw_import = yapf.py3compat.raw_input yapf.py3compat.raw_input = patch_raw_input yield finally: @@ -90,7 +90,7 @@ class RunMainTest(yapf_test_helper.YAPFTest): def testShouldHandleYapfError(self): """run_main should handle YapfError and sys.exit(1).""" expected_message = 'yapf: input filenames did not match any python files\n' - sys.argv = ['yapf', 'foo.c'] + sys.argv = ['yapf', 'foo.c'] with captured_output() as (out, err): with self.assertRaises(SystemExit): yapf.run_main() @@ -114,7 +114,7 @@ def testEchoInput(self): self.assertEqual(out.getvalue(), code) def testEchoInputWithStyle(self): - code = 'def f(a = 1\n\n):\n return 2*a\n' + code = 'def f(a = 1\n\n):\n return 2*a\n' yapf_code = 'def f(a=1):\n return 2 * a\n' with patched_input(code): with captured_output() as (out, _): @@ -135,5 +135,6 @@ def testHelp(self): self.assertEqual(ret, 0) help_message = out.getvalue() self.assertIn('indent_width=4', help_message) - self.assertIn('The number of spaces required before a trailing comment.', - help_message) + self.assertIn( + 'The number of spaces required before a trailing comment.', + help_message) diff --git a/yapftests/pytree_unwrapper_test.py b/yapftests/pytree_unwrapper_test.py index 525278def..cd67e0de1 100644 --- a/yapftests/pytree_unwrapper_test.py +++ b/yapftests/pytree_unwrapper_test.py @@ -43,69 +43,79 @@ def _CheckLogicalLines(self, llines, list_of_expected): self.assertEqual(list_of_expected, actual) def testSimpleFileScope(self): - code = textwrap.dedent(r""" + code = textwrap.dedent( + r""" x = 1 # a comment y = 2 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines(llines, [ - (0, ['x', '=', '1']), - (0, ['# a comment']), - (0, ['y', '=', '2']), - ]) + self._CheckLogicalLines( + llines, [ + (0, ['x', '=', '1']), + (0, ['# a comment']), + (0, ['y', '=', '2']), + ]) def testSimpleMultilineStatement(self): - code = textwrap.dedent(r""" + code = textwrap.dedent(r""" y = (1 + x) """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines(llines, [ - (0, ['y', '=', '(', '1', '+', 'x', ')']), - ]) + self._CheckLogicalLines( + llines, [ + (0, ['y', '=', '(', '1', '+', 'x', ')']), + ]) def testFileScopeWithInlineComment(self): - code = textwrap.dedent(r""" + code = textwrap.dedent( + r""" x = 1 # a comment y = 2 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines(llines, [ - (0, ['x', '=', '1', '# a comment']), - (0, ['y', '=', '2']), - ]) + self._CheckLogicalLines( + llines, [ + (0, ['x', '=', '1', '# a comment']), + (0, ['y', '=', '2']), + ]) def testSimpleIf(self): - code = textwrap.dedent(r""" + code = textwrap.dedent( + r""" if foo: x = 1 y = 2 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines(llines, [ - (0, ['if', 'foo', ':']), - (1, ['x', '=', '1']), - (1, ['y', '=', '2']), - ]) + self._CheckLogicalLines( + llines, [ + (0, ['if', 'foo', ':']), + (1, ['x', '=', '1']), + (1, ['y', '=', '2']), + ]) def testSimpleIfWithComments(self): - code = textwrap.dedent(r""" + code = textwrap.dedent( + r""" # c1 if foo: # c2 x = 1 y = 2 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines(llines, [ - (0, ['# c1']), - (0, ['if', 'foo', ':', '# c2']), - (1, ['x', '=', '1']), - (1, ['y', '=', '2']), - ]) + self._CheckLogicalLines( + llines, [ + (0, ['# c1']), + (0, ['if', 'foo', ':', '# c2']), + (1, ['x', '=', '1']), + (1, ['y', '=', '2']), + ]) def testIfWithCommentsInside(self): - code = textwrap.dedent(r""" + code = textwrap.dedent( + r""" if foo: # c1 x = 1 # c2 @@ -113,16 +123,18 @@ def testIfWithCommentsInside(self): y = 2 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines(llines, [ - (0, ['if', 'foo', ':']), - (1, ['# c1']), - (1, ['x', '=', '1', '# c2']), - (1, ['# c3']), - (1, ['y', '=', '2']), - ]) + self._CheckLogicalLines( + llines, [ + (0, ['if', 'foo', ':']), + (1, ['# c1']), + (1, ['x', '=', '1', '# c2']), + (1, ['# c3']), + (1, ['y', '=', '2']), + ]) def testIfElifElse(self): - code = textwrap.dedent(r""" + code = textwrap.dedent( + r""" if x: x = 1 # c1 elif y: # c2 @@ -132,18 +144,20 @@ def testIfElifElse(self): z = 1 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines(llines, [ - (0, ['if', 'x', ':']), - (1, ['x', '=', '1', '# c1']), - (0, ['elif', 'y', ':', '# c2']), - (1, ['y', '=', '1']), - (0, ['else', ':']), - (1, ['# c3']), - (1, ['z', '=', '1']), - ]) + self._CheckLogicalLines( + llines, [ + (0, ['if', 'x', ':']), + (1, ['x', '=', '1', '# c1']), + (0, ['elif', 'y', ':', '# c2']), + (1, ['y', '=', '1']), + (0, ['else', ':']), + (1, ['# c3']), + (1, ['z', '=', '1']), + ]) def testNestedCompoundTwoLevel(self): - code = textwrap.dedent(r""" + code = textwrap.dedent( + r""" if x: x = 1 # c1 while t: @@ -152,30 +166,34 @@ def testNestedCompoundTwoLevel(self): k = 1 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines(llines, [ - (0, ['if', 'x', ':']), - (1, ['x', '=', '1', '# c1']), - (1, ['while', 't', ':']), - (2, ['# c2']), - (2, ['j', '=', '1']), - (1, ['k', '=', '1']), - ]) + self._CheckLogicalLines( + llines, [ + (0, ['if', 'x', ':']), + (1, ['x', '=', '1', '# c1']), + (1, ['while', 't', ':']), + (2, ['# c2']), + (2, ['j', '=', '1']), + (1, ['k', '=', '1']), + ]) def testSimpleWhile(self): - code = textwrap.dedent(r""" + code = textwrap.dedent( + r""" while x > 1: # c1 # c2 x = 1 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines(llines, [ - (0, ['while', 'x', '>', '1', ':', '# c1']), - (1, ['# c2']), - (1, ['x', '=', '1']), - ]) + self._CheckLogicalLines( + llines, [ + (0, ['while', 'x', '>', '1', ':', '# c1']), + (1, ['# c2']), + (1, ['x', '=', '1']), + ]) def testSimpleTry(self): - code = textwrap.dedent(r""" + code = textwrap.dedent( + r""" try: pass except: @@ -188,34 +206,38 @@ def testSimpleTry(self): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines(llines, [ - (0, ['try', ':']), - (1, ['pass']), - (0, ['except', ':']), - (1, ['pass']), - (0, ['except', ':']), - (1, ['pass']), - (0, ['else', ':']), - (1, ['pass']), - (0, ['finally', ':']), - (1, ['pass']), - ]) + self._CheckLogicalLines( + llines, [ + (0, ['try', ':']), + (1, ['pass']), + (0, ['except', ':']), + (1, ['pass']), + (0, ['except', ':']), + (1, ['pass']), + (0, ['else', ':']), + (1, ['pass']), + (0, ['finally', ':']), + (1, ['pass']), + ]) def testSimpleFuncdef(self): - code = textwrap.dedent(r""" + code = textwrap.dedent( + r""" def foo(x): # c1 # c2 return x """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines(llines, [ - (0, ['def', 'foo', '(', 'x', ')', ':', '# c1']), - (1, ['# c2']), - (1, ['return', 'x']), - ]) + self._CheckLogicalLines( + llines, [ + (0, ['def', 'foo', '(', 'x', ')', ':', '# c1']), + (1, ['# c2']), + (1, ['return', 'x']), + ]) def testTwoFuncDefs(self): - code = textwrap.dedent(r""" + code = textwrap.dedent( + r""" def foo(x): # c1 # c2 return x @@ -225,40 +247,45 @@ def bar(): # c3 return x """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines(llines, [ - (0, ['def', 'foo', '(', 'x', ')', ':', '# c1']), - (1, ['# c2']), - (1, ['return', 'x']), - (0, ['def', 'bar', '(', ')', ':', '# c3']), - (1, ['# c4']), - (1, ['return', 'x']), - ]) + self._CheckLogicalLines( + llines, [ + (0, ['def', 'foo', '(', 'x', ')', ':', '# c1']), + (1, ['# c2']), + (1, ['return', 'x']), + (0, ['def', 'bar', '(', ')', ':', '# c3']), + (1, ['# c4']), + (1, ['return', 'x']), + ]) def testSimpleClassDef(self): - code = textwrap.dedent(r""" + code = textwrap.dedent( + r""" class Klass: # c1 # c2 p = 1 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines(llines, [ - (0, ['class', 'Klass', ':', '# c1']), - (1, ['# c2']), - (1, ['p', '=', '1']), - ]) + self._CheckLogicalLines( + llines, [ + (0, ['class', 'Klass', ':', '# c1']), + (1, ['# c2']), + (1, ['p', '=', '1']), + ]) def testSingleLineStmtInFunc(self): - code = textwrap.dedent(r""" + code = textwrap.dedent(r""" def f(): return 37 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines(llines, [ - (0, ['def', 'f', '(', ')', ':']), - (1, ['return', '37']), - ]) + self._CheckLogicalLines( + llines, [ + (0, ['def', 'f', '(', ')', ':']), + (1, ['return', '37']), + ]) def testMultipleComments(self): - code = textwrap.dedent(r""" + code = textwrap.dedent( + r""" # Comment #1 # Comment #2 @@ -266,15 +293,17 @@ def f(): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines(llines, [ - (0, ['# Comment #1']), - (0, ['# Comment #2']), - (0, ['def', 'f', '(', ')', ':']), - (1, ['pass']), - ]) + self._CheckLogicalLines( + llines, [ + (0, ['# Comment #1']), + (0, ['# Comment #2']), + (0, ['def', 'f', '(', ')', ':']), + (1, ['pass']), + ]) def testSplitListWithComment(self): - code = textwrap.dedent(r""" + code = textwrap.dedent( + r""" a = [ 'a', 'b', @@ -282,9 +311,14 @@ def testSplitListWithComment(self): ] """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines(llines, [(0, [ - 'a', '=', '[', "'a'", ',', "'b'", ',', "'c'", ',', '# hello world', ']' - ])]) + self._CheckLogicalLines( + llines, [ + ( + 0, [ + 'a', '=', '[', "'a'", ',', "'b'", ',', "'c'", ',', + '# hello world', ']' + ]) + ]) class MatchBracketsTest(yapf_test_helper.YAPFTest): @@ -300,9 +334,11 @@ def _CheckMatchingBrackets(self, llines, list_of_expected): """ actual = [] for lline in llines: - filtered_values = [(ft, ft.matching_bracket) - for ft in lline.tokens - if ft.name not in pytree_utils.NONSEMANTIC_TOKENS] + filtered_values = [ + (ft, ft.matching_bracket) + for ft in lline.tokens + if ft.name not in pytree_utils.NONSEMANTIC_TOKENS + ] if filtered_values: actual.append(filtered_values) @@ -317,7 +353,8 @@ def _CheckMatchingBrackets(self, llines, list_of_expected): self.assertEqual(lline[close_bracket][0], lline[open_bracket][1]) def testFunctionDef(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def foo(a, b=['w','d'], c=[42, 37]): pass """) @@ -328,7 +365,8 @@ def foo(a, b=['w','d'], c=[42, 37]): ]) def testDecorator(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ @bar() def foo(a, b, c): pass @@ -341,7 +379,8 @@ def foo(a, b, c): ]) def testClassDef(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class A(B, C, D): pass """) diff --git a/yapftests/pytree_utils_test.py b/yapftests/pytree_utils_test.py index c175f833e..ec61f75d2 100644 --- a/yapftests/pytree_utils_test.py +++ b/yapftests/pytree_utils_test.py @@ -25,7 +25,7 @@ # module. _GRAMMAR_SYMBOL2NUMBER = pygram.python_grammar.symbol2number -_FOO = 'foo' +_FOO = 'foo' _FOO1 = 'foo1' _FOO2 = 'foo2' _FOO3 = 'foo3' @@ -87,12 +87,12 @@ def _BuildSimpleTree(self): # simple_stmt: # NAME('foo') # - lpar1 = pytree.Leaf(token.LPAR, '(') - lpar2 = pytree.Leaf(token.LPAR, '(') - simple_stmt = pytree.Node(_GRAMMAR_SYMBOL2NUMBER['simple_stmt'], - [pytree.Leaf(token.NAME, 'foo')]) - return pytree.Node(_GRAMMAR_SYMBOL2NUMBER['suite'], - [lpar1, lpar2, simple_stmt]) + lpar1 = pytree.Leaf(token.LPAR, '(') + lpar2 = pytree.Leaf(token.LPAR, '(') + simple_stmt = pytree.Node( + _GRAMMAR_SYMBOL2NUMBER['simple_stmt'], [pytree.Leaf(token.NAME, 'foo')]) + return pytree.Node( + _GRAMMAR_SYMBOL2NUMBER['suite'], [lpar1, lpar2, simple_stmt]) def _MakeNewNodeRPAR(self): return pytree.Leaf(token.RPAR, ')') @@ -102,18 +102,18 @@ def setUp(self): def testInsertNodesBefore(self): # Insert before simple_stmt and make sure it went to the right place - pytree_utils.InsertNodesBefore([self._MakeNewNodeRPAR()], - self._simple_tree.children[2]) + pytree_utils.InsertNodesBefore( + [self._MakeNewNodeRPAR()], self._simple_tree.children[2]) self.assertEqual(4, len(self._simple_tree.children)) - self.assertEqual('RPAR', - pytree_utils.NodeName(self._simple_tree.children[2])) - self.assertEqual('simple_stmt', - pytree_utils.NodeName(self._simple_tree.children[3])) + self.assertEqual( + 'RPAR', pytree_utils.NodeName(self._simple_tree.children[2])) + self.assertEqual( + 'simple_stmt', pytree_utils.NodeName(self._simple_tree.children[3])) def testInsertNodesBeforeFirstChild(self): # Insert before the first child of its parent simple_stmt = self._simple_tree.children[2] - foo_child = simple_stmt.children[0] + foo_child = simple_stmt.children[0] pytree_utils.InsertNodesBefore([self._MakeNewNodeRPAR()], foo_child) self.assertEqual(3, len(self._simple_tree.children)) self.assertEqual(2, len(simple_stmt.children)) @@ -122,18 +122,18 @@ def testInsertNodesBeforeFirstChild(self): def testInsertNodesAfter(self): # Insert after and make sure it went to the right place - pytree_utils.InsertNodesAfter([self._MakeNewNodeRPAR()], - self._simple_tree.children[2]) + pytree_utils.InsertNodesAfter( + [self._MakeNewNodeRPAR()], self._simple_tree.children[2]) self.assertEqual(4, len(self._simple_tree.children)) - self.assertEqual('simple_stmt', - pytree_utils.NodeName(self._simple_tree.children[2])) - self.assertEqual('RPAR', - pytree_utils.NodeName(self._simple_tree.children[3])) + self.assertEqual( + 'simple_stmt', pytree_utils.NodeName(self._simple_tree.children[2])) + self.assertEqual( + 'RPAR', pytree_utils.NodeName(self._simple_tree.children[3])) def testInsertNodesAfterLastChild(self): # Insert after the last child of its parent simple_stmt = self._simple_tree.children[2] - foo_child = simple_stmt.children[0] + foo_child = simple_stmt.children[0] pytree_utils.InsertNodesAfter([self._MakeNewNodeRPAR()], foo_child) self.assertEqual(3, len(self._simple_tree.children)) self.assertEqual(2, len(simple_stmt.children)) @@ -143,16 +143,16 @@ def testInsertNodesAfterLastChild(self): def testInsertNodesWhichHasParent(self): # Try to insert an existing tree node into another place and fail. with self.assertRaises(RuntimeError): - pytree_utils.InsertNodesAfter([self._simple_tree.children[1]], - self._simple_tree.children[0]) + pytree_utils.InsertNodesAfter( + [self._simple_tree.children[1]], self._simple_tree.children[0]) class AnnotationsTest(unittest.TestCase): def setUp(self): self._leaf = pytree.Leaf(token.LPAR, '(') - self._node = pytree.Node(_GRAMMAR_SYMBOL2NUMBER['simple_stmt'], - [pytree.Leaf(token.NAME, 'foo')]) + self._node = pytree.Node( + _GRAMMAR_SYMBOL2NUMBER['simple_stmt'], [pytree.Leaf(token.NAME, 'foo')]) def testGetWhenNone(self): self.assertIsNone(pytree_utils.GetNodeAnnotation(self._leaf, _FOO)) @@ -183,18 +183,18 @@ def testMultiple(self): self.assertEqual(pytree_utils.GetNodeAnnotation(self._leaf, _FOO5), 5) def testSubtype(self): - pytree_utils.AppendNodeAnnotation(self._leaf, - pytree_utils.Annotation.SUBTYPE, _FOO) + pytree_utils.AppendNodeAnnotation( + self._leaf, pytree_utils.Annotation.SUBTYPE, _FOO) self.assertSetEqual( - pytree_utils.GetNodeAnnotation(self._leaf, - pytree_utils.Annotation.SUBTYPE), {_FOO}) + pytree_utils.GetNodeAnnotation( + self._leaf, pytree_utils.Annotation.SUBTYPE), {_FOO}) pytree_utils.RemoveSubtypeAnnotation(self._leaf, _FOO) self.assertSetEqual( - pytree_utils.GetNodeAnnotation(self._leaf, - pytree_utils.Annotation.SUBTYPE), set()) + pytree_utils.GetNodeAnnotation( + self._leaf, pytree_utils.Annotation.SUBTYPE), set()) def testSetOnNode(self): pytree_utils.SetNodeAnnotation(self._node, _FOO, 20) diff --git a/yapftests/pytree_visitor_test.py b/yapftests/pytree_visitor_test.py index 45a83b113..231183030 100644 --- a/yapftests/pytree_visitor_test.py +++ b/yapftests/pytree_visitor_test.py @@ -31,7 +31,7 @@ class _NodeNameCollector(pytree_visitor.PyTreeVisitor): """ def __init__(self): - self.all_node_names = [] + self.all_node_names = [] self.name_node_values = [] def DefaultNodeVisit(self, node): @@ -61,7 +61,7 @@ def Visit_NAME(self, leaf): class PytreeVisitorTest(unittest.TestCase): def testCollectAllNodeNamesSimpleCode(self): - tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_SIMPLE_CODE) + tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_SIMPLE_CODE) collector = _NodeNameCollector() collector.Visit(tree) expected_names = [ @@ -76,7 +76,7 @@ def testCollectAllNodeNamesSimpleCode(self): self.assertEqual(expected_name_node_values, collector.name_node_values) def testCollectAllNodeNamesNestedCode(self): - tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_NESTED_CODE) + tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_NESTED_CODE) collector = _NodeNameCollector() collector.Visit(tree) expected_names = [ @@ -95,7 +95,7 @@ def testCollectAllNodeNamesNestedCode(self): def testDumper(self): # PyTreeDumper is mainly a debugging utility, so only do basic sanity # checking. - tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_SIMPLE_CODE) + tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_SIMPLE_CODE) stream = py3compat.StringIO() pytree_visitor.PyTreeDumper(target_stream=stream).Visit(tree) @@ -106,7 +106,7 @@ def testDumper(self): def testDumpPyTree(self): # Similar sanity checking for the convenience wrapper DumpPyTree - tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_SIMPLE_CODE) + tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_SIMPLE_CODE) stream = py3compat.StringIO() pytree_visitor.DumpPyTree(tree, target_stream=stream) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 798dbab9a..7f1e1a43e 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -33,10 +33,12 @@ def testSplittingAllArgs(self): style.SetGlobalStyle( style.CreateStyleFromConfig( '{split_all_comma_separated_values: true, column_limit: 40}')) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ responseDict = {"timestamp": timestamp, "someValue": value, "whatever": 120} """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ responseDict = { "timestamp": timestamp, "someValue": value, @@ -46,10 +48,12 @@ def testSplittingAllArgs(self): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ yes = { 'yes': 'no', 'no': 'yes', } """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ yes = { 'yes': 'no', 'no': 'yes', @@ -57,11 +61,13 @@ def testSplittingAllArgs(self): """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo(long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args): pass """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo(long_arg, really_long_arg, really_really_long_arg, @@ -70,10 +76,12 @@ def foo(long_arg, """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ foo_tuple = [long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args] """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ foo_tuple = [ long_arg, really_long_arg, @@ -83,21 +91,25 @@ def foo(long_arg, """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ foo_tuple = [short, arg] """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ foo_tuple = [short, arg] """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # There is a test for split_all_top_level_comma_separated_values, with # different expected value - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ someLongFunction(this_is_a_very_long_parameter, abc=(a, this_will_just_fit_xxxxxxx)) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ someLongFunction( this_is_a_very_long_parameter, abc=(a, @@ -112,10 +124,12 @@ def testSplittingTopLevelAllArgs(self): '{split_all_top_level_comma_separated_values: true, ' 'column_limit: 40}')) # Works the same way as split_all_comma_separated_values - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ responseDict = {"timestamp": timestamp, "someValue": value, "whatever": 120} """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ responseDict = { "timestamp": timestamp, "someValue": value, @@ -125,11 +139,13 @@ def testSplittingTopLevelAllArgs(self): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Works the same way as split_all_comma_separated_values - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo(long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args): pass """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo(long_arg, really_long_arg, really_really_long_arg, @@ -139,10 +155,12 @@ def foo(long_arg, llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Works the same way as split_all_comma_separated_values - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ foo_tuple = [long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args] """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ foo_tuple = [ long_arg, really_long_arg, @@ -153,35 +171,41 @@ def foo(long_arg, llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Works the same way as split_all_comma_separated_values - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ foo_tuple = [short, arg] """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ foo_tuple = [short, arg] """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # There is a test for split_all_comma_separated_values, with different # expected value - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ someLongFunction(this_is_a_very_long_parameter, abc=(a, this_will_just_fit_xxxxxxx)) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ someLongFunction( this_is_a_very_long_parameter, abc=(a, this_will_just_fit_xxxxxxx)) """) - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) actual_formatted_code = reformatter.Reformat(llines) self.assertEqual(40, len(actual_formatted_code.splitlines()[-1])) self.assertCodeEqual(expected_formatted_code, actual_formatted_code) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ someLongFunction(this_is_a_very_long_parameter, abc=(a, this_will_not_fit_xxxxxxxxx)) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ someLongFunction( this_is_a_very_long_parameter, abc=(a, @@ -191,11 +215,13 @@ def foo(long_arg, self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Exercise the case where there's no opening bracket (for a, b) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ a, b = f( a_very_long_parameter, yet_another_one, and_another) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ a, b = f( a_very_long_parameter, yet_another_one, and_another) """) @@ -203,7 +229,8 @@ def foo(long_arg, self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Don't require splitting before comments. - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ KO = { 'ABC': Abc, # abc 'DEF': Def, # def @@ -212,7 +239,8 @@ def foo(long_arg, 'JKL': Jkl, } """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ KO = { 'ABC': Abc, # abc 'DEF': Def, # def @@ -225,7 +253,8 @@ def foo(long_arg, self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSimpleFunctionsWithTrailingComments(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def g(): # Trailing comment if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -237,7 +266,8 @@ def f( # Intermediate comment xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def g(): # Trailing comment if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -254,11 +284,13 @@ def f( # Intermediate comment self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBlankLinesBetweenTopLevelImportsAndVariables(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ import foo as bar VAR = 'baz' """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ import foo as bar VAR = 'baz' @@ -266,12 +298,14 @@ def testBlankLinesBetweenTopLevelImportsAndVariables(self): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ import foo as bar VAR = 'baz' """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ import foo as bar @@ -283,28 +317,32 @@ def testBlankLinesBetweenTopLevelImportsAndVariables(self): '{based_on_style: yapf, ' 'blank_lines_between_top_level_imports_and_variables: 2}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ import foo as bar # Some comment """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ import foo as bar # Some comment """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ import foo as bar class Baz(): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ import foo as bar @@ -314,12 +352,14 @@ class Baz(): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ import foo as bar def foobar(): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ import foo as bar @@ -329,12 +369,14 @@ def foobar(): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foobar(): from foo import Bar Bar.baz() """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foobar(): from foo import Bar Bar.baz() @@ -343,34 +385,39 @@ def foobar(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBlankLinesAtEndOfFile(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foobar(): # foo pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foobar(): # foo pass """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ x = { 'a':37,'b':42, 'c':927} """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ x = {'a': 37, 'b': 42, 'c': 927} """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testIndentBlankLines(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class foo(object): def foobar(self): @@ -398,18 +445,19 @@ class foo(object):\n \n def foobar(self):\n \n pass\n \n def barfoo(se '{based_on_style: yapf, indent_blank_lines: true}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) - unformatted_code, expected_formatted_code = (expected_formatted_code, - unformatted_code) + unformatted_code, expected_formatted_code = ( + expected_formatted_code, unformatted_code) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMultipleUgliness(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ x = { 'a':37,'b':42, 'c':927} @@ -425,7 +473,8 @@ def g(self, x,y=42): def f ( a ) : return 37+-+a[42-x : y**3] """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ x = {'a': 37, 'b': 42, 'c': 927} y = 'hello ' 'world' @@ -449,7 +498,8 @@ def f(a): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testComments(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class Foo(object): pass @@ -471,7 +521,8 @@ class Baz(object): class Qux(object): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class Foo(object): pass @@ -502,16 +553,18 @@ class Qux(object): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSingleComment(self): - code = textwrap.dedent("""\ + code = textwrap.dedent("""\ # Thing 1 """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentsWithTrailingSpaces(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ # Thing 1 \n# Thing 2 \n""") - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ # Thing 1 # Thing 2 """) @@ -519,7 +572,8 @@ def testCommentsWithTrailingSpaces(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testCommentsInDataLiteral(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def f(): return collections.OrderedDict({ # First comment. @@ -536,7 +590,8 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testEndingWhitespaceAfterSimpleStatement(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ import foo as bar # Thing 1 # Thing 2 @@ -545,7 +600,8 @@ def testEndingWhitespaceAfterSimpleStatement(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDocstrings(self): - unformatted_code = textwrap.dedent('''\ + unformatted_code = textwrap.dedent( + '''\ u"""Module-level docstring.""" import os class Foo(object): @@ -562,7 +618,8 @@ def qux(self): print('hello {}'.format('world')) return 42 ''') - expected_formatted_code = textwrap.dedent('''\ + expected_formatted_code = textwrap.dedent( + '''\ u"""Module-level docstring.""" import os @@ -583,7 +640,8 @@ def qux(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDocstringAndMultilineComment(self): - unformatted_code = textwrap.dedent('''\ + unformatted_code = textwrap.dedent( + '''\ """Hello world""" # A multiline # comment @@ -597,7 +655,8 @@ def foo(self): # comment pass ''') - expected_formatted_code = textwrap.dedent('''\ + expected_formatted_code = textwrap.dedent( + '''\ """Hello world""" @@ -618,7 +677,8 @@ def foo(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMultilineDocstringAndMultilineComment(self): - unformatted_code = textwrap.dedent('''\ + unformatted_code = textwrap.dedent( + '''\ """Hello world RIP Dennis Richie. @@ -641,7 +701,8 @@ def foo(self): # comment pass ''') - expected_formatted_code = textwrap.dedent('''\ + expected_formatted_code = textwrap.dedent( + '''\ """Hello world RIP Dennis Richie. @@ -671,24 +732,26 @@ def foo(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testTupleCommaBeforeLastParen(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ a = ( 1, ) """) expected_formatted_code = textwrap.dedent("""\ a = (1,) """) - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoBreakOutsideOfBracket(self): # FIXME(morbo): How this is formatted is not correct. But it's syntactically # correct. - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def f(): assert port >= minimum, \ 'Unexpected port %d when minimum was %d.' % (port, minimum) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def f(): assert port >= minimum, 'Unexpected port %d when minimum was %d.' % (port, minimum) @@ -697,7 +760,8 @@ def f(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBlankLinesBeforeDecorators(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ @foo() class A(object): @bar() @@ -705,7 +769,8 @@ class A(object): def x(self): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ @foo() class A(object): @@ -718,14 +783,16 @@ def x(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testCommentBetweenDecorators(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ @foo() # frob @bar def x (self): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ @foo() # frob @bar @@ -736,12 +803,14 @@ def x(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testListComprehension(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def given(y): [k for k in () if k in y] """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def given(y): [k for k in () if k in y] """) @@ -749,14 +818,16 @@ def given(y): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testListComprehensionPreferOneLine(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def given(y): long_variable_name = [ long_var_name + 1 for long_var_name in () if long_var_name == 2] """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def given(y): long_variable_name = [ long_var_name + 1 for long_var_name in () if long_var_name == 2 @@ -766,12 +837,14 @@ def given(y): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testListComprehensionPreferOneLineOverArithmeticSplit(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def given(used_identifiers): return (sum(len(identifier) for identifier in used_identifiers) / len(used_identifiers)) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def given(used_identifiers): return (sum(len(identifier) for identifier in used_identifiers) / len(used_identifiers)) @@ -780,14 +853,16 @@ def given(used_identifiers): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testListComprehensionPreferThreeLinesForLineWrap(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def given(y): long_variable_name = [ long_var_name + 1 for long_var_name, number_two in () if long_var_name == 2 and number_two == 3] """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def given(y): long_variable_name = [ long_var_name + 1 @@ -799,14 +874,16 @@ def given(y): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testListComprehensionPreferNoBreakForTrivialExpression(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def given(y): long_variable_name = [ long_var_name for long_var_name, number_two in () if long_var_name == 2 and number_two == 3] """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def given(y): long_variable_name = [ long_var_name for long_var_name, number_two in () @@ -817,7 +894,7 @@ def given(y): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testOpeningAndClosingBrackets(self): - unformatted_code = """\ + unformatted_code = """\ foo( (1, ) ) foo( ( 1, 2, 3 ) ) foo( ( 1, 2, 3, ) ) @@ -831,14 +908,16 @@ def testOpeningAndClosingBrackets(self): 3, )) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSingleLineFunctions(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo(): return 42 """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo(): return 42 """) @@ -849,21 +928,23 @@ def testNoQueueSeletionInMiddleOfLine(self): # If the queue isn't properly constructed, then a token in the middle of the # line may be selected as the one with least penalty. The tokens after that # one are then splatted at the end of the line with no formatting. - unformatted_code = """\ + unformatted_code = """\ find_symbol(node.type) + "< " + " ".join(find_pattern(n) for n in node.child) + " >" """ # noqa expected_formatted_code = """\ find_symbol(node.type) + "< " + " ".join( find_pattern(n) for n in node.child) + " >" """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoSpacesBetweenSubscriptsAndCalls(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ aaaaaaaaaa = bbbbbbbb.ccccccccc() [42] (a, 2) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ aaaaaaaaaa = bbbbbbbb.ccccccccc()[42](a, 2) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) @@ -871,21 +952,25 @@ def testNoSpacesBetweenSubscriptsAndCalls(self): def testNoSpacesBetweenOpeningBracketAndStartingOperator(self): # Unary operator. - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ aaaaaaaaaa = bbbbbbbb.ccccccccc[ -1 ]( -42 ) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ aaaaaaaaaa = bbbbbbbb.ccccccccc[-1](-42) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Varargs and kwargs. - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ aaaaaaaaaa = bbbbbbbb.ccccccccc( *varargs ) aaaaaaaaaa = bbbbbbbb.ccccccccc( **kwargs ) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ aaaaaaaaaa = bbbbbbbb.ccccccccc(*varargs) aaaaaaaaaa = bbbbbbbb.ccccccccc(**kwargs) """) @@ -893,13 +978,15 @@ def testNoSpacesBetweenOpeningBracketAndStartingOperator(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMultilineCommentReformatted(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if True: # This is a multiline # comment. pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if True: # This is a multiline # comment. @@ -909,7 +996,8 @@ def testMultilineCommentReformatted(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDictionaryMakerFormatting(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ _PYTHON_STATEMENTS = frozenset({ lambda x, y: 'simple_stmt': 'small_stmt', 'expr_stmt': 'print_stmt', 'del_stmt': 'pass_stmt', lambda: 'break_stmt': 'continue_stmt', 'return_stmt': 'raise_stmt', @@ -917,7 +1005,8 @@ def testDictionaryMakerFormatting(self): 'if_stmt', 'while_stmt': 'for_stmt', }) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ _PYTHON_STATEMENTS = frozenset({ lambda x, y: 'simple_stmt': 'small_stmt', 'expr_stmt': 'print_stmt', @@ -934,14 +1023,16 @@ def testDictionaryMakerFormatting(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSimpleMultilineCode(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if True: aaaaaaaaaaaaaa.bbbbbbbbbbbbbb.ccccccc(zzzzzzzzzzzz, \ xxxxxxxxxxx, yyyyyyyyyyyy, vvvvvvvvv) aaaaaaaaaaaaaa.bbbbbbbbbbbbbb.ccccccc(zzzzzzzzzzzz, \ xxxxxxxxxxx, yyyyyyyyyyyy, vvvvvvvvv) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if True: aaaaaaaaaaaaaa.bbbbbbbbbbbbbb.ccccccc(zzzzzzzzzzzz, xxxxxxxxxxx, yyyyyyyyyyyy, vvvvvvvvv) @@ -952,7 +1043,8 @@ def testSimpleMultilineCode(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMultilineComment(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ if Foo: # Hello world # Yo man. @@ -965,14 +1057,15 @@ def testMultilineComment(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testSpaceBetweenStringAndParentheses(self): - code = textwrap.dedent("""\ + code = textwrap.dedent("""\ b = '0' ('hello') """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testMultilineString(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ code = textwrap.dedent('''\ if Foo: # Hello world @@ -986,7 +1079,8 @@ def testMultilineString(self): llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent('''\ + unformatted_code = textwrap.dedent( + '''\ def f(): email_text += """This is a really long docstring that goes over the column limit and is multi-line.

Czar: """+despot["Nicholas"]+"""
@@ -995,7 +1089,8 @@ def f(): """ ''') # noqa - expected_formatted_code = textwrap.dedent('''\ + expected_formatted_code = textwrap.dedent( + '''\ def f(): email_text += """This is a really long docstring that goes over the column limit and is multi-line.

Czar: """ + despot["Nicholas"] + """
@@ -1008,7 +1103,8 @@ def f(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSimpleMultilineWithComments(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ if ( # This is the first comment a and # This is the second comment # This is the third comment @@ -1020,12 +1116,14 @@ def testSimpleMultilineWithComments(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testMatchingParenSplittingMatching(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def f(): raise RuntimeError('unable to find insertion point for target node', (target,)) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def f(): raise RuntimeError('unable to find insertion point for target node', (target,)) @@ -1034,7 +1132,8 @@ def f(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testContinuationIndent(self): - unformatted_code = textwrap.dedent('''\ + unformatted_code = textwrap.dedent( + '''\ class F: def _ProcessArgLists(self, node): """Common method for processing argument lists.""" @@ -1044,7 +1143,8 @@ def _ProcessArgLists(self, node): child, subtype=_ARGLIST_TOKEN_TO_SUBTYPE.get( child.value, format_token.Subtype.NONE)) ''') - expected_formatted_code = textwrap.dedent('''\ + expected_formatted_code = textwrap.dedent( + '''\ class F: def _ProcessArgLists(self, node): @@ -1060,12 +1160,14 @@ def _ProcessArgLists(self, node): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testTrailingCommaAndBracket(self): - unformatted_code = textwrap.dedent('''\ + unformatted_code = textwrap.dedent( + '''\ a = { 42, } b = ( 42, ) c = [ 42, ] ''') - expected_formatted_code = textwrap.dedent('''\ + expected_formatted_code = textwrap.dedent( + '''\ a = { 42, } @@ -1078,20 +1180,23 @@ def testTrailingCommaAndBracket(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testI18n(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ N_('Some years ago - never mind how long precisely - having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world.') # A comment is here. """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ foo('Fake function call') #. Some years ago - never mind how long precisely - having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testI18nCommentsInDataLiteral(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def f(): return collections.OrderedDict({ #. First i18n comment. @@ -1105,7 +1210,8 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testClosingBracketIndent(self): - code = textwrap.dedent('''\ + code = textwrap.dedent( + '''\ def f(): def g(): @@ -1118,7 +1224,8 @@ def g(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testClosingBracketsInlinedInCall(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class Foo(object): def bar(self): @@ -1132,7 +1239,8 @@ def bar(self): "porkporkpork": 5, }) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class Foo(object): def bar(self): @@ -1150,7 +1258,8 @@ def bar(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testLineWrapInForExpression(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class A: def x(self, node, name, n=1): @@ -1163,7 +1272,7 @@ def x(self, node, name, n=1): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionCallContinuationLine(self): - code = """\ + code = """\ class foo: def bar(self, node, name, n=1): @@ -1177,7 +1286,8 @@ def bar(self, node, name, n=1): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testI18nNonFormatting(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class F(object): def __init__(self, fieldname, @@ -1189,7 +1299,8 @@ def __init__(self, fieldname, self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSpaceBetweenUnaryOpAndOpeningParen(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ if ~(a or b): pass """) @@ -1197,7 +1308,8 @@ def testNoSpaceBetweenUnaryOpAndOpeningParen(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentBeforeFuncDef(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class Foo(object): a = 42 @@ -1215,7 +1327,8 @@ def __init__(self, self.assertCodeEqual(code, reformatter.Reformat(llines)) def testExcessLineCountWithDefaultKeywords(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class Fnord(object): def Moo(self): aaaaaaaaaaaaaaaa = self._bbbbbbbbbbbbbbbbbbbbbbb( @@ -1223,7 +1336,8 @@ def Moo(self): fffff=fffff, ggggggg=ggggggg, hhhhhhhhhhhhh=hhhhhhhhhhhhh, iiiiiii=iiiiiiiiiiiiii) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class Fnord(object): def Moo(self): @@ -1240,7 +1354,8 @@ def Moo(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSpaceAfterNotOperator(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ if not (this and that): pass """) @@ -1248,7 +1363,8 @@ def testSpaceAfterNotOperator(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoPenaltySplitting(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def f(): if True: if True: @@ -1261,7 +1377,8 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testExpressionPenalties(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def f(): if ((left.value == '(' and right.value == ')') or (left.value == '[' and right.value == ']') or @@ -1272,14 +1389,16 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testLineDepthOfSingleLineStatement(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ while True: continue for x in range(3): continue try: a = 42 except: b = 42 with open(a) as fd: a = fd.read() """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ while True: continue for x in range(3): @@ -1295,11 +1414,13 @@ def testLineDepthOfSingleLineStatement(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplitListWithTerminatingComma(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ FOO = ['bar', 'baz', 'mux', 'qux', 'quux', 'quuux', 'quuuux', 'quuuuux', 'quuuuuux', 'quuuuuuux', lambda a, b: 37,] """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ FOO = [ 'bar', 'baz', @@ -1318,7 +1439,8 @@ def testSplitListWithTerminatingComma(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplitListWithInterspersedComments(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ FOO = [ 'bar', # bar 'baz', # baz @@ -1337,7 +1459,7 @@ def testSplitListWithInterspersedComments(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testRelativeImportStatements(self): - code = textwrap.dedent("""\ + code = textwrap.dedent("""\ from ... import bork """) llines = yapf_test_helper.ParseAndUnwrap(code) @@ -1345,13 +1467,15 @@ def testRelativeImportStatements(self): def testSingleLineList(self): # A list on a single line should prefer to remain contiguous. - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = aaaaaaaaaaa( ("...", "."), "..", ".............................................." ) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = aaaaaaaaaaa( ("...", "."), "..", "..............................................") """) # noqa @@ -1359,7 +1483,8 @@ def testSingleLineList(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBlankLinesBeforeFunctionsNotInColumnZero(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ import signal @@ -1374,7 +1499,8 @@ def timeout(seconds=1): except: pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ import signal try: @@ -1393,7 +1519,8 @@ def timeout(seconds=1): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoKeywordArgumentBreakage(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class A(object): def b(self): @@ -1405,7 +1532,7 @@ def b(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testTrailerOnSingleLine(self): - code = """\ + code = """\ urlpatterns = patterns('', url(r'^$', 'homepage_view'), url(r'^/login/$', 'login_view'), url(r'^/login/$', 'logout_view'), @@ -1415,7 +1542,8 @@ def testTrailerOnSingleLine(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testIfConditionalParens(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class Foo: def bar(): @@ -1428,7 +1556,8 @@ def bar(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testContinuationMarkers(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. "\\ "Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur "\\ "ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis "\\ @@ -1438,14 +1567,16 @@ def testContinuationMarkers(self): llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ from __future__ import nested_scopes, generators, division, absolute_import, with_statement, \\ print_function, unicode_literals """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ if aaaaaaaaa == 42 and bbbbbbbbbbbbbb == 42 and \\ cccccccc == 42: pass @@ -1454,7 +1585,8 @@ def testContinuationMarkers(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentsWithContinuationMarkers(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def fn(arg): v = fn2(key1=True, #c1 @@ -1465,7 +1597,8 @@ def fn(arg): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testMultipleContinuationMarkers(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ xyz = \\ \\ some_thing() @@ -1474,7 +1607,7 @@ def testMultipleContinuationMarkers(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testContinuationMarkerAfterStringWithContinuation(self): - code = """\ + code = """\ s = 'foo \\ bar' \\ .format() @@ -1483,7 +1616,8 @@ def testContinuationMarkerAfterStringWithContinuation(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testEmptyContainers(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ flags.DEFINE_list( 'output_dirs', [], 'Lorem ipsum dolor sit amet, consetetur adipiscing elit. Donec a diam lectus. ' @@ -1493,10 +1627,12 @@ def testEmptyContainers(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testSplitStringsIfSurroundedByParens(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ a = foo.bar({'xxxxxxxxxxxxxxxxxxxxxxx' 'yyyyyyyyyyyyyyyyyyyyyyyyyy': baz[42]} + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbb' 'cccccccccccccccccccccccccccccccc' 'ddddddddddddddddddddddddddddd') """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ a = foo.bar({'xxxxxxxxxxxxxxxxxxxxxxx' 'yyyyyyyyyyyyyyyyyyyyyyyyyy': baz[42]} + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' @@ -1507,7 +1643,8 @@ def testSplitStringsIfSurroundedByParens(self): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ a = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' \ 'bbbbbbbbbbbbbbbbbbbbbbbbbb' 'cccccccccccccccccccccccccccccccc' \ 'ddddddddddddddddddddddddddddd' @@ -1516,7 +1653,8 @@ def testSplitStringsIfSurroundedByParens(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testMultilineShebang(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ #!/bin/sh if "true" : '''\' then @@ -1536,7 +1674,8 @@ def testMultilineShebang(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSplittingAroundTermOperators(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ a_very_long_function_call_yada_yada_etc_etc_etc(long_arg1, long_arg2 / long_arg3) """) @@ -1544,7 +1683,8 @@ def testNoSplittingAroundTermOperators(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSplittingAroundCompOperators(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa is not bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa in bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa not in bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) @@ -1552,7 +1692,8 @@ def testNoSplittingAroundCompOperators(self): c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa is bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa <= bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) """) # noqa - expected_code = textwrap.dedent("""\ + expected_code = textwrap.dedent( + """\ c = ( aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa is not bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) @@ -1574,7 +1715,8 @@ def testNoSplittingAroundCompOperators(self): self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testNoSplittingWithinSubscriptList(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ somequitelongvariablename.somemember[(a, b)] = { 'somelongkey': 1, 'someotherlongkey': 2 @@ -1584,7 +1726,8 @@ def testNoSplittingWithinSubscriptList(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testExcessCharacters(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class foo: def bar(self): @@ -1595,14 +1738,16 @@ def bar(self): llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def _(): if True: if True: if contract == allow_contract and attr_dict.get(if_attribute) == has_value: return True """) # noqa - expected_code = textwrap.dedent("""\ + expected_code = textwrap.dedent( + """\ def _(): if True: if True: @@ -1614,7 +1759,8 @@ def _(): self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testDictSetGenerator(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ foo = { variable: 'hello world. How are you today?' for variable in fnord @@ -1625,7 +1771,8 @@ def testDictSetGenerator(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testUnaryOpInDictionaryValue(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ beta = "123" test = {'alpha': beta[-1]} @@ -1636,7 +1783,8 @@ def testUnaryOpInDictionaryValue(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testUnaryNotOperator(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ if True: if True: if True: @@ -1648,7 +1796,7 @@ def testUnaryNotOperator(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testRelaxArraySubscriptAffinity(self): - code = """\ + code = """\ class A(object): def f(self, aaaaaaaaa, bbbbbbbbbbbbb, row): @@ -1664,17 +1812,18 @@ def f(self, aaaaaaaaa, bbbbbbbbbbbbb, row): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionCallInDict(self): - code = "a = {'a': b(c=d, **e)}\n" + code = "a = {'a': b(c=d, **e)}\n" llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionCallInNestedDict(self): - code = "a = {'a': {'a': {'a': b(c=d, **e)}}}\n" + code = "a = {'a': {'a': {'a': b(c=d, **e)}}}\n" llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testUnbreakableNot(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def test(): if not "Foooooooooooooooooooooooooooooo" or "Foooooooooooooooooooooooooooooo" == "Foooooooooooooooooooooooooooooo": pass @@ -1683,7 +1832,8 @@ def test(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testSplitListWithComment(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ a = [ 'a', 'b', @@ -1694,7 +1844,8 @@ def testSplitListWithComment(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testOverColumnLimit(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class Test: def testSomething(self): @@ -1704,7 +1855,8 @@ def testSomething(self): ('aaaaaaaaaaaaa', 'bbbb'): 'ccccccccccccccccccccccccccccccccccccccccccc', } """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class Test: def testSomething(self): @@ -1721,7 +1873,8 @@ def testSomething(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testEndingComment(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ a = f( a="something", b="something requiring comment which is quite long", # comment about b (pushes line over 79) @@ -1731,7 +1884,8 @@ def testEndingComment(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testContinuationSpaceRetention(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def fn(): return module \\ .method(Object(data, @@ -1742,7 +1896,8 @@ def fn(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testIfExpressionWithFunctionCall(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ if x or z.y( a, c, @@ -1754,7 +1909,8 @@ def testIfExpressionWithFunctionCall(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testUnformattedAfterMultilineString(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def foo(): com_text = \\ ''' @@ -1765,7 +1921,8 @@ def foo(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSpacesAroundKeywordDefaultValues(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ sources = { 'json': request.get_json(silent=True) or {}, 'json2': request.get_json(silent=True), @@ -1776,12 +1933,14 @@ def testNoSpacesAroundKeywordDefaultValues(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSplittingBeforeEndingSubscriptBracket(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if True: if True: status = cf.describe_stacks(StackName=stackname)[u'Stacks'][0][u'StackStatus'] """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if True: if True: status = cf.describe_stacks( @@ -1791,7 +1950,8 @@ def testNoSplittingBeforeEndingSubscriptBracket(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoSplittingOnSingleArgument(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ xxxxxxxxxxxxxx = (re.search(r'(\\d+\\.\\d+\\.\\d+\\.)\\d+', aaaaaaa.bbbbbbbbbbbb).group(1) + re.search(r'\\d+\\.\\d+\\.\\d+\\.(\\d+)', @@ -1801,7 +1961,8 @@ def testNoSplittingOnSingleArgument(self): re.search(r'\\d+\\.\\d+\\.\\d+\\.(\\d+)', ccccccc).group(c.d)) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ xxxxxxxxxxxxxx = ( re.search(r'(\\d+\\.\\d+\\.\\d+\\.)\\d+', aaaaaaa.bbbbbbbbbbbb).group(1) + re.search(r'\\d+\\.\\d+\\.\\d+\\.(\\d+)', ccccccc).group(1)) @@ -1813,13 +1974,15 @@ def testNoSplittingOnSingleArgument(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingArraysSensibly(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ while True: while True: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list['bbbbbbbbbbbbbbbbbbbbbbbbb'].split(',') aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list('bbbbbbbbbbbbbbbbbbbbbbbbb').split(',') """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ while True: while True: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list[ @@ -1831,13 +1994,15 @@ def testSplittingArraysSensibly(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testComprehensionForAndIf(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class f: def __repr__(self): tokens_repr = ','.join(['{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens]) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class f: def __repr__(self): @@ -1848,7 +2013,8 @@ def __repr__(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testFunctionCallArguments(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def f(): if True: pytree_utils.InsertNodesBefore(_CreateCommentsFromPrefix( @@ -1858,7 +2024,8 @@ def f(): comment_prefix, comment_lineno, comment_column, standalone=True)) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def f(): if True: pytree_utils.InsertNodesBefore( @@ -1873,18 +2040,21 @@ def f(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBinaryOperators(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ a = b ** 37 c = (20 ** -3) / (_GRID_ROWS ** (code_length - 10)) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ a = b**37 c = (20**-3) / (_GRID_ROWS**(code_length - 10)) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def f(): if True: if (self.stack[-1].split_before_closing_bracket and @@ -1897,7 +2067,8 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testContiguousList(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ [retval1, retval2] = a_very_long_function(argument_1, argument2, argument_3, argument_4) """) # noqa @@ -1905,7 +2076,8 @@ def testContiguousList(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testArgsAndKwargsFormatting(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ a(a=aaaaaaaaaaaaaaaaaaaaa, b=aaaaaaaaaaaaaaaaaaaaaaaa, c=aaaaaaaaaaaaaaaaaa, @@ -1915,7 +2087,8 @@ def testArgsAndKwargsFormatting(self): llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def foo(): return [ Bar(xxx='some string', @@ -1927,7 +2100,8 @@ def foo(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentColumnLimitOverflow(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def f(): if True: TaskManager.get_tags = MagicMock( @@ -1940,7 +2114,8 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testMultilineLambdas(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class SomeClass(object): do_something = True @@ -1951,7 +2126,8 @@ def succeeded(self, dddddddddddddd): d.addCallback(lambda _: self.aaaaaa.bbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccccccc(dddddddddddddd)) return d """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class SomeClass(object): do_something = True @@ -1969,13 +2145,14 @@ def succeeded(self, dddddddddddddd): style.CreateStyleFromConfig( '{based_on_style: yapf, allow_multiline_lambdas: true}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testMultilineDictionaryKeys(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ MAP_WITH_LONG_KEYS = { ('lorem ipsum', 'dolor sit amet'): 1, @@ -1985,7 +2162,8 @@ def testMultilineDictionaryKeys(self): 3 } """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ MAP_WITH_LONG_KEYS = { ('lorem ipsum', 'dolor sit amet'): 1, @@ -1999,16 +2177,18 @@ def testMultilineDictionaryKeys(self): try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: yapf, ' - 'allow_multiline_dictionary_keys: true}')) + style.CreateStyleFromConfig( + '{based_on_style: yapf, ' + 'allow_multiline_dictionary_keys: true}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testStableDictionaryFormatting(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class A(object): def method(self): @@ -2025,15 +2205,16 @@ def method(self): try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: pep8, indent_width: 2, ' - 'continuation_indent_width: 4, ' - 'indent_dictionary_value: True}')) + style.CreateStyleFromConfig( + '{based_on_style: pep8, indent_width: 2, ' + 'continuation_indent_width: 4, ' + 'indent_dictionary_value: True}')) - llines = yapf_test_helper.ParseAndUnwrap(code) + llines = yapf_test_helper.ParseAndUnwrap(code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, reformatted_code) - llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, reformatted_code) finally: @@ -2042,12 +2223,14 @@ def method(self): def testStableInlinedDictionaryFormatting(self): try: style.SetGlobalStyle(style.CreatePEP8Style()) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def _(): url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( value, urllib.urlencode({'action': 'update', 'parameter': value})) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def _(): url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( value, urllib.urlencode({ @@ -2056,23 +2239,25 @@ def _(): })) """) - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) - llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testDontSplitKeywordValueArguments(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def mark_game_scored(gid): _connect.execute(_games.update().where(_games.c.gid == gid).values( scored=True)) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def mark_game_scored(gid): _connect.execute( _games.update().where(_games.c.gid == gid).values(scored=True)) @@ -2081,7 +2266,8 @@ def mark_game_scored(gid): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDontAddBlankLineAfterMultilineString(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ query = '''SELECT id FROM table WHERE day in {}''' @@ -2091,7 +2277,8 @@ def testDontAddBlankLineAfterMultilineString(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFormattingListComprehensions(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def a(): if True: if True: @@ -2105,7 +2292,8 @@ def a(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSplittingWhenBinPacking(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ a_very_long_function_name( long_argument_name_1=1, long_argument_name_2=2, @@ -2127,23 +2315,25 @@ def testNoSplittingWhenBinPacking(self): 'dedent_closing_brackets: True, ' 'split_before_named_assigns: False}')) - llines = yapf_test_helper.ParseAndUnwrap(code) + llines = yapf_test_helper.ParseAndUnwrap(code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, reformatted_code) - llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, reformatted_code) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testNotSplittingAfterSubscript(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if not aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.b(c == d[ 'eeeeee']).ffffff(): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if not aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.b( c == d['eeeeee']).ffffff(): pass @@ -2152,7 +2342,8 @@ def testNotSplittingAfterSubscript(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingOneArgumentList(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def _(): if True: if True: @@ -2161,7 +2352,8 @@ def _(): if True: boxes[id_] = np.concatenate((points.min(axis=0), qoints.max(axis=0))) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def _(): if True: if True: @@ -2175,7 +2367,8 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingBeforeFirstElementListArgument(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class _(): @classmethod def _pack_results_for_constraint_or(cls, combination, constraints): @@ -2188,7 +2381,8 @@ def _pack_results_for_constraint_or(cls, combination, constraints): ), constraints, InvestigationResult.OR ) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class _(): @classmethod @@ -2204,7 +2398,8 @@ def _pack_results_for_constraint_or(cls, combination, constraints): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingArgumentsTerminatedByComma(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3) function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3,) @@ -2215,7 +2410,8 @@ def testSplittingArgumentsTerminatedByComma(self): r =f0 (1, 2,3,) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3) function_name( @@ -2250,18 +2446,19 @@ def testSplittingArgumentsTerminatedByComma(self): '{based_on_style: yapf, ' 'split_arguments_when_comma_terminated: True}')) - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) - llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testImportAsList(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ from toto import titi, tata, tutu # noqa from toto import titi, tata, tutu from toto import (titi, tata, tutu) @@ -2270,7 +2467,8 @@ def testImportAsList(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDictionaryValuesOnOwnLines(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ a = { 'aaaaaaaaaaaaaaaaaaaaaaaa': Check('ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ', '=', True), @@ -2294,7 +2492,8 @@ def testDictionaryValuesOnOwnLines(self): Check('QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ', '=', False), } """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ a = { 'aaaaaaaaaaaaaaaaaaaaaaaa': Check('ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ', '=', True), @@ -2322,27 +2521,31 @@ def testDictionaryValuesOnOwnLines(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDictionaryOnOwnLine(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ doc = test_utils.CreateTestDocumentViaController( content={ 'a': 'b' }, branch_key=branch.key, collection_key=collection.key) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ doc = test_utils.CreateTestDocumentViaController( content={'a': 'b'}, branch_key=branch.key, collection_key=collection.key) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ doc = test_utils.CreateTestDocumentViaController( content={ 'a': 'b' }, branch_key=branch.key, collection_key=collection.key, collection_key2=collection.key2) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ doc = test_utils.CreateTestDocumentViaController( content={'a': 'b'}, branch_key=branch.key, @@ -2353,7 +2556,8 @@ def testDictionaryOnOwnLine(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNestedListsInDictionary(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ _A = { 'cccccccccc': ('^^1',), 'rrrrrrrrrrrrrrrrrrrrrrrrr': ('^7913', # AAAAAAAAAAAAAA. @@ -2382,7 +2586,8 @@ def testNestedListsInDictionary(self): ), } """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ _A = { 'cccccccccc': ('^^1',), 'rrrrrrrrrrrrrrrrrrrrrrrrr': ( @@ -2420,7 +2625,8 @@ def testNestedListsInDictionary(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNestedDictionary(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class _(): def _(): breadcrumbs = [{'name': 'Admin', @@ -2430,7 +2636,8 @@ def _(): 'url': url_for(".home")}, {'title': title}] """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class _(): def _(): breadcrumbs = [ @@ -2448,7 +2655,8 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDictionaryElementsOnOneLine(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class _(): @mock.patch.dict( @@ -2468,10 +2676,12 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNotInParams(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ list("a long line to break the line. a long line to break the brk a long lin", not True) """) # noqa - expected_code = textwrap.dedent("""\ + expected_code = textwrap.dedent( + """\ list("a long line to break the line. a long line to break the brk a long lin", not True) """) # noqa @@ -2479,14 +2689,16 @@ def testNotInParams(self): self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testNamedAssignNotAtEndOfLine(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def _(): if True: with py3compat.open_with_encoding(filename, mode='w', encoding=encoding) as fd: pass """) - expected_code = textwrap.dedent("""\ + expected_code = textwrap.dedent( + """\ def _(): if True: with py3compat.open_with_encoding( @@ -2497,7 +2709,8 @@ def _(): self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testBlankLineBeforeClassDocstring(self): - unformatted_code = textwrap.dedent('''\ + unformatted_code = textwrap.dedent( + '''\ class A: """Does something. @@ -2508,7 +2721,8 @@ class A: def __init__(self): pass ''') - expected_code = textwrap.dedent('''\ + expected_code = textwrap.dedent( + '''\ class A: """Does something. @@ -2521,7 +2735,8 @@ def __init__(self): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent('''\ + unformatted_code = textwrap.dedent( + '''\ class A: """Does something. @@ -2532,7 +2747,8 @@ class A: def __init__(self): pass ''') - expected_formatted_code = textwrap.dedent('''\ + expected_formatted_code = textwrap.dedent( + '''\ class A: """Does something. @@ -2551,13 +2767,14 @@ def __init__(self): 'blank_line_before_class_docstring: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testBlankLineBeforeModuleDocstring(self): - unformatted_code = textwrap.dedent('''\ + unformatted_code = textwrap.dedent( + '''\ #!/usr/bin/env python # -*- coding: utf-8 name> -*- @@ -2567,7 +2784,8 @@ def testBlankLineBeforeModuleDocstring(self): def foobar(): pass ''') - expected_code = textwrap.dedent('''\ + expected_code = textwrap.dedent( + '''\ #!/usr/bin/env python # -*- coding: utf-8 name> -*- """Some module docstring.""" @@ -2579,7 +2797,8 @@ def foobar(): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent('''\ + unformatted_code = textwrap.dedent( + '''\ #!/usr/bin/env python # -*- coding: utf-8 name> -*- """Some module docstring.""" @@ -2588,7 +2807,8 @@ def foobar(): def foobar(): pass ''') - expected_formatted_code = textwrap.dedent('''\ + expected_formatted_code = textwrap.dedent( + '''\ #!/usr/bin/env python # -*- coding: utf-8 name> -*- @@ -2606,18 +2826,20 @@ def foobar(): 'blank_line_before_module_docstring: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testTupleCohesion(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def f(): this_is_a_very_long_function_name(an_extremely_long_variable_name, ( 'a string that may be too long %s' % 'M15')) """) - expected_code = textwrap.dedent("""\ + expected_code = textwrap.dedent( + """\ def f(): this_is_a_very_long_function_name( an_extremely_long_variable_name, @@ -2627,14 +2849,15 @@ def f(): self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testSubscriptExpression(self): - code = textwrap.dedent("""\ + code = textwrap.dedent("""\ foo = d[not a] """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testListWithFunctionCalls(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo(): return [ Bar( @@ -2646,7 +2869,8 @@ def foo(): zzz='a third long string') ] """) - expected_code = textwrap.dedent("""\ + expected_code = textwrap.dedent( + """\ def foo(): return [ Bar(xxx='some string', @@ -2661,11 +2885,13 @@ def foo(): self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testEllipses(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ X=... Y = X if ... else X """) - expected_code = textwrap.dedent("""\ + expected_code = textwrap.dedent( + """\ X = ... Y = X if ... else X """) @@ -2679,7 +2905,7 @@ def testPseudoParens(self): {'nested_key': 1, }, } """ - expected_code = """\ + expected_code = """\ my_dict = { 'key': # Some comment about the key { @@ -2687,16 +2913,18 @@ def testPseudoParens(self): }, } """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testSplittingBeforeFirstArgumentOnFunctionCall(self): """Tests split_before_first_argument on a function call.""" - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ a_very_long_function_name("long string with formatting {0:s}".format( "mystring")) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ a_very_long_function_name( "long string with formatting {0:s}".format("mystring")) """) @@ -2707,19 +2935,21 @@ def testSplittingBeforeFirstArgumentOnFunctionCall(self): '{based_on_style: yapf, split_before_first_argument: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testSplittingBeforeFirstArgumentOnFunctionDefinition(self): """Tests split_before_first_argument on a function definition.""" - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def _GetNumberOfSecondsFromElements(year, month, day, hours, minutes, seconds, microseconds): return """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def _GetNumberOfSecondsFromElements( year, month, day, hours, minutes, seconds, microseconds): return @@ -2731,21 +2961,23 @@ def _GetNumberOfSecondsFromElements( '{based_on_style: yapf, split_before_first_argument: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testSplittingBeforeFirstArgumentOnCompoundStatement(self): """Tests split_before_first_argument on a compound statement.""" - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if (long_argument_name_1 == 1 or long_argument_name_2 == 2 or long_argument_name_3 == 3 or long_argument_name_4 == 4): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if (long_argument_name_1 == 1 or long_argument_name_2 == 2 or long_argument_name_3 == 3 or long_argument_name_4 == 4): pass @@ -2757,14 +2989,15 @@ def testSplittingBeforeFirstArgumentOnCompoundStatement(self): '{based_on_style: yapf, split_before_first_argument: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testCoalesceBracketsOnDict(self): """Tests coalesce_brackets on a dictionary.""" - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ date_time_values = ( { u'year': year, @@ -2776,7 +3009,8 @@ def testCoalesceBracketsOnDict(self): } ) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ date_time_values = ({ u'year': year, u'month': month, @@ -2793,13 +3027,14 @@ def testCoalesceBracketsOnDict(self): '{based_on_style: yapf, coalesce_brackets: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testSplitAfterComment(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ if __name__ == "__main__": with another_resource: account = { @@ -2824,7 +3059,8 @@ def testAsyncAsNonKeyword(self): style.SetGlobalStyle(style.CreatePEP8Style()) # In Python 2, async may be used as a non-keyword identifier. - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ from util import async @@ -2846,8 +3082,9 @@ def testDisableEndingCommaHeuristic(self): try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: yapf,' - ' disable_ending_comma_heuristic: True}')) + style.CreateStyleFromConfig( + '{based_on_style: yapf,' + ' disable_ending_comma_heuristic: True}')) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -2855,7 +3092,8 @@ def testDisableEndingCommaHeuristic(self): style.SetGlobalStyle(style.CreateYapfStyle()) def testDedentClosingBracketsWithTypeAnnotationExceedingLineLength(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: pass @@ -2863,7 +3101,8 @@ def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: pass """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def function( first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None ) -> None: @@ -2878,17 +3117,19 @@ def function( try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: yapf,' - ' dedent_closing_brackets: True}')) + style.CreateStyleFromConfig( + '{based_on_style: yapf,' + ' dedent_closing_brackets: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testIndentClosingBracketsWithTypeAnnotationExceedingLineLength(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: pass @@ -2896,7 +3137,8 @@ def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: pass """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def function( first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None ) -> None: @@ -2911,17 +3153,19 @@ def function( try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: yapf,' - ' indent_closing_brackets: True}')) + style.CreateStyleFromConfig( + '{based_on_style: yapf,' + ' indent_closing_brackets: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testIndentClosingBracketsInFunctionCall(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None, third_and_final_argument=True): pass @@ -2929,7 +3173,8 @@ def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None, third_a def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_and_last_argument=None): pass """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def function( first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None, @@ -2946,17 +3191,19 @@ def function( try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: yapf,' - ' indent_closing_brackets: True}')) + style.CreateStyleFromConfig( + '{based_on_style: yapf,' + ' indent_closing_brackets: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testIndentClosingBracketsInTuple(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def function(): some_var = ('a long element', 'another long element', 'short element', 'really really long element') return True @@ -2965,7 +3212,8 @@ def function(): some_var = ('a couple', 'small', 'elemens') return False """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def function(): some_var = ( 'a long element', 'another long element', 'short element', @@ -2981,17 +3229,19 @@ def function(): try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: yapf,' - ' indent_closing_brackets: True}')) + style.CreateStyleFromConfig( + '{based_on_style: yapf,' + ' indent_closing_brackets: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testIndentClosingBracketsInList(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def function(): some_var = ['a long element', 'another long element', 'short element', 'really really long element'] return True @@ -3000,7 +3250,8 @@ def function(): some_var = ['a couple', 'small', 'elemens'] return False """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def function(): some_var = [ 'a long element', 'another long element', 'short element', @@ -3016,17 +3267,19 @@ def function(): try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: yapf,' - ' indent_closing_brackets: True}')) + style.CreateStyleFromConfig( + '{based_on_style: yapf,' + ' indent_closing_brackets: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testIndentClosingBracketsInDict(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def function(): some_var = {1: ('a long element', 'and another really really long element that is really really amazingly long'), 2: 'another long element', 3: 'short element', 4: 'really really long element'} return True @@ -3035,7 +3288,8 @@ def function(): some_var = {1: 'a couple', 2: 'small', 3: 'elemens'} return False """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def function(): some_var = { 1: @@ -3057,17 +3311,19 @@ def function(): try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: yapf,' - ' indent_closing_brackets: True}')) + style.CreateStyleFromConfig( + '{based_on_style: yapf,' + ' indent_closing_brackets: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testMultipleDictionariesInList(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class A: def b(): d = { @@ -3093,7 +3349,8 @@ def b(): ] } """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class A: def b(): @@ -3125,9 +3382,10 @@ def testForceMultilineDict_True(self): style.CreateStyleFromConfig('{force_multiline_dict: true}')) unformatted_code = textwrap.dedent( "responseDict = {'childDict': {'spam': 'eggs'}}\n") - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - actual = reformatter.Reformat(llines) - expected = textwrap.dedent("""\ + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + actual = reformatter.Reformat(llines) + expected = textwrap.dedent( + """\ responseDict = { 'childDict': { 'spam': 'eggs' @@ -3142,23 +3400,26 @@ def testForceMultilineDict_False(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig('{force_multiline_dict: false}')) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ responseDict = {'childDict': {'spam': 'eggs'}} """) expected_formatted_code = unformatted_code - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @unittest.skipUnless(py3compat.PY38, 'Requires Python 3.8') def testWalrus(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if (x := len([1]*1000)>100): print(f'{x} is pretty big' ) """) - expected = textwrap.dedent("""\ + expected = textwrap.dedent( + """\ if (x := len([1] * 1000) > 100): print(f'{x} is pretty big') """) @@ -3170,21 +3431,23 @@ def testAlignAssignBlankLineInbetween(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig('{align_assignment: true}')) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ val_first = 1 val_second += 2 val_third = 3 """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ val_first = 1 val_second += 2 val_third = 3 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -3194,21 +3457,23 @@ def testAlignAssignCommentLineInbetween(self): style.CreateStyleFromConfig( '{align_assignment: true,' 'new_alignment_after_commentline = true}')) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ val_first = 1 val_second += 2 # comment val_third = 3 """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ val_first = 1 val_second += 2 # comment val_third = 3 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -3216,7 +3481,8 @@ def testAlignAssignDefLineInbetween(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig('{align_assignment: true}')) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ val_first = 1 val_second += 2 def fun(): @@ -3224,7 +3490,8 @@ def fun(): abc = '' val_third = 3 """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ val_first = 1 val_second += 2 @@ -3237,8 +3504,8 @@ def fun(): val_third = 3 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -3246,7 +3513,8 @@ def testAlignAssignObjectWithNewLineInbetween(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig('{align_assignment: true}')) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ val_first = 1 val_second += 2 object = { @@ -3256,7 +3524,8 @@ def testAlignAssignObjectWithNewLineInbetween(self): } val_third = 3 """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ val_first = 1 val_second += 2 object = { @@ -3267,8 +3536,8 @@ def testAlignAssignObjectWithNewLineInbetween(self): val_third = 3 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -3276,13 +3545,13 @@ def testAlignAssignWithOnlyOneAssignmentLine(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig('{align_assignment: true}')) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ val_first = 1 """) expected_formatted_code = unformatted_code - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 54a62b588..d8beb04cb 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -29,7 +29,7 @@ def setUpClass(cls): style.SetGlobalStyle(style.CreateYapfStyle()) def testB137580392(self): - code = """\ + code = """\ def _create_testing_simulator_and_sink( ) -> Tuple[_batch_simulator:_batch_simulator.BatchSimulator, _batch_simulator.SimulationSink]: @@ -39,7 +39,7 @@ def _create_testing_simulator_and_sink( self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB73279849(self): - unformatted_code = """\ + unformatted_code = """\ class A: def _(a): return 'hello' [ a ] @@ -49,11 +49,11 @@ class A: def _(a): return 'hello'[a] """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB122455211(self): - unformatted_code = """\ + unformatted_code = """\ _zzzzzzzzzzzzzzzzzzzz = Union[sssssssssssssssssssss.pppppppppppppppp, sssssssssssssssssssss.pppppppppppppppppppppppppppp] """ @@ -62,11 +62,11 @@ def testB122455211(self): sssssssssssssssssssss.pppppppppppppppp, sssssssssssssssssssss.pppppppppppppppppppppppppppp] """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB119300344(self): - code = """\ + code = """\ def _GenerateStatsEntries( process_id: Text, timestamp: Optional[rdfvalue.RDFDatetime] = None @@ -77,7 +77,7 @@ def _GenerateStatsEntries( self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB132886019(self): - code = """\ + code = """\ X = { 'some_dict_key': frozenset([ @@ -90,7 +90,7 @@ def testB132886019(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB26521719(self): - code = """\ + code = """\ class _(): def _(self): @@ -101,7 +101,7 @@ def _(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB122541552(self): - code = """\ + code = """\ # pylint: disable=g-explicit-bool-comparison,singleton-comparison _QUERY = account.Account.query(account.Account.enabled == True) # pylint: enable=g-explicit-bool-comparison,singleton-comparison @@ -114,7 +114,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB124415889(self): - code = """\ + code = """\ class _(): def run_queue_scanners(): @@ -137,7 +137,7 @@ def modules_to_install(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB73166511(self): - code = """\ + code = """\ def _(): if min_std is not None: groundtruth_age_variances = tf.maximum(groundtruth_age_variances, @@ -147,7 +147,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB118624921(self): - code = """\ + code = """\ def _(): function_call( alert_name='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', @@ -160,7 +160,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB35417079(self): - code = """\ + code = """\ class _(): def _(): @@ -175,7 +175,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB120047670(self): - unformatted_code = """\ + unformatted_code = """\ X = { 'NO_PING_COMPONENTS': [ 79775, # Releases / FOO API @@ -195,11 +195,11 @@ def testB120047670(self): 'PING_BLOCKED_BUGS': False, } """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB120245013(self): - unformatted_code = """\ + unformatted_code = """\ class Foo(object): def testNoAlertForShortPeriod(self, rutabaga): self.targets[:][streamz_path,self._fillInOtherFields(streamz_path, {streamz_field_of_interest:True})] = series.Counter('1s', '+ 500x10000') @@ -213,11 +213,11 @@ def testNoAlertForShortPeriod(self, rutabaga): self._fillInOtherFields(streamz_path, {streamz_field_of_interest: True} )] = series.Counter('1s', '+ 500x10000') """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB117841880(self): - code = """\ + code = """\ def xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( aaaaaaaaaaaaaaaaaaa: AnyStr, bbbbbbbbbbbb: Optional[Sequence[AnyStr]] = None, @@ -234,7 +234,7 @@ def xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB111764402(self): - unformatted_code = """\ + unformatted_code = """\ x = self.stubs.stub(video_classification_map, 'read_video_classifications', (lambda external_ids, **unused_kwargs: {external_id: self._get_serving_classification('video') for external_id in external_ids})) """ # noqa expected_formatted_code = """\ @@ -244,11 +244,11 @@ def testB111764402(self): for external_id in external_ids })) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB116825060(self): - code = """\ + code = """\ result_df = pd.DataFrame({LEARNED_CTR_COLUMN: learned_ctr}, index=df_metrics.index) """ @@ -256,7 +256,7 @@ def testB116825060(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB112711217(self): - code = """\ + code = """\ def _(): stats['moderated'] = ~stats.moderation_reason.isin( approved_moderation_reasons) @@ -265,7 +265,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB112867548(self): - unformatted_code = """\ + unformatted_code = """\ def _(): return flask.make_response( 'Records: {}, Problems: {}, More: {}'.format( @@ -283,11 +283,11 @@ def _(): httplib.ACCEPTED if process_result.has_more else httplib.OK, {'content-type': _TEXT_CONTEXT_TYPE}) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB112651423(self): - unformatted_code = """\ + unformatted_code = """\ def potato(feeditems, browse_use_case=None): for item in turnip: if kumquat: @@ -302,11 +302,11 @@ def potato(feeditems, browse_use_case=None): 'FEEDS_LOAD_PLAYLIST_VIDEOS_FOR_ALL_ITEMS'] and item.video: continue """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB80484938(self): - code = """\ + code = """\ for sssssss, aaaaaaaaaa in [ ('ssssssssssssssssssss', 'sssssssssssssssssssssssss'), ('nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn', @@ -349,7 +349,7 @@ def testB80484938(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB120771563(self): - code = """\ + code = """\ class A: def b(): @@ -376,7 +376,7 @@ def b(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB79462249(self): - code = """\ + code = """\ foo.bar(baz, [ quux(thud=42), norf, @@ -398,7 +398,7 @@ def testB79462249(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB113210278(self): - unformatted_code = """\ + unformatted_code = """\ def _(): aaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccc(\ eeeeeeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffffffffffffffffffffff.\ @@ -410,11 +410,11 @@ def _(): eeeeeeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffffffffffffffffffffff .ggggggggggggggggggggggggggggggggg.hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh()) """ # noqa - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB77923341(self): - code = """\ + code = """\ def f(): if (aaaaaaaaaaaaaa.bbbbbbbbbbbb.ccccc <= 0 and # pytype: disable=attribute-error ddddddddddd.eeeeeeeee == constants.FFFFFFFFFFFFFF): @@ -424,7 +424,7 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB77329955(self): - code = """\ + code = """\ class _(): @parameterized.named_parameters( @@ -442,7 +442,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB65197969(self): - unformatted_code = """\ + unformatted_code = """\ class _(): def _(): @@ -457,11 +457,11 @@ def _(): seconds=max(float(time_scale), small_interval) * 1.41**min(num_attempts, 9)) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB65546221(self): - unformatted_code = """\ + unformatted_code = """\ SUPPORTED_PLATFORMS = ( "centos-6", "centos-7", @@ -484,11 +484,11 @@ def testB65546221(self): "debian-9-stretch", ) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30500455(self): - unformatted_code = """\ + unformatted_code = """\ INITIAL_SYMTAB = dict([(name, 'exception#' + name) for name in INITIAL_EXCEPTIONS ] * [(name, 'type#' + name) for name in INITIAL_TYPES] + [ (name, 'function#' + name) for name in INITIAL_FUNCTIONS @@ -501,11 +501,11 @@ def testB30500455(self): [(name, 'function#' + name) for name in INITIAL_FUNCTIONS] + [(name, 'const#' + name) for name in INITIAL_CONSTS]) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB38343525(self): - code = """\ + code = """\ # This does foo. @arg.String('some_path_to_a_file', required=True) # This does bar. @@ -517,7 +517,7 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB37099651(self): - unformatted_code = """\ + unformatted_code = """\ _MEMCACHE = lazy.MakeLazy( # pylint: disable=g-long-lambda lambda: function.call.mem.clients(FLAGS.some_flag_thingy, default_namespace=_LAZY_MEM_NAMESPACE, allow_pickle=True) @@ -534,11 +534,11 @@ def testB37099651(self): # pylint: enable=g-long-lambda ) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB33228502(self): - unformatted_code = """\ + unformatted_code = """\ def _(): success_rate_stream_table = module.Precompute( query_function=module.DefineQueryFunction( @@ -572,11 +572,11 @@ def _(): | m.Join('successes', 'total') | m.Point(m.VAL['successes'] / m.VAL['total'])))) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30394228(self): - code = """\ + code = """\ class _(): def _(self): @@ -589,7 +589,7 @@ def _(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB65246454(self): - unformatted_code = """\ + unformatted_code = """\ class _(): def _(self): @@ -605,11 +605,11 @@ def _(self): self.assertEqual({i.id for i in successful_instances}, {i.id for i in self._statuses.successful_instances}) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB67935450(self): - unformatted_code = """\ + unformatted_code = """\ def _(): return ( (Gauge( @@ -646,11 +646,11 @@ def _(): m.Cond(m.VAL['start'] != 0, m.VAL['start'], m.TimestampMicros() / 1000000L))) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB66011084(self): - unformatted_code = """\ + unformatted_code = """\ X = { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": # Comment 1. ([] if True else [ # Comment 2. @@ -678,22 +678,22 @@ def testB66011084(self): ]), } """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB67455376(self): - unformatted_code = """\ + unformatted_code = """\ sponge_ids.extend(invocation.id() for invocation in self._client.GetInvocationsByLabels(labels)) """ # noqa expected_formatted_code = """\ sponge_ids.extend(invocation.id() for invocation in self._client.GetInvocationsByLabels(labels)) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB35210351(self): - unformatted_code = """\ + unformatted_code = """\ def _(): config.AnotherRuleThing( 'the_title_to_the_thing_here', @@ -719,11 +719,11 @@ def _(): GetTheAlertToIt('the_title_to_the_thing_here'), GetNotificationTemplate('your_email_here'))) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB34774905(self): - unformatted_code = """\ + unformatted_code = """\ x=[VarExprType(ir_name=IrName( value='x', expr_type=UnresolvedAttrExprType( atom=UnknownExprType(), attr_name=IrName( value='x', expr_type=UnknownExprType(), usage='UNKNOWN', fqn=None, @@ -748,18 +748,18 @@ def testB34774905(self): astn=None)) ] """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB65176185(self): - code = """\ + code = """\ xx = zip(*[(a, b) for (a, b, c) in yy]) """ llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB35210166(self): - unformatted_code = """\ + unformatted_code = """\ def _(): query = ( m.Fetch(n.Raw('monarch.BorgTask', '/proc/container/memory/usage'), { 'borg_user': borguser, 'borg_job': jobname }) @@ -776,11 +776,11 @@ def _(): | o.Window(m.Align('5m')) | p.GroupBy(['borg_user', 'borg_job', 'borg_cell'], q.Mean())) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB32167774(self): - unformatted_code = """\ + unformatted_code = """\ X = ( 'is_official', 'is_cover', @@ -803,11 +803,11 @@ def testB32167774(self): 'is_compilation', ) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB66912275(self): - unformatted_code = """\ + unformatted_code = """\ def _(): with self.assertRaisesRegexp(errors.HttpError, 'Invalid'): patch_op = api_client.forwardingRules().patch( @@ -827,11 +827,11 @@ def _(): 'fingerprint': base64.urlsafe_b64encode('invalid_fingerprint') }).execute() """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB67312284(self): - code = """\ + code = """\ def _(): self.assertEqual( [u'to be published 2', u'to be published 1', u'to be published 0'], @@ -841,7 +841,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB65241516(self): - unformatted_code = """\ + unformatted_code = """\ checkpoint_files = gfile.Glob(os.path.join(TrainTraceDir(unit_key, "*", "*"), embedding_model.CHECKPOINT_FILENAME + "-*")) """ # noqa expected_formatted_code = """\ @@ -850,11 +850,12 @@ def testB65241516(self): TrainTraceDir(unit_key, "*", "*"), embedding_model.CHECKPOINT_FILENAME + "-*")) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB37460004(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ assert all(s not in (_SENTINEL, None) for s in nested_schemas ), 'Nested schemas should never contain None/_SENTINEL' """) @@ -862,7 +863,7 @@ def testB37460004(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB36806207(self): - code = """\ + code = """\ def _(): linearity_data = [[row] for row in [ "%.1f mm" % (np.mean(linearity_values["pos_error"]) * 1000.0), @@ -881,7 +882,8 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB36215507(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class X(): def _(): @@ -895,7 +897,8 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB35212469(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def _(): X = { 'retain': { @@ -904,7 +907,8 @@ def _(): } } """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def _(): X = { 'retain': { @@ -917,12 +921,14 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB31063453(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def _(): while ((not mpede_proc) or ((time_time() - last_modified) < FLAGS_boot_idle_timeout)): pass """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def _(): while ((not mpede_proc) or ((time_time() - last_modified) < FLAGS_boot_idle_timeout)): @@ -932,7 +938,8 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB35021894(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def _(): labelacl = Env(qa={ 'read': 'name/some-type-of-very-long-name-for-reading-perms', @@ -943,7 +950,8 @@ def _(): 'modify': 'name/some-other-type-of-very-long-name-for-modifying' }) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def _(): labelacl = Env( qa={ @@ -959,10 +967,12 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB34682902(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ logging.info("Mean angular velocity norm: %.3f", np.linalg.norm(np.mean(ang_vel_arr, axis=0))) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ logging.info("Mean angular velocity norm: %.3f", np.linalg.norm(np.mean(ang_vel_arr, axis=0))) """) @@ -970,13 +980,15 @@ def testB34682902(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB33842726(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class _(): def _(): hints.append(('hg tag -f -l -r %s %s # %s' % (short(ctx.node( )), candidatetag, firstline))[:78]) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class _(): def _(): hints.append(('hg tag -f -l -r %s %s # %s' % @@ -986,7 +998,8 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB32931780(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ environments = { 'prod': { # this is a comment before the first entry. @@ -1017,7 +1030,8 @@ def testB32931780(self): } } """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ environments = { 'prod': { # this is a comment before the first entry. @@ -1048,7 +1062,8 @@ def testB32931780(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB33047408(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def _(): for sort in (sorts or []): request['sorts'].append({ @@ -1062,7 +1077,8 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB32714745(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class _(): def _BlankDefinition(): @@ -1092,14 +1108,16 @@ def _BlankDefinition(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB32737279(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ here_is_a_dict = { 'key': # Comment. 'value' } """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ here_is_a_dict = { 'key': # Comment. 'value' @@ -1109,7 +1127,8 @@ def testB32737279(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB32570937(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def _(): if (job_message.ball not in ('*', ball) or job_message.call not in ('*', call) or @@ -1120,7 +1139,8 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB31937033(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class _(): def __init__(self, metric, fields_cb=None): @@ -1130,7 +1150,7 @@ def __init__(self, metric, fields_cb=None): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB31911533(self): - code = """\ + code = """\ class _(): @parameterized.NamedParameters( @@ -1146,7 +1166,8 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB31847238(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class _(): def aaaaa(self, bbbbb, cccccccccccccc=None): # TODO(who): pylint: disable=unused-argument @@ -1155,7 +1176,8 @@ def aaaaa(self, bbbbb, cccccccccccccc=None): # TODO(who): pylint: disable=unuse def xxxxx(self, yyyyy, zzzzzzzzzzzzzz=None): # A normal comment that runs over the column limit. return 1 """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class _(): def aaaaa(self, bbbbb, cccccccccccccc=None): # TODO(who): pylint: disable=unused-argument @@ -1171,11 +1193,13 @@ def xxxxx( self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30760569(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ {'1234567890123456789012345678901234567890123456789012345678901234567890': '1234567890123456789012345678901234567890'} """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ { '1234567890123456789012345678901234567890123456789012345678901234567890': '1234567890123456789012345678901234567890' @@ -1185,13 +1209,15 @@ def testB30760569(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB26034238(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class Thing: def Function(self): thing.Scrape('/aaaaaaaaa/bbbbbbbbbb/ccccc/dddd/eeeeeeeeeeeeee/ffffffffffffff').AndReturn(42) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class Thing: def Function(self): @@ -1203,7 +1229,8 @@ def Function(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30536435(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def main(unused_argv): if True: if True: @@ -1212,7 +1239,8 @@ def main(unused_argv): ccccccccc.within, imports.ddddddddddddddddddd(name_item.ffffffffffffffff))) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def main(unused_argv): if True: if True: @@ -1224,12 +1252,14 @@ def main(unused_argv): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30442148(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def lulz(): return (some_long_module_name.SomeLongClassName. some_long_attribute_name.some_long_method_name()) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def lulz(): return (some_long_module_name.SomeLongClassName.some_long_attribute_name .some_long_method_name()) @@ -1238,7 +1268,8 @@ def lulz(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB26868213(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def _(): xxxxxxxxxxxxxxxxxxx = { 'ssssss': {'ddddd': 'qqqqq', @@ -1253,7 +1284,8 @@ def _(): } } """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def _(): xxxxxxxxxxxxxxxxxxx = { 'ssssss': { @@ -1274,7 +1306,8 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30173198(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class _(): def _(): @@ -1285,7 +1318,8 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB29908765(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class _(): def __repr__(self): @@ -1296,7 +1330,8 @@ def __repr__(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB30087362(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def _(): for s in sorted(env['foo']): bar() @@ -1309,7 +1344,8 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB30087363(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ if False: bar() # This is a comment @@ -1321,12 +1357,14 @@ def testB30087363(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB29093579(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def _(): _xxxxxxxxxxxxxxx(aaaaaaaa, bbbbbbbbbbbbbb.cccccccccc[ dddddddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffff]) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def _(): _xxxxxxxxxxxxxxx( aaaaaaaa, @@ -1337,7 +1375,8 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB26382315(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ @hello_world # This is a first comment @@ -1349,7 +1388,8 @@ def foo(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB27616132(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if True: query.fetch_page.assert_has_calls([ mock.call(100, @@ -1360,7 +1400,8 @@ def testB27616132(self): start_cursor=cursor_2), ]) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if True: query.fetch_page.assert_has_calls([ mock.call(100, start_cursor=None), @@ -1372,7 +1413,8 @@ def testB27616132(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB27590179(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if True: if True: self.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = ( @@ -1382,7 +1424,8 @@ def testB27590179(self): self.bbb.cccccccccc(ddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee) }) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if True: if True: self.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = ({ @@ -1396,11 +1439,13 @@ def testB27590179(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB27266946(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def _(): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = (self.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccccccccccc) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def _(): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = ( self.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb @@ -1410,7 +1455,8 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB25505359(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ _EXAMPLE = { 'aaaaaaaaaaaaaa': [{ 'bbbb': 'cccccccccccccccccccccc', @@ -1425,7 +1471,8 @@ def testB25505359(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB25324261(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ aaaaaaaaa = set(bbbb.cccc for ddd in eeeeee.fffffffffff.gggggggggggggggg for cccc in ddd.specification) @@ -1434,7 +1481,8 @@ def testB25324261(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB25136704(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class f: def test(self): @@ -1446,7 +1494,8 @@ def test(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB25165602(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def f(): ids = {u: i for u, i in zip(self.aaaaa, xrange(42, 42 + len(self.aaaaaa)))} """) # noqa @@ -1454,7 +1503,8 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB25157123(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def ListArgs(): FairlyLongMethodName([relatively_long_identifier_for_a_list], another_argument_with_a_long_identifier) @@ -1463,7 +1513,8 @@ def ListArgs(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB25136820(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo(): return collections.OrderedDict({ # Preceding comment. @@ -1471,7 +1522,8 @@ def foo(): '$bbbbbbbbbbbbbbbbbbbbbbbb', }) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo(): return collections.OrderedDict({ # Preceding comment. @@ -1483,13 +1535,15 @@ def foo(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB25131481(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ APPARENT_ACTIONS = ('command_type', { 'materialize': lambda x: some_type_of_function('materialize ' + x.command_def), '#': lambda x: x # do nothing }) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ APPARENT_ACTIONS = ( 'command_type', { @@ -1503,7 +1557,8 @@ def testB25131481(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB23445244(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo(): if True: return xxxxxxxxxxxxxxxx( @@ -1514,7 +1569,8 @@ def foo(): FLAGS.aaaaaaaaaaaaaa + FLAGS.bbbbbbbbbbbbbbbbbbb, }) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo(): if True: return xxxxxxxxxxxxxxxx( @@ -1530,7 +1586,8 @@ def foo(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB20559654(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class A(object): def foo(self): @@ -1538,7 +1595,8 @@ def foo(self): ['AA BBBB CCC DDD EEEEEEEE X YY ZZZZ FFF EEE AAAAAAAA'], aaaaaaaaaaa=True, bbbbbbbb=None) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class A(object): def foo(self): @@ -1551,7 +1609,8 @@ def foo(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB23943842(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class F(): def f(): self.assertDictEqual( @@ -1565,7 +1624,8 @@ def f(): 'lines': 'l8'} }) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class F(): def f(): @@ -1589,12 +1649,14 @@ def f(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB20551180(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo(): if True: return (struct.pack('aaaa', bbbbbbbbbb, ccccccccccccccc, dddddddd) + eeeeeee) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo(): if True: return (struct.pack('aaaa', bbbbbbbbbb, ccccccccccccccc, dddddddd) + @@ -1604,12 +1666,14 @@ def foo(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB23944849(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class A(object): def xxxxxxxxx(self, aaaaaaa, bbbbbbb=ccccccccccc, dddddd=300, eeeeeeeeeeeeee=None, fffffffffffffff=0): pass """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class A(object): def xxxxxxxxx(self, @@ -1624,12 +1688,14 @@ def xxxxxxxxx(self, self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB23935890(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class F(): def functioni(self, aaaaaaa, bbbbbbb, cccccc, dddddddddddddd, eeeeeeeeeeeeeee): pass """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class F(): def functioni(self, aaaaaaa, bbbbbbb, cccccc, dddddddddddddd, @@ -1640,7 +1706,8 @@ def functioni(self, aaaaaaa, bbbbbbb, cccccc, dddddddddddddd, self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB28414371(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def _(): return ((m.fffff( m.rrr('mmmmmmmmmmmmmmmm', 'ssssssssssssssssssssssssss'), ffffffffffffffff) @@ -1665,7 +1732,8 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20127686(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def f(): if True: return ((m.fffff( @@ -1683,11 +1751,13 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20016122(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ from a_very_long_or_indented_module_name_yada_yada import (long_argument_1, long_argument_2) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ from a_very_long_or_indented_module_name_yada_yada import ( long_argument_1, long_argument_2) """) @@ -1698,12 +1768,13 @@ def testB20016122(self): '{based_on_style: pep8, split_penalty_import_names: 350}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class foo(): def __eq__(self, other): @@ -1723,8 +1794,9 @@ def __eq__(self, other): try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: yapf, ' - 'split_before_logical_operator: True}')) + style.CreateStyleFromConfig( + '{based_on_style: yapf, ' + 'split_before_logical_operator: True}')) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1732,12 +1804,14 @@ def __eq__(self, other): style.SetGlobalStyle(style.CreateYapfStyle()) def testB22527411(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def f(): if True: aaaaaa.bbbbbbbbbbbbbbbbbbbb[-1].cccccccccccccc.ddd().eeeeeeee(ffffffffffffff) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def f(): if True: aaaaaa.bbbbbbbbbbbbbbbbbbbb[-1].cccccccccccccc.ddd().eeeeeeee( @@ -1747,7 +1821,8 @@ def f(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB20849933(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def main(unused_argv): if True: aaaaaaaa = { @@ -1755,7 +1830,8 @@ def main(unused_argv): (eeeeee.FFFFFFFFFFFFFFFFFF), } """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def main(unused_argv): if True: aaaaaaaa = { @@ -1767,7 +1843,8 @@ def main(unused_argv): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB20813997(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def myfunc_1(): myarray = numpy.zeros((2, 2, 2)) print(myarray[:, 1, :]) @@ -1776,7 +1853,8 @@ def myfunc_1(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20605036(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ foo = { 'aaaa': { # A comment for no particular reason. @@ -1790,7 +1868,8 @@ def testB20605036(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20562732(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ foo = [ # Comment about first list item 'First item', @@ -1802,7 +1881,8 @@ def testB20562732(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20128830(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ a = { 'xxxxxxxxxxxxxxxxxxxx': { 'aaaa': @@ -1822,7 +1902,8 @@ def testB20128830(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20073838(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class DummyModel(object): def do_nothing(self, class_1_count): @@ -1839,7 +1920,8 @@ def do_nothing(self, class_1_count): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19626808(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ if True: aaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbb( 'ccccccccccc', ddddddddd='eeeee').fffffffff([ggggggggggggggggggggg]) @@ -1848,7 +1930,8 @@ def testB19626808(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19547210(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ while True: if True: if True: @@ -1862,7 +1945,8 @@ def testB19547210(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19377034(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def f(): if (aaaaaaaaaaaaaaa.start >= aaaaaaaaaaaaaaa.end or bbbbbbbbbbbbbbb.start >= bbbbbbbbbbbbbbb.end): @@ -1872,7 +1956,8 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19372573(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def f(): if a: return 42 while True: @@ -1890,7 +1975,8 @@ def f(): style.SetGlobalStyle(style.CreateYapfStyle()) def testB19353268(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ a = {1, 2, 3}[x] b = {'foo': 42, 'bar': 37}['foo'] """) @@ -1898,7 +1984,8 @@ def testB19353268(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19287512(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class Foo(object): def bar(self): @@ -1908,7 +1995,8 @@ def bar(self): .Mmmmmmmmmmmmmmmmmm(-1, 'permission error'))): self.assertRaises(nnnnnnnnnnnnnnnn.ooooo, ppppp.qqqqqqqqqqqqqqqqq) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class Foo(object): def bar(self): @@ -1923,7 +2011,8 @@ def bar(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB19194420(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ method.Set( 'long argument goes here that causes the line to break', lambda arg2=0.5: arg2) @@ -1932,7 +2021,7 @@ def testB19194420(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19073499(self): - code = """\ + code = """\ instance = ( aaaaaaa.bbbbbbb().ccccccccccccccccc().ddddddddddd({ 'aa': 'context!' @@ -1944,7 +2033,8 @@ def testB19073499(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB18257115(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ if True: if True: self._Test(aaaa, bbbbbbb.cccccccccc, dddddddd, eeeeeeeeeee, @@ -1954,7 +2044,8 @@ def testB18257115(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB18256666(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class Foo(object): def Bar(self): @@ -1972,7 +2063,8 @@ def Bar(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB18256826(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ if True: pass # A multiline comment. @@ -1991,7 +2083,8 @@ def testB18256826(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB18255697(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ AAAAAAAAAAAAAAA = { 'XXXXXXXXXXXXXX': 4242, # Inline comment # Next comment @@ -2002,12 +2095,14 @@ def testB18255697(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB17534869(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if True: self.assertLess(abs(time.time()-aaaa.bbbbbbbbbbb( datetime.datetime.now())), 1) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if True: self.assertLess( abs(time.time() - aaaa.bbbbbbbbbbb(datetime.datetime.now())), 1) @@ -2016,14 +2111,16 @@ def testB17534869(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB17489866(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def f(): if True: if True: return aaaa.bbbbbbbbb(ccccccc=dddddddddddddd({('eeee', \ 'ffffffff'): str(j)})) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def f(): if True: if True: @@ -2034,7 +2131,8 @@ def f(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB17133019(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class aaaaaaaaaaaaaa(object): def bbbbbbbbbb(self): @@ -2045,7 +2143,8 @@ def bbbbbbbbbb(self): ), "rb") as gggggggggggggggggggg: print(gggggggggggggggggggg) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class aaaaaaaaaaaaaa(object): def bbbbbbbbbb(self): @@ -2059,7 +2158,8 @@ def bbbbbbbbbb(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB17011869(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ '''blah......''' class SomeClass(object): @@ -2070,7 +2170,8 @@ class SomeClass(object): 'DDDDDDDD': 0.4811 } """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ '''blah......''' @@ -2086,14 +2187,16 @@ class SomeClass(object): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB16783631(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if True: with aaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccc(ddddddddddddd, eeeeeeeee=self.fffffffffffff )as gggg: pass """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if True: with aaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccc( ddddddddddddd, eeeeeeeee=self.fffffffffffff) as gggg: @@ -2103,12 +2206,14 @@ def testB16783631(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB16572361(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo(self): def bar(my_dict_name): self.my_dict_name['foo-bar-baz-biz-boo-baa-baa'].IncrementBy.assert_called_once_with('foo_bar_baz_boo') """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo(self): def bar(my_dict_name): @@ -2120,13 +2225,15 @@ def bar(my_dict_name): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB15884241(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if 1: if 1: for row in AAAA: self.create(aaaaaaaa="/aaa/bbbb/cccc/dddddd/eeeeeeeeeeeeeeeeeeeeeeeeee/%s" % row [0].replace(".foo", ".bar"), aaaaa=bbb[1], ccccc=bbb[2], dddd=bbb[3], eeeeeeeeeee=[s.strip() for s in bbb[4].split(",")], ffffffff=[s.strip() for s in bbb[5].split(",")], gggggg=bbb[6]) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if 1: if 1: for row in AAAA: @@ -2144,7 +2251,8 @@ def testB15884241(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB15697268(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def main(unused_argv): ARBITRARY_CONSTANT_A = 10 an_array_with_an_exceedingly_long_name = range(ARBITRARY_CONSTANT_A + 1) @@ -2153,7 +2261,8 @@ def main(unused_argv): a_long_name_slicing = an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A] bad_slice = ("I am a crazy, no good, string what's too long, etc." + " no really ")[:ARBITRARY_CONSTANT_A] """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def main(unused_argv): ARBITRARY_CONSTANT_A = 10 an_array_with_an_exceedingly_long_name = range(ARBITRARY_CONSTANT_A + 1) @@ -2169,7 +2278,7 @@ def main(unused_argv): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB15597568(self): - unformatted_code = """\ + unformatted_code = """\ if True: if True: if True: @@ -2183,14 +2292,16 @@ def testB15597568(self): (", and the process timed out." if did_time_out else ".")) % errorcode) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB15542157(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ aaaaaaaaaaaa = bbbb.ccccccccccccccc(dddddd.eeeeeeeeeeeeee, ffffffffffffffffff, gggggg.hhhhhhhhhhhhhhhhh) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ aaaaaaaaaaaa = bbbb.ccccccccccccccc(dddddd.eeeeeeeeeeeeee, ffffffffffffffffff, gggggg.hhhhhhhhhhhhhhhhh) """) # noqa @@ -2198,7 +2309,8 @@ def testB15542157(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB15438132(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if aaaaaaa.bbbbbbbbbb: cccccc.dddddddddd(eeeeeeeeeee=fffffffffffff.gggggggggggggggggg) if hhhhhh.iiiii.jjjjjjjjjjjjj: @@ -2214,7 +2326,8 @@ def testB15438132(self): lllll.mm), nnnnnnnnnn=ooooooo.pppppppppp) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if aaaaaaa.bbbbbbbbbb: cccccc.dddddddddd(eeeeeeeeeee=fffffffffffff.gggggggggggggggggg) if hhhhhh.iiiii.jjjjjjjjjjjjj: @@ -2233,7 +2346,7 @@ def testB15438132(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB14468247(self): - unformatted_code = """\ + unformatted_code = """\ call(a=1, b=2, ) @@ -2244,15 +2357,17 @@ def testB14468247(self): b=2, ) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB14406499(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo1(parameter_1, parameter_2, parameter_3, parameter_4, \ parameter_5, parameter_6): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo1(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6): pass @@ -2261,18 +2376,21 @@ def foo1(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB13900309(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ self.aaaaaaaaaaa( # A comment in the middle of it all. 948.0/3600, self.bbb.ccccccccccccccccccccc(dddddddddddddddd.eeee, True)) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ self.aaaaaaaaaaa( # A comment in the middle of it all. 948.0 / 3600, self.bbb.ccccccccccccccccccccc(dddddddddddddddd.eeee, True)) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ aaaaaaaaaa.bbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccccc( DC_1, (CL - 50, CL), AAAAAAAA, BBBBBBBBBBBBBBBB, 98.0, CCCCCCC).ddddddddd( # Look! A comment is here. @@ -2281,41 +2399,49 @@ def testB13900309(self): llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc().dddddddddddddddddddddddddd(1, 2, 3, 4) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc( ).dddddddddddddddddddddddddd(1, 2, 3, 4) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc(x).dddddddddddddddddddddddddd(1, 2, 3, 4) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc( x).dddddddddddddddddddddddddd(1, 2, 3, 4) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ aaaaaaaaaaaaaaaaaaaaaaaa(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx).dddddddddddddddddddddddddd(1, 2, 3, 4) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ aaaaaaaaaaaaaaaaaaaaaaaa( xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx).dddddddddddddddddddddddddd(1, 2, 3, 4) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ aaaaaaaaaaaaaaaaaaaaaaaa().bbbbbbbbbbbbbbbbbbbbbbbb().ccccccccccccccccccc().\ dddddddddddddddddd().eeeeeeeeeeeeeeeeeeeee().fffffffffffffffff().gggggggggggggggggg() """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ aaaaaaaaaaaaaaaaaaaaaaaa().bbbbbbbbbbbbbbbbbbbbbbbb().ccccccccccccccccccc( ).dddddddddddddddddd().eeeeeeeeeeeeeeeeeeeee().fffffffffffffffff( ).gggggggggggggggggg() @@ -2324,7 +2450,8 @@ def testB13900309(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB67935687(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ Fetch( Raw('monarch.BorgTask', '/union/row_operator_action_delay'), {'borg_user': self.borg_user}) @@ -2332,13 +2459,15 @@ def testB67935687(self): llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ shelf_renderer.expand_text = text.translate_to_unicode( expand_text % { 'creator': creator }) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ shelf_renderer.expand_text = text.translate_to_unicode(expand_text % {'creator': creator}) """) # noqa diff --git a/yapftests/reformatter_facebook_test.py b/yapftests/reformatter_facebook_test.py index c61f32bf5..14b07d06b 100644 --- a/yapftests/reformatter_facebook_test.py +++ b/yapftests/reformatter_facebook_test.py @@ -29,12 +29,14 @@ def setUpClass(cls): style.SetGlobalStyle(style.CreateFacebookStyle()) def testNoNeedForLineBreaks(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def overly_long_function_name( just_one_arg, **kwargs): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def overly_long_function_name(just_one_arg, **kwargs): pass """) @@ -42,13 +44,15 @@ def overly_long_function_name(just_one_arg, **kwargs): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDedentClosingBracket(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def overly_long_function_name( first_argument_on_the_same_line, second_argument_makes_the_line_too_long): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def overly_long_function_name( first_argument_on_the_same_line, second_argument_makes_the_line_too_long ): @@ -58,12 +62,14 @@ def overly_long_function_name( self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBreakAfterOpeningBracketIfContentsTooBig(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def overly_long_function_name(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def overly_long_function_name( a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, \ v, w, x, y, z @@ -74,7 +80,8 @@ def overly_long_function_name( self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDedentClosingBracketWithComments(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def overly_long_function_name( # comment about the first argument first_argument_with_a_very_long_name_or_so, @@ -82,7 +89,8 @@ def overly_long_function_name( second_argument_makes_the_line_too_long): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def overly_long_function_name( # comment about the first argument first_argument_with_a_very_long_name_or_so, @@ -95,7 +103,8 @@ def overly_long_function_name( self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDedentImportAsNames(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ from module import ( internal_function as function, SOME_CONSTANT_NUMBER1, @@ -107,7 +116,8 @@ def testDedentImportAsNames(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDedentTestListGexp(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ try: pass except ( @@ -122,7 +132,8 @@ def testDedentTestListGexp(self): ) as exception: pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ try: pass except ( @@ -146,13 +157,15 @@ def testDedentTestListGexp(self): def testBrokenIdempotency(self): # TODO(ambv): The following behaviour should be fixed. - pass0_code = textwrap.dedent("""\ + pass0_code = textwrap.dedent( + """\ try: pass except (IOError, OSError, LookupError, RuntimeError, OverflowError) as exception: pass """) # noqa - pass1_code = textwrap.dedent("""\ + pass1_code = textwrap.dedent( + """\ try: pass except ( @@ -163,7 +176,8 @@ def testBrokenIdempotency(self): llines = yapf_test_helper.ParseAndUnwrap(pass0_code) self.assertCodeEqual(pass1_code, reformatter.Reformat(llines)) - pass2_code = textwrap.dedent("""\ + pass2_code = textwrap.dedent( + """\ try: pass except ( @@ -175,7 +189,8 @@ def testBrokenIdempotency(self): self.assertCodeEqual(pass2_code, reformatter.Reformat(llines)) def testIfExprHangingIndent(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if True: if True: if True: @@ -184,7 +199,8 @@ def testIfExprHangingIndent(self): self.foobars.counters['db.marshmellow_skins'] != 1): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if True: if True: if True: @@ -198,11 +214,13 @@ def testIfExprHangingIndent(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSimpleDedenting(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if True: self.assertEqual(result.reason_not_added, "current preflight is still running") """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if True: self.assertEqual( result.reason_not_added, "current preflight is still running" @@ -212,7 +230,8 @@ def testSimpleDedenting(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDedentingWithSubscripts(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class Foo: class Bar: @classmethod @@ -221,7 +240,8 @@ def baz(cls, clues_list, effect, constraints, constraint_manager): return cls.single_constraint_not(clues_lists, effect, constraints[0], constraint_manager) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class Foo: class Bar: @classmethod @@ -235,7 +255,8 @@ def baz(cls, clues_list, effect, constraints, constraint_manager): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDedentingCallsWithInnerLists(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class _(): def _(): cls.effect_clues = { @@ -246,7 +267,8 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDedentingListComprehension(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class Foo(): def _pack_results_for_constraint_or(): self.param_groups = dict( @@ -284,7 +306,8 @@ def _pack_results_for_constraint_or(): ('localhost', os.path.join(path, 'node_2.log'), super_parser) ] """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class Foo(): def _pack_results_for_constraint_or(): self.param_groups = dict( @@ -324,7 +347,8 @@ def _pack_results_for_constraint_or(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMustSplitDedenting(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class _(): def _(): effect_line = FrontInput( @@ -336,7 +360,8 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDedentIfConditional(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class _(): def _(): if True: @@ -350,7 +375,8 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDedentSet(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class _(): def _(): assert set(self.constraint_links.get_links()) == set( @@ -366,7 +392,8 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDedentingInnerScope(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class Foo(): @classmethod def _pack_results_for_constraint_or(cls, combination, constraints): @@ -375,16 +402,17 @@ def _pack_results_for_constraint_or(cls, combination, constraints): constraints, InvestigationResult.OR ) """) # noqa - llines = yapf_test_helper.ParseAndUnwrap(code) + llines = yapf_test_helper.ParseAndUnwrap(code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, reformatted_code) - llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, reformatted_code) def testCommentWithNewlinesInPrefix(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo(): if 0: return False @@ -397,7 +425,8 @@ def foo(): print(foo()) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo(): if 0: return False @@ -413,7 +442,7 @@ def foo(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testIfStmtClosingBracket(self): - unformatted_code = """\ + unformatted_code = """\ if (isinstance(value , (StopIteration , StopAsyncIteration )) and exc.__cause__ is value_asdfasdfasdfasdfsafsafsafdasfasdfs): return False """ # noqa @@ -424,7 +453,7 @@ def testIfStmtClosingBracket(self): ): return False """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index acc218d24..19c294d18 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -30,11 +30,13 @@ def setUpClass(cls): # pylint: disable=g-missing-super-call style.SetGlobalStyle(style.CreatePEP8Style()) def testIndent4(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if a+b: pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if a + b: pass """) @@ -42,7 +44,8 @@ def testIndent4(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSingleLineIfStatements(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ if True: a = 42 elif False: b = 42 else: c = 42 @@ -51,12 +54,14 @@ def testSingleLineIfStatements(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testBlankBetweenClassAndDef(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class Foo: def joe(): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class Foo: def joe(): @@ -66,7 +71,8 @@ def joe(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBlankBetweenDefsInClass(self): - unformatted_code = textwrap.dedent('''\ + unformatted_code = textwrap.dedent( + '''\ class TestClass: def __init__(self): self.running = False @@ -75,7 +81,8 @@ def run(self): def is_running(self): return self.running ''') - expected_formatted_code = textwrap.dedent('''\ + expected_formatted_code = textwrap.dedent( + '''\ class TestClass: def __init__(self): @@ -91,11 +98,13 @@ def is_running(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSingleWhiteBeforeTrailingComment(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if a+b: # comment pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if a + b: # comment pass """) @@ -103,19 +112,22 @@ def testSingleWhiteBeforeTrailingComment(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSpaceBetweenEndingCommandAndClosingBracket(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ a = ( 1, ) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ a = (1, ) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testContinuedNonOutdentedLine(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class eld(d): if str(geom.geom_type).upper( ) != self.geom_type and not self.geom_type == 'GEOMETRY': @@ -125,7 +137,8 @@ class eld(d): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testWrappingPercentExpressions(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def f(): if True: zzzzz = '%s-%s' % (xxxxxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxx.yyy + 1) @@ -133,7 +146,8 @@ def f(): zzzzz = '%s-%s' % (xxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxxxxxx + 1) zzzzz = '%s-%s'.ww(xxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxxxxxx + 1) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def f(): if True: zzzzz = '%s-%s' % (xxxxxxxxxxxxxxxxxxxxxxxxxx + 1, @@ -149,12 +163,14 @@ def f(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testAlignClosingBracketWithVisualIndentation(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ TEST_LIST = ('foo', 'bar', # first comment 'baz' # second comment ) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ TEST_LIST = ( 'foo', 'bar', # first comment @@ -164,7 +180,8 @@ def testAlignClosingBracketWithVisualIndentation(self): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def f(): def g(): @@ -173,7 +190,8 @@ def g(): ): pass """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def f(): def g(): @@ -186,11 +204,13 @@ def g(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testIndentSizeChanging(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if True: runtime_mins = (program_end_time - program_start_time).total_seconds() / 60.0 """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if True: runtime_mins = (program_end_time - program_start_time).total_seconds() / 60.0 @@ -199,7 +219,8 @@ def testIndentSizeChanging(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testHangingIndentCollision(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if (aaaaaaaaaaaaaa + bbbbbbbbbbbbbbbb == ccccccccccccccccc and xxxxxxxxxxxxx or yyyyyyyyyyyyyyyyy): pass elif (xxxxxxxxxxxxxxx(aaaaaaaaaaa, bbbbbbbbbbbbbb, cccccccccccc, dddddddddd=None)): @@ -213,7 +234,8 @@ def h(): for connection in itertools.chain(branch.contact, branch.address, morestuff.andmore.andmore.andmore.andmore.andmore.andmore.andmore): dosomething(connection) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if (aaaaaaaaaaaaaa + bbbbbbbbbbbbbbbb == ccccccccccccccccc and xxxxxxxxxxxxx or yyyyyyyyyyyyyyyyy): pass @@ -242,7 +264,8 @@ def testSplittingBeforeLogicalOperator(self): style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: pep8, split_before_logical_operator: True}')) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo(): return bool(update.message.new_chat_member or update.message.left_chat_member or update.message.new_chat_title or update.message.new_chat_photo or @@ -251,7 +274,8 @@ def foo(): or update.message.migrate_to_chat_id or update.message.migrate_from_chat_id or update.message.pinned_message) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo(): return bool( update.message.new_chat_member or update.message.left_chat_member @@ -265,18 +289,20 @@ def foo(): or update.message.pinned_message) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) def testContiguousListEndingWithComment(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if True: if True: keys.append(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) # may be unassigned. """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if True: if True: keys.append( @@ -290,11 +316,13 @@ def testSplittingBeforeFirstArgument(self): style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: pep8, split_before_first_argument: True}')) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ a_very_long_function_name(long_argument_name_1=1, long_argument_name_2=2, long_argument_name_3=3, long_argument_name_4=4) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ a_very_long_function_name( long_argument_name_1=1, long_argument_name_2=2, @@ -302,17 +330,19 @@ def testSplittingBeforeFirstArgument(self): long_argument_name_4=4) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) def testSplittingExpressionsInsideSubscripts(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo(): df = df[(df['campaign_status'] == 'LIVE') & (df['action_status'] == 'LIVE')] """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo(): df = df[(df['campaign_status'] == 'LIVE') & (df['action_status'] == 'LIVE')] @@ -321,13 +351,15 @@ def foo(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplitListsAndDictSetMakersIfCommaTerminated(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ DJANGO_TEMPLATES_OPTIONS = {"context_processors": []} DJANGO_TEMPLATES_OPTIONS = {"context_processors": [],} x = ["context_processors"] x = ["context_processors",] """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ DJANGO_TEMPLATES_OPTIONS = {"context_processors": []} DJANGO_TEMPLATES_OPTIONS = { "context_processors": [], @@ -341,13 +373,15 @@ def testSplitListsAndDictSetMakersIfCommaTerminated(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplitAroundNamedAssigns(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class a(): def a(): return a( aaaaaaaaaa=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class a(): def a(): @@ -359,13 +393,15 @@ def a(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testUnaryOperator(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if not -3 < x < 3: pass if -3 < x < 3: pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if not -3 < x < 3: pass if -3 < x < 3: @@ -377,21 +413,24 @@ def testUnaryOperator(self): def testNoSplitBeforeDictValue(self): try: style.SetGlobalStyle( - style.CreateStyleFromConfig('{based_on_style: pep8, ' - 'allow_split_before_dict_value: false, ' - 'coalesce_brackets: true, ' - 'dedent_closing_brackets: true, ' - 'each_dict_entry_on_separate_line: true, ' - 'split_before_logical_operator: true}')) - - unformatted_code = textwrap.dedent("""\ + style.CreateStyleFromConfig( + '{based_on_style: pep8, ' + 'allow_split_before_dict_value: false, ' + 'coalesce_brackets: true, ' + 'dedent_closing_brackets: true, ' + 'each_dict_entry_on_separate_line: true, ' + 'split_before_logical_operator: true}')) + + unformatted_code = textwrap.dedent( + """\ some_dict = { 'title': _("I am example data"), 'description': _("Lorem ipsum dolor met sit amet elit, si vis pacem para bellum " "elites nihi very long string."), } """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ some_dict = { 'title': _("I am example data"), 'description': _( @@ -401,13 +440,15 @@ def testNoSplitBeforeDictValue(self): } """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ X = {'a': 1, 'b': 2, 'key': this_is_a_function_call_that_goes_over_the_column_limit_im_pretty_sure()} """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ X = { 'a': 1, 'b': 2, @@ -415,16 +456,18 @@ def testNoSplitBeforeDictValue(self): } """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ attrs = { 'category': category, 'role': forms.ModelChoiceField(label=_("Role"), required=False, queryset=category_roles, initial=selected_role, empty_label=_("No access"),), } """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ attrs = { 'category': category, 'role': forms.ModelChoiceField( @@ -437,17 +480,19 @@ def testNoSplitBeforeDictValue(self): } """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ css_class = forms.CharField( label=_("CSS class"), required=False, help_text=_("Optional CSS class used to customize this category appearance from templates."), ) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ css_class = forms.CharField( label=_("CSS class"), required=False, @@ -457,8 +502,8 @@ def testNoSplitBeforeDictValue(self): ) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) @@ -473,7 +518,7 @@ def _(): cdffile['Latitude'][:] >= select_lat - radius) & ( cdffile['Latitude'][:] <= select_lat + radius)) """ - expected_code = """\ + expected_code = """\ def _(): include_values = np.where( (cdffile['Quality_Flag'][:] >= 5) & (cdffile['Day_Night_Flag'][:] == 1) @@ -482,7 +527,7 @@ def _(): & (cdffile['Latitude'][:] >= select_lat - radius) & (cdffile['Latitude'][:] <= select_lat + radius)) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertEqual(expected_code, reformatter.Reformat(llines)) def testNoBlankLinesOnlyForFirstNestedObject(self): @@ -500,7 +545,7 @@ def bar(self): bar docs """ ''' - expected_code = '''\ + expected_code = '''\ class Demo: """ Demo docs @@ -516,7 +561,7 @@ def bar(self): bar docs """ ''' - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertEqual(expected_code, reformatter.Reformat(llines)) def testSplitBeforeArithmeticOperators(self): @@ -525,7 +570,7 @@ def testSplitBeforeArithmeticOperators(self): style.CreateStyleFromConfig( '{based_on_style: pep8, split_before_arithmetic_operator: true}')) - unformatted_code = """\ + unformatted_code = """\ def _(): raise ValueError('This is a long message that ends with an argument: ' + str(42)) """ # noqa @@ -534,9 +579,9 @@ def _(): raise ValueError('This is a long message that ends with an argument: ' + str(42)) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) @@ -546,12 +591,12 @@ def testListSplitting(self): (1,1), (1,1), (1,1), (1,1), (1,1), (1,1), (1,1), (1,10), (1,11), (1, 10), (1,11), (10,11)]) """ - expected_code = """\ + expected_code = """\ foo([(1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 10), (1, 11), (1, 10), (1, 11), (10, 11)]) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testNoBlankLineBeforeNestedFuncOrClass(self): @@ -561,7 +606,7 @@ def testNoBlankLineBeforeNestedFuncOrClass(self): '{based_on_style: pep8, ' 'blank_line_before_nested_class_or_def: false}')) - unformatted_code = '''\ + unformatted_code = '''\ def normal_function(): """Return the nested function.""" @@ -589,14 +634,15 @@ class nested_class(): return nested_function ''' - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) def testParamListIndentationCollision1(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class _(): def __init__(self, title: Optional[str], diffs: Collection[BinaryDiff] = (), charset: Union[Type[AsciiCharset], Type[LineCharset]] = AsciiCharset, preprocess: Callable[[str], str] = identity, @@ -605,7 +651,8 @@ def __init__(self, title: Optional[str], diffs: Collection[BinaryDiff] = (), cha self._cs = charset self._preprocess = preprocess """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class _(): def __init__( @@ -624,7 +671,8 @@ def __init__( self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testParamListIndentationCollision2(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def simple_pass_function_with_an_extremely_long_name_and_some_arguments( argument0, argument1): pass @@ -633,7 +681,8 @@ def simple_pass_function_with_an_extremely_long_name_and_some_arguments( self.assertCodeEqual(code, reformatter.Reformat(llines)) def testParamListIndentationCollision3(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def func1( arg1, arg2, @@ -651,11 +700,13 @@ def func2( self.assertCodeEqual(code, reformatter.Reformat(llines)) def testTwoWordComparisonOperators(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl is not ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj) _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl not in {ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj}) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl is not ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj) _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl @@ -667,7 +718,8 @@ def testTwoWordComparisonOperators(self): @unittest.skipUnless(not py3compat.PY3, 'Requires Python 2.7') def testAsyncAsNonKeyword(self): # In Python 2, async may be used as a non-keyword identifier. - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ from util import async @@ -683,12 +735,14 @@ def bar(self): self.assertCodeEqual(code, reformatter.Reformat(llines, verify=False)) def testStableInlinedDictionaryFormatting(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def _(): url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( value, urllib.urlencode({'action': 'update', 'parameter': value})) """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def _(): url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( value, urllib.urlencode({ @@ -697,18 +751,19 @@ def _(): })) """) - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) - llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testSpaceBetweenColonAndElipses(self): style.SetGlobalStyle(style.CreatePEP8Style()) - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class MyClass(ABC): place: ... @@ -719,10 +774,11 @@ class MyClass(ABC): @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testSpaceBetweenDictColonAndElipses(self): style.SetGlobalStyle(style.CreatePEP8Style()) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ {0:"...", 1:...} """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ {0: "...", 1: ...} """) @@ -732,7 +788,8 @@ def testSpaceBetweenDictColonAndElipses(self): class TestsForSpacesInsideBrackets(yapf_test_helper.YAPFTest): """Test the SPACE_INSIDE_BRACKETS style option.""" - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ foo() foo(1) foo(1,2) @@ -765,7 +822,8 @@ def testEnabled(self): style.SetGlobalStyle( style.CreateStyleFromConfig('{space_inside_brackets: True}')) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ foo() foo( 1 ) foo( 1, 2 ) @@ -803,7 +861,8 @@ def testEnabled(self): def testDefault(self): style.SetGlobalStyle(style.CreatePEP8Style()) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ foo() foo(1) foo(1, 2) @@ -842,7 +901,8 @@ def testDefault(self): def testAwait(self): style.SetGlobalStyle( style.CreateStyleFromConfig('{space_inside_brackets: True}')) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ import asyncio import time @@ -855,7 +915,8 @@ async def main(): if (await get_html()): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ import asyncio import time @@ -876,7 +937,8 @@ async def main(): class TestsForSpacesAroundSubscriptColon(yapf_test_helper.YAPFTest): """Test the SPACES_AROUND_SUBSCRIPT_COLON style option.""" - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ a = list1[ : ] b = list2[ slice_start: ] c = list3[ slice_start:slice_end ] @@ -892,7 +954,8 @@ class TestsForSpacesAroundSubscriptColon(yapf_test_helper.YAPFTest): def testEnabled(self): style.SetGlobalStyle( style.CreateStyleFromConfig('{spaces_around_subscript_colon: True}')) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ a = list1[:] b = list2[slice_start :] c = list3[slice_start : slice_end] @@ -909,11 +972,13 @@ def testEnabled(self): def testWithSpaceInsideBrackets(self): style.SetGlobalStyle( - style.CreateStyleFromConfig('{' - 'spaces_around_subscript_colon: true, ' - 'space_inside_brackets: true,' - '}')) - expected_formatted_code = textwrap.dedent("""\ + style.CreateStyleFromConfig( + '{' + 'spaces_around_subscript_colon: true, ' + 'space_inside_brackets: true,' + '}')) + expected_formatted_code = textwrap.dedent( + """\ a = list1[ : ] b = list2[ slice_start : ] c = list3[ slice_start : slice_end ] @@ -930,7 +995,8 @@ def testWithSpaceInsideBrackets(self): def testDefault(self): style.SetGlobalStyle(style.CreatePEP8Style()) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ a = list1[:] b = list2[slice_start:] c = list3[slice_start:slice_end] diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index b5d68e86f..88dd9d7bd 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -33,11 +33,13 @@ def setUpClass(cls): # pylint: disable=g-missing-super-call style.SetGlobalStyle(style.CreatePEP8Style()) def testTypedNames(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def x(aaaaaaaaaaaaaaa:int,bbbbbbbbbbbbbbbb:str,ccccccccccccccc:dict,eeeeeeeeeeeeee:set={1, 2, 3})->bool: pass """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def x(aaaaaaaaaaaaaaa: int, bbbbbbbbbbbbbbbb: str, ccccccccccccccc: dict, @@ -48,11 +50,13 @@ def x(aaaaaaaaaaaaaaa: int, self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testTypedNameWithLongNamedArg(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def func(arg=long_function_call_that_pushes_the_line_over_eighty_characters()) -> ReturnType: pass """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def func(arg=long_function_call_that_pushes_the_line_over_eighty_characters() ) -> ReturnType: pass @@ -61,11 +65,13 @@ def func(arg=long_function_call_that_pushes_the_line_over_eighty_characters() self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testKeywordOnlyArgSpecifier(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo(a, *, kw): return a+kw """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo(a, *, kw): return a + kw """) @@ -74,13 +80,15 @@ def foo(a, *, kw): @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testPEP448ParameterExpansion(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ { ** x } { **{} } { **{ **x }, **x } {'a': 1, **kw , 'b':3, **kw2 } """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ {**x} {**{}} {**{**x}, **x} @@ -90,11 +98,13 @@ def testPEP448ParameterExpansion(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testAnnotations(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo(a: list, b: "bar") -> dict: return a+b """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo(a: list, b: "bar") -> dict: return a + b """) @@ -102,15 +112,16 @@ def foo(a: list, b: "bar") -> dict: self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testExecAsNonKeyword(self): - unformatted_code = 'methods.exec( sys.modules[name])\n' + unformatted_code = 'methods.exec( sys.modules[name])\n' expected_formatted_code = 'methods.exec(sys.modules[name])\n' - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testAsyncFunctions(self): if sys.version_info[1] < 5: return - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ import asyncio import time @@ -130,7 +141,7 @@ async def main(): self.assertCodeEqual(code, reformatter.Reformat(llines, verify=False)) def testNoSpacesAroundPowerOperator(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ a**b """) expected_formatted_code = textwrap.dedent("""\ @@ -143,13 +154,13 @@ def testNoSpacesAroundPowerOperator(self): '{based_on_style: pep8, SPACES_AROUND_POWER_OPERATOR: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) def testSpacesAroundDefaultOrNamedAssign(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ f(a=5) """) expected_formatted_code = textwrap.dedent("""\ @@ -163,13 +174,14 @@ def testSpacesAroundDefaultOrNamedAssign(self): 'SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) def testTypeHint(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo(x: int=42): pass @@ -177,7 +189,8 @@ def foo(x: int=42): def foo2(x: 'int' =42): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo(x: int = 42): pass @@ -189,17 +202,18 @@ def foo2(x: 'int' = 42): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMatrixMultiplication(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ a=b@c """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ a = b @ c """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoneKeyword(self): - code = """\ + code = """\ None.__ne__() """ llines = yapf_test_helper.ParseAndUnwrap(code) @@ -208,7 +222,8 @@ def testNoneKeyword(self): def testAsyncWithPrecedingComment(self): if sys.version_info[1] < 5: return - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ import asyncio # Comment @@ -218,7 +233,8 @@ async def bar(): async def foo(): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ import asyncio @@ -236,7 +252,8 @@ async def foo(): def testAsyncFunctionsNested(self): if sys.version_info[1] < 5: return - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ async def outer(): async def inner(): @@ -248,13 +265,15 @@ async def inner(): def testKeepTypesIntact(self): if sys.version_info[1] < 5: return - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def _ReduceAbstractContainers( self, *args: Optional[automation_converter.PyiCollectionAbc]) -> List[ automation_converter.PyiCollectionAbc]: pass """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def _ReduceAbstractContainers( self, *args: Optional[automation_converter.PyiCollectionAbc] ) -> List[automation_converter.PyiCollectionAbc]: @@ -266,13 +285,15 @@ def _ReduceAbstractContainers( def testContinuationIndentWithAsync(self): if sys.version_info[1] < 5: return - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ async def start_websocket(): async with session.ws_connect( r"ws://a_really_long_long_long_long_long_long_url") as ws: pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ async def start_websocket(): async with session.ws_connect( r"ws://a_really_long_long_long_long_long_long_url") as ws: @@ -285,7 +306,7 @@ def testSplittingArguments(self): if sys.version_info[1] < 5: return - unformatted_code = """\ + unformatted_code = """\ async def open_file(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None): pass @@ -346,15 +367,15 @@ def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): 'split_before_first_argument: true}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) def testDictUnpacking(self): if sys.version_info[1] < 5: return - unformatted_code = """\ + unformatted_code = """\ class Foo: def foo(self): foofoofoofoofoofoofoofoo('foofoofoofoofoo', { @@ -373,7 +394,7 @@ def foo(self): **foofoofoo }) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMultilineFormatString(self): @@ -401,7 +422,7 @@ def dirichlet(x12345678901234567890123456789012345678901234567890=...) -> None: self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionTypedReturnNextLine(self): - code = """\ + code = """\ def _GenerateStatsEntries( process_id: Text, timestamp: Optional[ffffffff.FFFFFFFFFFF] = None @@ -412,7 +433,7 @@ def _GenerateStatsEntries( self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionTypedReturnSameLine(self): - code = """\ + code = """\ def rrrrrrrrrrrrrrrrrrrrrr( ccccccccccccccccccccccc: Tuple[Text, Text]) -> List[Tuple[Text, Text]]: pass @@ -423,7 +444,8 @@ def rrrrrrrrrrrrrrrrrrrrrr( def testAsyncForElseNotIndentedInsideBody(self): if sys.version_info[1] < 5: return - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ async def fn(): async for message in websocket: for i in range(10): @@ -439,7 +461,8 @@ async def fn(): def testForElseInAsyncNotMixedWithAsyncFor(self): if sys.version_info[1] < 5: return - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ async def fn(): for i in range(10): pass @@ -450,12 +473,14 @@ async def fn(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testParameterListIndentationConflicts(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def raw_message( # pylint: disable=too-many-arguments self, text, user_id=1000, chat_type='private', forward_date=None, forward_from=None): pass """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def raw_message( # pylint: disable=too-many-arguments self, text, diff --git a/yapftests/reformatter_style_config_test.py b/yapftests/reformatter_style_config_test.py index c5726cb30..6746ba0ed 100644 --- a/yapftests/reformatter_style_config_test.py +++ b/yapftests/reformatter_style_config_test.py @@ -30,26 +30,30 @@ def setUp(self): def testSetGlobalStyle(self): try: style.SetGlobalStyle(style.CreateYapfStyle()) - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent( + u"""\ for i in range(5): print('bar') """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent( + u"""\ for i in range(5): print('bar') """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) style.DEFAULT_STYLE = self.current_style - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent( + u"""\ for i in range(5): print('bar') """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent( + u"""\ for i in range(5): print('bar') """) @@ -58,32 +62,35 @@ def testSetGlobalStyle(self): def testOperatorNoSpaceStyle(self): try: - sympy_style = style.CreatePEP8Style() + sympy_style = style.CreatePEP8Style() sympy_style['NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS'] = \ style._StringSetConverter('*,/') style.SetGlobalStyle(sympy_style) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ a = 1+2 * 3 - 4 / 5 b = '0' * 1 """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ a = 1 + 2*3 - 4/5 b = '0'*1 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) style.DEFAULT_STYLE = self.current_style def testOperatorPrecedenceStyle(self): try: - pep8_with_precedence = style.CreatePEP8Style() + pep8_with_precedence = style.CreatePEP8Style() pep8_with_precedence['ARITHMETIC_PRECEDENCE_INDICATION'] = True style.SetGlobalStyle(pep8_with_precedence) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ 1+2 (1 + 2) * (3 - (4 / 5)) a = 1 * 2 + 3 / 4 @@ -98,7 +105,8 @@ def testOperatorPrecedenceStyle(self): j = (1 * 2 - 3) + 4 k = (1 * 2 * 3) + (4 * 5 * 6 * 7 * 8) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ 1 + 2 (1+2) * (3 - (4/5)) a = 1*2 + 3/4 @@ -115,19 +123,20 @@ def testOperatorPrecedenceStyle(self): """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) style.DEFAULT_STYLE = self.current_style def testNoSplitBeforeFirstArgumentStyle1(self): try: - pep8_no_split_before_first = style.CreatePEP8Style() + pep8_no_split_before_first = style.CreatePEP8Style() pep8_no_split_before_first['SPLIT_BEFORE_FIRST_ARGUMENT'] = False - pep8_no_split_before_first['SPLIT_BEFORE_NAMED_ASSIGNS'] = False + pep8_no_split_before_first['SPLIT_BEFORE_NAMED_ASSIGNS'] = False style.SetGlobalStyle(pep8_no_split_before_first) - formatted_code = textwrap.dedent("""\ + formatted_code = textwrap.dedent( + """\ # Example from in-code MustSplit comments foo = outer_function_call(fitting_inner_function_call(inner_arg1, inner_arg2), outer_arg1, outer_arg2) @@ -164,11 +173,12 @@ def testNoSplitBeforeFirstArgumentStyle1(self): def testNoSplitBeforeFirstArgumentStyle2(self): try: - pep8_no_split_before_first = style.CreatePEP8Style() + pep8_no_split_before_first = style.CreatePEP8Style() pep8_no_split_before_first['SPLIT_BEFORE_FIRST_ARGUMENT'] = False - pep8_no_split_before_first['SPLIT_BEFORE_NAMED_ASSIGNS'] = True + pep8_no_split_before_first['SPLIT_BEFORE_NAMED_ASSIGNS'] = True style.SetGlobalStyle(pep8_no_split_before_first) - formatted_code = textwrap.dedent("""\ + formatted_code = textwrap.dedent( + """\ # Examples Issue#556 i_take_a_lot_of_params(arg1, param1=very_long_expression1(), diff --git a/yapftests/reformatter_verify_test.py b/yapftests/reformatter_verify_test.py index 33ba3a614..2abbd19ff 100644 --- a/yapftests/reformatter_verify_test.py +++ b/yapftests/reformatter_verify_test.py @@ -32,7 +32,8 @@ def setUpClass(cls): style.SetGlobalStyle(style.CreatePEP8Style()) def testVerifyException(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class ABC(metaclass=type): pass """) @@ -42,20 +43,23 @@ class ABC(metaclass=type): reformatter.Reformat(llines) # verify should be False by default. def testNoVerify(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class ABC(metaclass=type): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class ABC(metaclass=type): pass """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines, verify=False)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines, verify=False)) def testVerifyFutureImport(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ from __future__ import print_function def call_my_function(the_function): @@ -68,7 +72,8 @@ def call_my_function(the_function): with self.assertRaises(verifier.InternalError): reformatter.Reformat(llines, verify=True) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ from __future__ import print_function @@ -80,11 +85,12 @@ def call_my_function(the_function): call_my_function(print) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines, verify=False)) + self.assertCodeEqual( + expected_formatted_code, reformatter.Reformat(llines, verify=False)) def testContinuationLineShouldBeDistinguished(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ class Foo(object): def bar(self): diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index f7474a398..24226cbac 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -26,10 +26,10 @@ from yapftests import yapf_test_helper -UNBREAKABLE = split_penalty.UNBREAKABLE +UNBREAKABLE = split_penalty.UNBREAKABLE VERY_STRONGLY_CONNECTED = split_penalty.VERY_STRONGLY_CONNECTED -DOTTED_NAME = split_penalty.DOTTED_NAME -STRONGLY_CONNECTED = split_penalty.STRONGLY_CONNECTED +DOTTED_NAME = split_penalty.DOTTED_NAME +STRONGLY_CONNECTED = split_penalty.STRONGLY_CONNECTED class SplitPenaltyTest(yapf_test_helper.YAPFTest): @@ -68,9 +68,12 @@ def FlattenRec(tree): if pytree_utils.NodeName(tree) in pytree_utils.NONSEMANTIC_TOKENS: return [] if isinstance(tree, pytree.Leaf): - return [(tree.value, - pytree_utils.GetNodeAnnotation( - tree, pytree_utils.Annotation.SPLIT_PENALTY))] + return [ + ( + tree.value, + pytree_utils.GetNodeAnnotation( + tree, pytree_utils.Annotation.SPLIT_PENALTY)) + ] nodes = [] for node in tree.children: nodes += FlattenRec(node) @@ -85,181 +88,194 @@ def foo(x): pass """) tree = self._ParseAndComputePenalties(code) - self._CheckPenalties(tree, [ - ('def', None), - ('foo', UNBREAKABLE), - ('(', UNBREAKABLE), - ('x', None), - (')', STRONGLY_CONNECTED), - (':', UNBREAKABLE), - ('pass', None), - ]) + self._CheckPenalties( + tree, [ + ('def', None), + ('foo', UNBREAKABLE), + ('(', UNBREAKABLE), + ('x', None), + (')', STRONGLY_CONNECTED), + (':', UNBREAKABLE), + ('pass', None), + ]) # Test function definition with trailing comment. - code = textwrap.dedent(r""" + code = textwrap.dedent( + r""" def foo(x): # trailing comment pass """) tree = self._ParseAndComputePenalties(code) - self._CheckPenalties(tree, [ - ('def', None), - ('foo', UNBREAKABLE), - ('(', UNBREAKABLE), - ('x', None), - (')', STRONGLY_CONNECTED), - (':', UNBREAKABLE), - ('pass', None), - ]) + self._CheckPenalties( + tree, [ + ('def', None), + ('foo', UNBREAKABLE), + ('(', UNBREAKABLE), + ('x', None), + (')', STRONGLY_CONNECTED), + (':', UNBREAKABLE), + ('pass', None), + ]) # Test class definitions. - code = textwrap.dedent(r""" + code = textwrap.dedent( + r""" class A: pass class B(A): pass """) tree = self._ParseAndComputePenalties(code) - self._CheckPenalties(tree, [ - ('class', None), - ('A', UNBREAKABLE), - (':', UNBREAKABLE), - ('pass', None), - ('class', None), - ('B', UNBREAKABLE), - ('(', UNBREAKABLE), - ('A', None), - (')', None), - (':', UNBREAKABLE), - ('pass', None), - ]) + self._CheckPenalties( + tree, [ + ('class', None), + ('A', UNBREAKABLE), + (':', UNBREAKABLE), + ('pass', None), + ('class', None), + ('B', UNBREAKABLE), + ('(', UNBREAKABLE), + ('A', None), + (')', None), + (':', UNBREAKABLE), + ('pass', None), + ]) # Test lambda definitions. code = textwrap.dedent(r""" lambda a, b: None """) tree = self._ParseAndComputePenalties(code) - self._CheckPenalties(tree, [ - ('lambda', None), - ('a', VERY_STRONGLY_CONNECTED), - (',', VERY_STRONGLY_CONNECTED), - ('b', VERY_STRONGLY_CONNECTED), - (':', VERY_STRONGLY_CONNECTED), - ('None', VERY_STRONGLY_CONNECTED), - ]) + self._CheckPenalties( + tree, [ + ('lambda', None), + ('a', VERY_STRONGLY_CONNECTED), + (',', VERY_STRONGLY_CONNECTED), + ('b', VERY_STRONGLY_CONNECTED), + (':', VERY_STRONGLY_CONNECTED), + ('None', VERY_STRONGLY_CONNECTED), + ]) # Test dotted names. code = textwrap.dedent(r""" import a.b.c """) tree = self._ParseAndComputePenalties(code) - self._CheckPenalties(tree, [ - ('import', None), - ('a', None), - ('.', UNBREAKABLE), - ('b', UNBREAKABLE), - ('.', UNBREAKABLE), - ('c', UNBREAKABLE), - ]) + self._CheckPenalties( + tree, [ + ('import', None), + ('a', None), + ('.', UNBREAKABLE), + ('b', UNBREAKABLE), + ('.', UNBREAKABLE), + ('c', UNBREAKABLE), + ]) def testStronglyConnected(self): # Test dictionary keys. - code = textwrap.dedent(r""" + code = textwrap.dedent( + r""" a = { 'x': 42, y(lambda a: 23): 37, } """) tree = self._ParseAndComputePenalties(code) - self._CheckPenalties(tree, [ - ('a', None), - ('=', None), - ('{', None), - ("'x'", None), - (':', STRONGLY_CONNECTED), - ('42', None), - (',', None), - ('y', None), - ('(', UNBREAKABLE), - ('lambda', STRONGLY_CONNECTED), - ('a', VERY_STRONGLY_CONNECTED), - (':', VERY_STRONGLY_CONNECTED), - ('23', VERY_STRONGLY_CONNECTED), - (')', VERY_STRONGLY_CONNECTED), - (':', STRONGLY_CONNECTED), - ('37', None), - (',', None), - ('}', None), - ]) + self._CheckPenalties( + tree, [ + ('a', None), + ('=', None), + ('{', None), + ("'x'", None), + (':', STRONGLY_CONNECTED), + ('42', None), + (',', None), + ('y', None), + ('(', UNBREAKABLE), + ('lambda', STRONGLY_CONNECTED), + ('a', VERY_STRONGLY_CONNECTED), + (':', VERY_STRONGLY_CONNECTED), + ('23', VERY_STRONGLY_CONNECTED), + (')', VERY_STRONGLY_CONNECTED), + (':', STRONGLY_CONNECTED), + ('37', None), + (',', None), + ('}', None), + ]) # Test list comprehension. code = textwrap.dedent(r""" [a for a in foo if a.x == 37] """) tree = self._ParseAndComputePenalties(code) - self._CheckPenalties(tree, [ - ('[', None), - ('a', None), - ('for', 0), - ('a', STRONGLY_CONNECTED), - ('in', STRONGLY_CONNECTED), - ('foo', STRONGLY_CONNECTED), - ('if', 0), - ('a', STRONGLY_CONNECTED), - ('.', VERY_STRONGLY_CONNECTED), - ('x', DOTTED_NAME), - ('==', STRONGLY_CONNECTED), - ('37', STRONGLY_CONNECTED), - (']', None), - ]) + self._CheckPenalties( + tree, [ + ('[', None), + ('a', None), + ('for', 0), + ('a', STRONGLY_CONNECTED), + ('in', STRONGLY_CONNECTED), + ('foo', STRONGLY_CONNECTED), + ('if', 0), + ('a', STRONGLY_CONNECTED), + ('.', VERY_STRONGLY_CONNECTED), + ('x', DOTTED_NAME), + ('==', STRONGLY_CONNECTED), + ('37', STRONGLY_CONNECTED), + (']', None), + ]) def testFuncCalls(self): code = 'foo(1, 2, 3)\n' tree = self._ParseAndComputePenalties(code) - self._CheckPenalties(tree, [ - ('foo', None), - ('(', UNBREAKABLE), - ('1', None), - (',', UNBREAKABLE), - ('2', None), - (',', UNBREAKABLE), - ('3', None), - (')', VERY_STRONGLY_CONNECTED), - ]) + self._CheckPenalties( + tree, [ + ('foo', None), + ('(', UNBREAKABLE), + ('1', None), + (',', UNBREAKABLE), + ('2', None), + (',', UNBREAKABLE), + ('3', None), + (')', VERY_STRONGLY_CONNECTED), + ]) # Now a method call, which has more than one trailer code = 'foo.bar.baz(1, 2, 3)\n' tree = self._ParseAndComputePenalties(code) - self._CheckPenalties(tree, [ - ('foo', None), - ('.', VERY_STRONGLY_CONNECTED), - ('bar', DOTTED_NAME), - ('.', VERY_STRONGLY_CONNECTED), - ('baz', DOTTED_NAME), - ('(', STRONGLY_CONNECTED), - ('1', None), - (',', UNBREAKABLE), - ('2', None), - (',', UNBREAKABLE), - ('3', None), - (')', VERY_STRONGLY_CONNECTED), - ]) + self._CheckPenalties( + tree, [ + ('foo', None), + ('.', VERY_STRONGLY_CONNECTED), + ('bar', DOTTED_NAME), + ('.', VERY_STRONGLY_CONNECTED), + ('baz', DOTTED_NAME), + ('(', STRONGLY_CONNECTED), + ('1', None), + (',', UNBREAKABLE), + ('2', None), + (',', UNBREAKABLE), + ('3', None), + (')', VERY_STRONGLY_CONNECTED), + ]) # Test single generator argument. code = 'max(i for i in xrange(10))\n' tree = self._ParseAndComputePenalties(code) - self._CheckPenalties(tree, [ - ('max', None), - ('(', UNBREAKABLE), - ('i', 0), - ('for', 0), - ('i', STRONGLY_CONNECTED), - ('in', STRONGLY_CONNECTED), - ('xrange', STRONGLY_CONNECTED), - ('(', UNBREAKABLE), - ('10', STRONGLY_CONNECTED), - (')', VERY_STRONGLY_CONNECTED), - (')', VERY_STRONGLY_CONNECTED), - ]) + self._CheckPenalties( + tree, [ + ('max', None), + ('(', UNBREAKABLE), + ('i', 0), + ('for', 0), + ('i', STRONGLY_CONNECTED), + ('in', STRONGLY_CONNECTED), + ('xrange', STRONGLY_CONNECTED), + ('(', UNBREAKABLE), + ('10', STRONGLY_CONNECTED), + (')', VERY_STRONGLY_CONNECTED), + (')', VERY_STRONGLY_CONNECTED), + ]) if __name__ == '__main__': diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 8a37f9535..4aceba3d0 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -50,8 +50,8 @@ def testContinuationAlignStyleStringConverter(self): 'VALIGN-RIGHT') with self.assertRaises(ValueError) as ctx: style._ContinuationAlignStyleStringConverter('blahblah') - self.assertIn("unknown continuation align style: 'blahblah'", - str(ctx.exception)) + self.assertIn( + "unknown continuation align style: 'blahblah'", str(ctx.exception)) def testStringListConverter(self): self.assertEqual(style._StringListConverter('foo, bar'), ['foo', 'bar']) @@ -136,7 +136,8 @@ def tearDownClass(cls): # pylint: disable=g-missing-super-call shutil.rmtree(cls.test_tmpdir) def testDefaultBasedOnStyle(self): - cfg = textwrap.dedent(u'''\ + cfg = textwrap.dedent( + u'''\ [style] continuation_indent_width = 20 ''') @@ -146,7 +147,8 @@ def testDefaultBasedOnStyle(self): self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) def testDefaultBasedOnPEP8Style(self): - cfg = textwrap.dedent(u'''\ + cfg = textwrap.dedent( + u'''\ [style] based_on_style = pep8 continuation_indent_width = 40 @@ -157,7 +159,8 @@ def testDefaultBasedOnPEP8Style(self): self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 40) def testDefaultBasedOnGoogleStyle(self): - cfg = textwrap.dedent(u'''\ + cfg = textwrap.dedent( + u'''\ [style] based_on_style = google continuation_indent_width = 20 @@ -168,7 +171,8 @@ def testDefaultBasedOnGoogleStyle(self): self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) def testDefaultBasedOnFacebookStyle(self): - cfg = textwrap.dedent(u'''\ + cfg = textwrap.dedent( + u'''\ [style] based_on_style = facebook continuation_indent_width = 20 @@ -179,7 +183,8 @@ def testDefaultBasedOnFacebookStyle(self): self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) def testBoolOptionValue(self): - cfg = textwrap.dedent(u'''\ + cfg = textwrap.dedent( + u'''\ [style] based_on_style = pep8 SPLIT_BEFORE_NAMED_ASSIGNS=False @@ -192,7 +197,8 @@ def testBoolOptionValue(self): self.assertEqual(cfg['SPLIT_BEFORE_LOGICAL_OPERATOR'], True) def testStringListOptionValue(self): - cfg = textwrap.dedent(u'''\ + cfg = textwrap.dedent( + u'''\ [style] based_on_style = pep8 I18N_FUNCTION_CALL = N_, V_, T_ @@ -218,7 +224,8 @@ def testErrorNoStyleSection(self): style.CreateStyleFromConfig(filepath) def testErrorUnknownStyleOption(self): - cfg = textwrap.dedent(u'''\ + cfg = textwrap.dedent( + u'''\ [style] indent_width=2 hummus=2 @@ -235,7 +242,7 @@ def testPyprojectTomlNoYapfSection(self): return filepath = os.path.join(self.test_tmpdir, 'pyproject.toml') - _ = open(filepath, 'w') + _ = open(filepath, 'w') with self.assertRaisesRegex(style.StyleConfigError, 'Unable to find section'): style.CreateStyleFromConfig(filepath) @@ -246,7 +253,8 @@ def testPyprojectTomlParseYapfSection(self): except ImportError: return - cfg = textwrap.dedent(u'''\ + cfg = textwrap.dedent( + u'''\ [tool.yapf] based_on_style = "pep8" continuation_indent_width = 40 @@ -276,12 +284,12 @@ def testDefaultBasedOnStyle(self): self.assertEqual(cfg['INDENT_WIDTH'], 2) def testDefaultBasedOnStyleBadDict(self): - self.assertRaisesRegex(style.StyleConfigError, 'Unknown style option', - style.CreateStyleFromConfig, - {'based_on_styl': 'pep8'}) - self.assertRaisesRegex(style.StyleConfigError, 'not a valid', - style.CreateStyleFromConfig, - {'INDENT_WIDTH': 'FOUR'}) + self.assertRaisesRegex( + style.StyleConfigError, 'Unknown style option', + style.CreateStyleFromConfig, {'based_on_styl': 'pep8'}) + self.assertRaisesRegex( + style.StyleConfigError, 'not a valid', style.CreateStyleFromConfig, + {'INDENT_WIDTH': 'FOUR'}) class StyleFromCommandLine(yapf_test_helper.YAPFTest): @@ -315,12 +323,15 @@ def testDefaultBasedOnDetaultTypeString(self): self.assertIsInstance(cfg, dict) def testDefaultBasedOnStyleBadString(self): - self.assertRaisesRegex(style.StyleConfigError, 'Unknown style option', - style.CreateStyleFromConfig, '{based_on_styl: pep8}') - self.assertRaisesRegex(style.StyleConfigError, 'not a valid', - style.CreateStyleFromConfig, '{INDENT_WIDTH: FOUR}') - self.assertRaisesRegex(style.StyleConfigError, 'Invalid style dict', - style.CreateStyleFromConfig, '{based_on_style: pep8') + self.assertRaisesRegex( + style.StyleConfigError, 'Unknown style option', + style.CreateStyleFromConfig, '{based_on_styl: pep8}') + self.assertRaisesRegex( + style.StyleConfigError, 'not a valid', style.CreateStyleFromConfig, + '{INDENT_WIDTH: FOUR}') + self.assertRaisesRegex( + style.StyleConfigError, 'Invalid style dict', + style.CreateStyleFromConfig, '{based_on_style: pep8') class StyleHelp(yapf_test_helper.YAPFTest): diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index 8616169c9..222153db4 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -35,9 +35,11 @@ def _CheckFormatTokenSubtypes(self, llines, list_of_expected): """ actual = [] for lline in llines: - filtered_values = [(ft.value, ft.subtypes) - for ft in lline.tokens - if ft.name not in pytree_utils.NONSEMANTIC_TOKENS] + filtered_values = [ + (ft.value, ft.subtypes) + for ft in lline.tokens + if ft.name not in pytree_utils.NONSEMANTIC_TOKENS + ] if filtered_values: actual.append(filtered_values) @@ -45,242 +47,263 @@ def _CheckFormatTokenSubtypes(self, llines, list_of_expected): def testFuncDefDefaultAssign(self): self.maxDiff = None # pylint: disable=invalid-name - code = textwrap.dedent(r""" + code = textwrap.dedent( + r""" def foo(a=37, *b, **c): return -x[:42] """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes(llines, [ - [ - ('def', {subtypes.NONE}), - ('foo', {subtypes.FUNC_DEF}), - ('(', {subtypes.NONE}), - ('a', { - subtypes.NONE, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - subtypes.PARAMETER_START, - }), - ('=', { - subtypes.DEFAULT_OR_NAMED_ASSIGN, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - }), - ('37', { - subtypes.NONE, - subtypes.PARAMETER_STOP, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - }), - (',', {subtypes.NONE}), - ('*', { - subtypes.PARAMETER_START, - subtypes.VARARGS_STAR, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - }), - ('b', { - subtypes.NONE, - subtypes.PARAMETER_STOP, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - }), - (',', {subtypes.NONE}), - ('**', { - subtypes.PARAMETER_START, - subtypes.KWARGS_STAR_STAR, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - }), - ('c', { - subtypes.NONE, - subtypes.PARAMETER_STOP, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - }), - (')', {subtypes.NONE}), - (':', {subtypes.NONE}), - ], - [ - ('return', {subtypes.NONE}), - ('-', {subtypes.UNARY_OPERATOR}), - ('x', {subtypes.NONE}), - ('[', {subtypes.SUBSCRIPT_BRACKET}), - (':', {subtypes.SUBSCRIPT_COLON}), - ('42', {subtypes.NONE}), - (']', {subtypes.SUBSCRIPT_BRACKET}), - ], - ]) + self._CheckFormatTokenSubtypes( + llines, [ + [ + ('def', {subtypes.NONE}), + ('foo', {subtypes.FUNC_DEF}), + ('(', {subtypes.NONE}), + ( + 'a', { + subtypes.NONE, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + subtypes.PARAMETER_START, + }), + ( + '=', { + subtypes.DEFAULT_OR_NAMED_ASSIGN, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + ( + '37', { + subtypes.NONE, + subtypes.PARAMETER_STOP, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + (',', {subtypes.NONE}), + ( + '*', { + subtypes.PARAMETER_START, + subtypes.VARARGS_STAR, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + ( + 'b', { + subtypes.NONE, + subtypes.PARAMETER_STOP, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + (',', {subtypes.NONE}), + ( + '**', { + subtypes.PARAMETER_START, + subtypes.KWARGS_STAR_STAR, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + ( + 'c', { + subtypes.NONE, + subtypes.PARAMETER_STOP, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + (')', {subtypes.NONE}), + (':', {subtypes.NONE}), + ], + [ + ('return', {subtypes.NONE}), + ('-', {subtypes.UNARY_OPERATOR}), + ('x', {subtypes.NONE}), + ('[', {subtypes.SUBSCRIPT_BRACKET}), + (':', {subtypes.SUBSCRIPT_COLON}), + ('42', {subtypes.NONE}), + (']', {subtypes.SUBSCRIPT_BRACKET}), + ], + ]) def testFuncCallWithDefaultAssign(self): - code = textwrap.dedent(r""" + code = textwrap.dedent(r""" foo(x, a='hello world') """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes(llines, [ - [ - ('foo', {subtypes.NONE}), - ('(', {subtypes.NONE}), - ('x', { - subtypes.NONE, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - }), - (',', {subtypes.NONE}), - ('a', { - subtypes.NONE, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - }), - ('=', {subtypes.DEFAULT_OR_NAMED_ASSIGN}), - ("'hello world'", {subtypes.NONE}), - (')', {subtypes.NONE}), - ], - ]) + self._CheckFormatTokenSubtypes( + llines, [ + [ + ('foo', {subtypes.NONE}), + ('(', {subtypes.NONE}), + ( + 'x', { + subtypes.NONE, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + (',', {subtypes.NONE}), + ( + 'a', { + subtypes.NONE, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + ('=', {subtypes.DEFAULT_OR_NAMED_ASSIGN}), + ("'hello world'", {subtypes.NONE}), + (')', {subtypes.NONE}), + ], + ]) def testSetComprehension(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ def foo(strs): return {s.lower() for s in strs} """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes(llines, [ - [ - ('def', {subtypes.NONE}), - ('foo', {subtypes.FUNC_DEF}), - ('(', {subtypes.NONE}), - ('strs', { - subtypes.NONE, - subtypes.PARAMETER_START, - subtypes.PARAMETER_STOP, - }), - (')', {subtypes.NONE}), - (':', {subtypes.NONE}), - ], - [ - ('return', {subtypes.NONE}), - ('{', {subtypes.NONE}), - ('s', {subtypes.COMP_EXPR}), - ('.', {subtypes.COMP_EXPR}), - ('lower', {subtypes.COMP_EXPR}), - ('(', {subtypes.COMP_EXPR}), - (')', {subtypes.COMP_EXPR}), - ('for', { - subtypes.DICT_SET_GENERATOR, - subtypes.COMP_FOR, - }), - ('s', {subtypes.COMP_FOR}), - ('in', {subtypes.COMP_FOR}), - ('strs', {subtypes.COMP_FOR}), - ('}', {subtypes.NONE}), - ], - ]) + self._CheckFormatTokenSubtypes( + llines, [ + [ + ('def', {subtypes.NONE}), + ('foo', {subtypes.FUNC_DEF}), + ('(', {subtypes.NONE}), + ( + 'strs', { + subtypes.NONE, + subtypes.PARAMETER_START, + subtypes.PARAMETER_STOP, + }), + (')', {subtypes.NONE}), + (':', {subtypes.NONE}), + ], + [ + ('return', {subtypes.NONE}), + ('{', {subtypes.NONE}), + ('s', {subtypes.COMP_EXPR}), + ('.', {subtypes.COMP_EXPR}), + ('lower', {subtypes.COMP_EXPR}), + ('(', {subtypes.COMP_EXPR}), + (')', {subtypes.COMP_EXPR}), + ('for', { + subtypes.DICT_SET_GENERATOR, + subtypes.COMP_FOR, + }), + ('s', {subtypes.COMP_FOR}), + ('in', {subtypes.COMP_FOR}), + ('strs', {subtypes.COMP_FOR}), + ('}', {subtypes.NONE}), + ], + ]) def testUnaryNotOperator(self): - code = textwrap.dedent("""\ + code = textwrap.dedent("""\ not a """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes(llines, [[('not', {subtypes.UNARY_OPERATOR}), - ('a', {subtypes.NONE})]]) + self._CheckFormatTokenSubtypes( + llines, [[('not', {subtypes.UNARY_OPERATOR}), ('a', {subtypes.NONE})]]) def testBitwiseOperators(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ x = ((a | (b ^ 3) & c) << 3) >> 1 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes(llines, [ - [ - ('x', {subtypes.NONE}), - ('=', {subtypes.ASSIGN_OPERATOR}), - ('(', {subtypes.NONE}), - ('(', {subtypes.NONE}), - ('a', {subtypes.NONE}), - ('|', {subtypes.BINARY_OPERATOR}), - ('(', {subtypes.NONE}), - ('b', {subtypes.NONE}), - ('^', {subtypes.BINARY_OPERATOR}), - ('3', {subtypes.NONE}), - (')', {subtypes.NONE}), - ('&', {subtypes.BINARY_OPERATOR}), - ('c', {subtypes.NONE}), - (')', {subtypes.NONE}), - ('<<', {subtypes.BINARY_OPERATOR}), - ('3', {subtypes.NONE}), - (')', {subtypes.NONE}), - ('>>', {subtypes.BINARY_OPERATOR}), - ('1', {subtypes.NONE}), - ], - ]) + self._CheckFormatTokenSubtypes( + llines, [ + [ + ('x', {subtypes.NONE}), + ('=', {subtypes.ASSIGN_OPERATOR}), + ('(', {subtypes.NONE}), + ('(', {subtypes.NONE}), + ('a', {subtypes.NONE}), + ('|', {subtypes.BINARY_OPERATOR}), + ('(', {subtypes.NONE}), + ('b', {subtypes.NONE}), + ('^', {subtypes.BINARY_OPERATOR}), + ('3', {subtypes.NONE}), + (')', {subtypes.NONE}), + ('&', {subtypes.BINARY_OPERATOR}), + ('c', {subtypes.NONE}), + (')', {subtypes.NONE}), + ('<<', {subtypes.BINARY_OPERATOR}), + ('3', {subtypes.NONE}), + (')', {subtypes.NONE}), + ('>>', {subtypes.BINARY_OPERATOR}), + ('1', {subtypes.NONE}), + ], + ]) def testArithmeticOperators(self): - code = textwrap.dedent("""\ + code = textwrap.dedent( + """\ x = ((a + (b - 3) * (1 % c) @ d) / 3) // 1 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes(llines, [ - [ - ('x', {subtypes.NONE}), - ('=', {subtypes.ASSIGN_OPERATOR}), - ('(', {subtypes.NONE}), - ('(', {subtypes.NONE}), - ('a', {subtypes.NONE}), - ('+', {subtypes.BINARY_OPERATOR}), - ('(', {subtypes.NONE}), - ('b', {subtypes.NONE}), - ('-', { - subtypes.BINARY_OPERATOR, - subtypes.SIMPLE_EXPRESSION, - }), - ('3', {subtypes.NONE}), - (')', {subtypes.NONE}), - ('*', {subtypes.BINARY_OPERATOR}), - ('(', {subtypes.NONE}), - ('1', {subtypes.NONE}), - ('%', { - subtypes.BINARY_OPERATOR, - subtypes.SIMPLE_EXPRESSION, - }), - ('c', {subtypes.NONE}), - (')', {subtypes.NONE}), - ('@', {subtypes.BINARY_OPERATOR}), - ('d', {subtypes.NONE}), - (')', {subtypes.NONE}), - ('/', {subtypes.BINARY_OPERATOR}), - ('3', {subtypes.NONE}), - (')', {subtypes.NONE}), - ('//', {subtypes.BINARY_OPERATOR}), - ('1', {subtypes.NONE}), - ], - ]) + self._CheckFormatTokenSubtypes( + llines, [ + [ + ('x', {subtypes.NONE}), + ('=', {subtypes.ASSIGN_OPERATOR}), + ('(', {subtypes.NONE}), + ('(', {subtypes.NONE}), + ('a', {subtypes.NONE}), + ('+', {subtypes.BINARY_OPERATOR}), + ('(', {subtypes.NONE}), + ('b', {subtypes.NONE}), + ('-', { + subtypes.BINARY_OPERATOR, + subtypes.SIMPLE_EXPRESSION, + }), + ('3', {subtypes.NONE}), + (')', {subtypes.NONE}), + ('*', {subtypes.BINARY_OPERATOR}), + ('(', {subtypes.NONE}), + ('1', {subtypes.NONE}), + ('%', { + subtypes.BINARY_OPERATOR, + subtypes.SIMPLE_EXPRESSION, + }), + ('c', {subtypes.NONE}), + (')', {subtypes.NONE}), + ('@', {subtypes.BINARY_OPERATOR}), + ('d', {subtypes.NONE}), + (')', {subtypes.NONE}), + ('/', {subtypes.BINARY_OPERATOR}), + ('3', {subtypes.NONE}), + (')', {subtypes.NONE}), + ('//', {subtypes.BINARY_OPERATOR}), + ('1', {subtypes.NONE}), + ], + ]) def testSubscriptColon(self): - code = textwrap.dedent("""\ + code = textwrap.dedent("""\ x[0:42:1] """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes(llines, [ - [ - ('x', {subtypes.NONE}), - ('[', {subtypes.SUBSCRIPT_BRACKET}), - ('0', {subtypes.NONE}), - (':', {subtypes.SUBSCRIPT_COLON}), - ('42', {subtypes.NONE}), - (':', {subtypes.SUBSCRIPT_COLON}), - ('1', {subtypes.NONE}), - (']', {subtypes.SUBSCRIPT_BRACKET}), - ], - ]) + self._CheckFormatTokenSubtypes( + llines, [ + [ + ('x', {subtypes.NONE}), + ('[', {subtypes.SUBSCRIPT_BRACKET}), + ('0', {subtypes.NONE}), + (':', {subtypes.SUBSCRIPT_COLON}), + ('42', {subtypes.NONE}), + (':', {subtypes.SUBSCRIPT_COLON}), + ('1', {subtypes.NONE}), + (']', {subtypes.SUBSCRIPT_BRACKET}), + ], + ]) def testFunctionCallWithStarExpression(self): - code = textwrap.dedent("""\ + code = textwrap.dedent("""\ [a, *b] """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes(llines, [ - [ - ('[', {subtypes.NONE}), - ('a', {subtypes.NONE}), - (',', {subtypes.NONE}), - ('*', { - subtypes.UNARY_OPERATOR, - subtypes.VARARGS_STAR, - }), - ('b', {subtypes.NONE}), - (']', {subtypes.NONE}), - ], - ]) + self._CheckFormatTokenSubtypes( + llines, [ + [ + ('[', {subtypes.NONE}), + ('a', {subtypes.NONE}), + (',', {subtypes.NONE}), + ('*', { + subtypes.UNARY_OPERATOR, + subtypes.VARARGS_STAR, + }), + ('b', {subtypes.NONE}), + (']', {subtypes.NONE}), + ], + ]) if __name__ == '__main__': diff --git a/yapftests/utils.py b/yapftests/utils.py index 268b8c43a..d10a0982c 100644 --- a/yapftests/utils.py +++ b/yapftests/utils.py @@ -42,15 +42,16 @@ def stdout_redirector(stream): # pylint: disable=invalid-name # Note: `buffering` is set to -1 despite documentation of NamedTemporaryFile # says None. This is probably a problem with the python documentation. @contextlib.contextmanager -def NamedTempFile(mode='w+b', - buffering=-1, - encoding=None, - errors=None, - newline=None, - suffix=None, - prefix=None, - dirname=None, - text=False): +def NamedTempFile( + mode='w+b', + buffering=-1, + encoding=None, + errors=None, + newline=None, + suffix=None, + prefix=None, + dirname=None, + text=False): """Context manager creating a new temporary file in text mode.""" if sys.version_info < (3, 5): # covers also python 2 if suffix is None: @@ -72,18 +73,11 @@ def NamedTempFile(mode='w+b', @contextlib.contextmanager -def TempFileContents(dirname, - contents, - encoding='utf-8', - newline='', - suffix=None): +def TempFileContents( + dirname, contents, encoding='utf-8', newline='', suffix=None): # Note: NamedTempFile properly handles unicode encoding when using mode='w' - with NamedTempFile( - dirname=dirname, - mode='w', - encoding=encoding, - newline=newline, - suffix=suffix) as (f, fname): + with NamedTempFile(dirname=dirname, mode='w', encoding=encoding, + newline=newline, suffix=suffix) as (f, fname): f.write(contents) f.flush() yield fname diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 2330f4e18..865a67e3b 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -54,10 +54,11 @@ def testSimple(self): self._Check(unformatted_code, unformatted_code) def testNoEndingNewline(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ if True: pass""") - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if True: pass """) @@ -65,7 +66,7 @@ def testNoEndingNewline(self): @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testPrintAfterPeriod(self): - unformatted_code = textwrap.dedent("""a.print\n""") + unformatted_code = textwrap.dedent("""a.print\n""") expected_formatted_code = textwrap.dedent("""a.print\n""") self._Check(unformatted_code, expected_formatted_code) @@ -80,7 +81,7 @@ def tearDown(self): # pylint: disable=g-missing-super-call def assertCodeEqual(self, expected_code, code): if code != expected_code: - msg = 'Code format mismatch:\n' + msg = 'Code format mismatch:\n' msg += 'Expected:\n >' msg += '\n > '.join(expected_code.splitlines()) msg += '\nActual:\n >' @@ -89,15 +90,18 @@ def assertCodeEqual(self, expected_code, code): self.fail(msg) def testFormatFile(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent( + u"""\ if True: pass """) - expected_formatted_code_pep8 = textwrap.dedent(u"""\ + expected_formatted_code_pep8 = textwrap.dedent( + u"""\ if True: pass """) - expected_formatted_code_yapf = textwrap.dedent(u"""\ + expected_formatted_code_yapf = textwrap.dedent( + u"""\ if True: pass """) @@ -109,7 +113,8 @@ def testFormatFile(self): self.assertCodeEqual(expected_formatted_code_yapf, formatted_code) def testDisableLinesPattern(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent( + u"""\ if a: b # yapf: disable @@ -117,7 +122,8 @@ def testDisableLinesPattern(self): if h: i """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent( + u"""\ if a: b # yapf: disable @@ -130,7 +136,8 @@ def testDisableLinesPattern(self): self.assertCodeEqual(expected_formatted_code, formatted_code) def testDisableAndReenableLinesPattern(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent( + u"""\ if a: b # yapf: disable @@ -139,7 +146,8 @@ def testDisableAndReenableLinesPattern(self): if h: i """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent( + u"""\ if a: b # yapf: disable @@ -153,7 +161,8 @@ def testDisableAndReenableLinesPattern(self): self.assertCodeEqual(expected_formatted_code, formatted_code) def testDisablePartOfMultilineComment(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent( + u"""\ if a: b # This is a multiline comment that disables YAPF. @@ -165,7 +174,8 @@ def testDisablePartOfMultilineComment(self): if h: i """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent( + u"""\ if a: b # This is a multiline comment that disables YAPF. @@ -180,7 +190,8 @@ def testDisablePartOfMultilineComment(self): formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(expected_formatted_code, formatted_code) - code = textwrap.dedent(u"""\ + code = textwrap.dedent( + u"""\ def foo_function(): # some comment # yapf: disable @@ -197,7 +208,8 @@ def foo_function(): self.assertCodeEqual(code, formatted_code) def testEnabledDisabledSameComment(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent( + u"""\ # yapf: disable a(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, ccccccccccccccccccccccccccccccc, ddddddddddddddddddddddd, eeeeeeeeeeeeeeeeeeeeeeeeeee) # yapf: enable @@ -210,21 +222,24 @@ def testEnabledDisabledSameComment(self): self.assertCodeEqual(code, formatted_code) def testFormatFileLinesSelection(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent( + u"""\ if a: b if f: g if h: i """) - expected_formatted_code_lines1and2 = textwrap.dedent(u"""\ + expected_formatted_code_lines1and2 = textwrap.dedent( + u"""\ if a: b if f: g if h: i """) - expected_formatted_code_lines3 = textwrap.dedent(u"""\ + expected_formatted_code_lines3 = textwrap.dedent( + u"""\ if a: b if f: g @@ -240,7 +255,8 @@ def testFormatFileLinesSelection(self): self.assertCodeEqual(expected_formatted_code_lines3, formatted_code) def testFormatFileDiff(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent( + u"""\ if True: pass """) @@ -250,7 +266,7 @@ def testFormatFileDiff(self): def testFormatFileInPlace(self): unformatted_code = u'True==False\n' - formatted_code = u'True == False\n' + formatted_code = u'True == False\n' with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: result, _, _ = yapf_api.FormatFile(filepath, in_place=True) self.assertEqual(result, None) @@ -268,17 +284,19 @@ def testFormatFileInPlace(self): print_diff=True) def testNoFile(self): - stream = py3compat.StringIO() + stream = py3compat.StringIO() handler = logging.StreamHandler(stream) - logger = logging.getLogger('mylogger') + logger = logging.getLogger('mylogger') logger.addHandler(handler) self.assertRaises( IOError, yapf_api.FormatFile, 'not_a_file.py', logger=logger.error) - self.assertEqual(stream.getvalue(), - "[Errno 2] No such file or directory: 'not_a_file.py'\n") + self.assertEqual( + stream.getvalue(), + "[Errno 2] No such file or directory: 'not_a_file.py'\n") def testCommentsUnformatted(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent( + u"""\ foo = [# A list of things # bork 'one', @@ -290,7 +308,8 @@ def testCommentsUnformatted(self): self.assertCodeEqual(code, formatted_code) def testDisabledHorizontalFormattingOnNewLine(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent( + u"""\ # yapf: disable a = [ 1] @@ -301,12 +320,14 @@ def testDisabledHorizontalFormattingOnNewLine(self): self.assertCodeEqual(code, formatted_code) def testSplittingSemicolonStatements(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent( + u"""\ def f(): x = y + 42 ; z = n * 42 if True: a += 1 ; b += 1; c += 1 """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent( + u"""\ def f(): x = y + 42 z = n * 42 @@ -320,12 +341,14 @@ def f(): self.assertCodeEqual(expected_formatted_code, formatted_code) def testSemicolonStatementsDisabled(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent( + u"""\ def f(): x = y + 42 ; z = n * 42 # yapf: disable if True: a += 1 ; b += 1; c += 1 """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent( + u"""\ def f(): x = y + 42 ; z = n * 42 # yapf: disable if True: @@ -338,7 +361,8 @@ def f(): self.assertCodeEqual(expected_formatted_code, formatted_code) def testDisabledSemiColonSeparatedStatements(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent( + u"""\ # yapf: disable if True: a ; b """) @@ -347,7 +371,8 @@ def testDisabledSemiColonSeparatedStatements(self): self.assertCodeEqual(code, formatted_code) def testDisabledMultilineStringInDictionary(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent( + u"""\ # yapf: disable A = [ @@ -366,7 +391,8 @@ def testDisabledMultilineStringInDictionary(self): self.assertCodeEqual(code, formatted_code) def testDisabledWithPrecedingText(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent( + u"""\ # TODO(fix formatting): yapf: disable A = [ @@ -402,11 +428,8 @@ def setUpClass(cls): # pylint: disable=g-missing-super-call def tearDownClass(cls): # pylint: disable=g-missing-super-call shutil.rmtree(cls.test_tmpdir) - def assertYapfReformats(self, - unformatted, - expected, - extra_options=None, - env=None): + def assertYapfReformats( + self, unformatted, expected, extra_options=None, env=None): """Check that yapf reformats the given code as expected. Invokes yapf in a subprocess, piping the unformatted code into its stdin. @@ -419,7 +442,7 @@ def assertYapfReformats(self, env: dict of environment variables. """ cmdline = YAPF_BINARY + (extra_options or []) - p = subprocess.Popen( + p = subprocess.Popen( cmdline, stdout=subprocess.PIPE, stdin=subprocess.PIPE, @@ -432,27 +455,30 @@ def assertYapfReformats(self, @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testUnicodeEncodingPipedToFile(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent( + u"""\ def foo(): print('⇒') """) - with utils.NamedTempFile( - dirname=self.test_tmpdir, suffix='.py') as (out, _): - with utils.TempFileContents( - self.test_tmpdir, unformatted_code, suffix='.py') as filepath: + with utils.NamedTempFile(dirname=self.test_tmpdir, + suffix='.py') as (out, _): + with utils.TempFileContents(self.test_tmpdir, unformatted_code, + suffix='.py') as filepath: subprocess.check_call(YAPF_BINARY + ['--diff', filepath], stdout=out) def testInPlaceReformatting(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent( + u"""\ def foo(): x = 37 """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo(): x = 37 """) - with utils.TempFileContents( - self.test_tmpdir, unformatted_code, suffix='.py') as filepath: + with utils.TempFileContents(self.test_tmpdir, unformatted_code, + suffix='.py') as filepath: p = subprocess.Popen(YAPF_BINARY + ['--in-place', filepath]) p.wait() with io.open(filepath, mode='r', newline='') as fd: @@ -460,10 +486,10 @@ def foo(): self.assertEqual(reformatted_code, expected_formatted_code) def testInPlaceReformattingBlank(self): - unformatted_code = u'\n\n' + unformatted_code = u'\n\n' expected_formatted_code = u'\n' - with utils.TempFileContents( - self.test_tmpdir, unformatted_code, suffix='.py') as filepath: + with utils.TempFileContents(self.test_tmpdir, unformatted_code, + suffix='.py') as filepath: p = subprocess.Popen(YAPF_BINARY + ['--in-place', filepath]) p.wait() with io.open(filepath, mode='r', encoding='utf-8', newline='') as fd: @@ -471,10 +497,10 @@ def testInPlaceReformattingBlank(self): self.assertEqual(reformatted_code, expected_formatted_code) def testInPlaceReformattingEmpty(self): - unformatted_code = u'' + unformatted_code = u'' expected_formatted_code = u'' - with utils.TempFileContents( - self.test_tmpdir, unformatted_code, suffix='.py') as filepath: + with utils.TempFileContents(self.test_tmpdir, unformatted_code, + suffix='.py') as filepath: p = subprocess.Popen(YAPF_BINARY + ['--in-place', filepath]) p.wait() with io.open(filepath, mode='r', encoding='utf-8', newline='') as fd: @@ -482,31 +508,37 @@ def testInPlaceReformattingEmpty(self): self.assertEqual(reformatted_code, expected_formatted_code) def testReadFromStdin(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo(): x = 37 """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo(): x = 37 """) self.assertYapfReformats(unformatted_code, expected_formatted_code) def testReadFromStdinWithEscapedStrings(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ s = "foo\\nbar" """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ s = "foo\\nbar" """) self.assertYapfReformats(unformatted_code, expected_formatted_code) def testSetYapfStyle(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo(): # trail x = 37 """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo(): # trail x = 37 """) @@ -516,15 +548,18 @@ def foo(): # trail extra_options=['--style=yapf']) def testSetCustomStyleBasedOnYapf(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo(): # trail x = 37 """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo(): # trail x = 37 """) - style_file = textwrap.dedent(u'''\ + style_file = textwrap.dedent( + u'''\ [style] based_on_style = yapf spaces_before_comment = 4 @@ -536,15 +571,18 @@ def foo(): # trail extra_options=['--style={0}'.format(stylepath)]) def testSetCustomStyleSpacesBeforeComment(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ a_very_long_statement_that_extends_way_beyond # Comment short # This is a shorter statement """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ a_very_long_statement_that_extends_way_beyond # Comment short # This is a shorter statement """) # noqa - style_file = textwrap.dedent(u'''\ + style_file = textwrap.dedent( + u'''\ [style] spaces_before_comment = 15, 20 ''') @@ -555,26 +593,28 @@ def testSetCustomStyleSpacesBeforeComment(self): extra_options=['--style={0}'.format(stylepath)]) def testReadSingleLineCodeFromStdin(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ if True: pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if True: pass """) self.assertYapfReformats(unformatted_code, expected_formatted_code) def testEncodingVerification(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent( + u"""\ '''The module docstring.''' # -*- coding: utf-8 -*- def f(): x = 37 """) - with utils.NamedTempFile( - suffix='.py', dirname=self.test_tmpdir) as (out, _): - with utils.TempFileContents( - self.test_tmpdir, unformatted_code, suffix='.py') as filepath: + with utils.NamedTempFile(suffix='.py', + dirname=self.test_tmpdir) as (out, _): + with utils.TempFileContents(self.test_tmpdir, unformatted_code, + suffix='.py') as filepath: try: subprocess.check_call(YAPF_BINARY + ['--diff', filepath], stdout=out) except subprocess.CalledProcessError as e: @@ -582,7 +622,8 @@ def f(): self.assertEqual(e.returncode, 1) # pylint: disable=g-assert-in-except # noqa def testReformattingSpecificLines(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass @@ -592,7 +633,8 @@ def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -612,14 +654,16 @@ def g(): extra_options=['--lines', '1-2']) def testOmitFormattingLinesBeforeDisabledFunctionComment(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ import sys # Comment def some_func(x): x = ["badly" , "formatted","line" ] """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ import sys # Comment @@ -632,7 +676,8 @@ def some_func(x): extra_options=['--lines', '5-5']) def testReformattingSkippingLines(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass @@ -643,7 +688,8 @@ def g(): pass # yapf: enable """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -659,7 +705,8 @@ def g(): self.assertYapfReformats(unformatted_code, expected_formatted_code) def testReformattingSkippingToEndOfFile(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass @@ -676,7 +723,8 @@ def e(): 'bbbbbbb'): pass """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -698,7 +746,8 @@ def e(): self.assertYapfReformats(unformatted_code, expected_formatted_code) def testReformattingSkippingSingleLine(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass @@ -707,7 +756,8 @@ def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): # yapf: disable pass """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -721,13 +771,15 @@ def g(): self.assertYapfReformats(unformatted_code, expected_formatted_code) def testDisableWholeDataStructure(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ A = set([ 'hello', 'world', ]) # yapf: disable """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ A = set([ 'hello', 'world', @@ -736,14 +788,16 @@ def testDisableWholeDataStructure(self): self.assertYapfReformats(unformatted_code, expected_formatted_code) def testDisableButAdjustIndentations(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class SplitPenaltyTest(unittest.TestCase): def testUnbreakable(self): self._CheckPenalties(tree, [ ]) # yapf: disable """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class SplitPenaltyTest(unittest.TestCase): def testUnbreakable(self): @@ -753,7 +807,8 @@ def testUnbreakable(self): self.assertYapfReformats(unformatted_code, expected_formatted_code) def testRetainingHorizontalWhitespace(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass @@ -762,7 +817,8 @@ def g(): if (xxxxxxxxxxxx.yyyyyyyy (zzzzzzzzzzzzz [0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): # yapf: disable pass """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -776,7 +832,8 @@ def g(): self.assertYapfReformats(unformatted_code, expected_formatted_code) def testRetainingVerticalWhitespace(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass @@ -788,7 +845,8 @@ def g(): pass """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -806,7 +864,8 @@ def g(): expected_formatted_code, extra_options=['--lines', '1-2']) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if a: b @@ -823,7 +882,8 @@ def g(): # trailing whitespace """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if a: b @@ -843,7 +903,8 @@ def g(): expected_formatted_code, extra_options=['--lines', '3-3', '--lines', '13-13']) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ ''' docstring @@ -856,7 +917,7 @@ def g(): unformatted_code, unformatted_code, extra_options=['--lines', '2-2']) def testVerticalSpacingWithCommentWithContinuationMarkers(self): - unformatted_code = """\ + unformatted_code = """\ # \\ # \\ # \\ @@ -878,13 +939,15 @@ def testVerticalSpacingWithCommentWithContinuationMarkers(self): extra_options=['--lines', '1-1']) def testRetainingSemicolonsWhenSpecifyingLines(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ a = line_to_format def f(): x = y + 42; z = n * 42 if True: a += 1 ; b += 1 ; c += 1 """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ a = line_to_format def f(): x = y + 42; z = n * 42 @@ -896,7 +959,8 @@ def f(): extra_options=['--lines', '1-1']) def testDisabledMultilineStrings(self): - unformatted_code = textwrap.dedent('''\ + unformatted_code = textwrap.dedent( + '''\ foo=42 def f(): email_text += """This is a really long docstring that goes over the column limit and is multi-line.

@@ -906,7 +970,8 @@ def f(): """ ''') # noqa - expected_formatted_code = textwrap.dedent('''\ + expected_formatted_code = textwrap.dedent( + '''\ foo = 42 def f(): email_text += """This is a really long docstring that goes over the column limit and is multi-line.

@@ -922,7 +987,8 @@ def f(): extra_options=['--lines', '1-1']) def testDisableWhenSpecifyingLines(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ # yapf: disable A = set([ 'hello', @@ -934,7 +1000,8 @@ def testDisableWhenSpecifyingLines(self): 'world', ]) # yapf: disable """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ # yapf: disable A = set([ 'hello', @@ -952,7 +1019,8 @@ def testDisableWhenSpecifyingLines(self): extra_options=['--lines', '1-10']) def testDisableFormattingInDataLiteral(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def horrible(): oh_god() why_would_you() @@ -971,7 +1039,8 @@ def still_horrible(): 'that' ] """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def horrible(): oh_god() why_would_you() @@ -992,7 +1061,8 @@ def still_horrible(): extra_options=['--lines', '14-15']) def testRetainVerticalFormattingBetweenDisabledAndEnabledLines(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class A(object): def aaaaaaaaaaaaa(self): c = bbbbbbbbb.ccccccccc('challenge', 0, 1, 10) @@ -1003,7 +1073,8 @@ def aaaaaaaaaaaaa(self): gggggggggggg.hhhhhhhhh(c, c.ffffffffffff)) iiiii = jjjjjjjjjjjjjj.iiiii """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class A(object): def aaaaaaaaaaaaa(self): c = bbbbbbbbb.ccccccccc('challenge', 0, 1, 10) @@ -1018,7 +1089,8 @@ def aaaaaaaaaaaaa(self): extra_options=['--lines', '4-7']) def testRetainVerticalFormattingBetweenDisabledLines(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class A(object): def aaaaaaaaaaaaa(self): pass @@ -1027,7 +1099,8 @@ def aaaaaaaaaaaaa(self): def bbbbbbbbbbbbb(self): # 5 pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class A(object): def aaaaaaaaaaaaa(self): pass @@ -1042,7 +1115,8 @@ def bbbbbbbbbbbbb(self): # 5 extra_options=['--lines', '4-4']) def testFormatLinesSpecifiedInMiddleOfExpression(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ class A(object): def aaaaaaaaaaaaa(self): c = bbbbbbbbb.ccccccccc('challenge', 0, 1, 10) @@ -1053,7 +1127,8 @@ def aaaaaaaaaaaaa(self): gggggggggggg.hhhhhhhhh(c, c.ffffffffffff)) iiiii = jjjjjjjjjjjjjj.iiiii """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ class A(object): def aaaaaaaaaaaaa(self): c = bbbbbbbbb.ccccccccc('challenge', 0, 1, 10) @@ -1068,7 +1143,8 @@ def aaaaaaaaaaaaa(self): extra_options=['--lines', '5-6']) def testCommentFollowingMultilineString(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo(): '''First line. Second line. @@ -1076,7 +1152,8 @@ def foo(): x = '''hello world''' # second comment return 42 # another comment """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo(): '''First line. Second line. @@ -1091,12 +1168,14 @@ def foo(): def testDedentClosingBracket(self): # no line-break on the first argument, not dedenting closing brackets - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def overly_long_function_name(first_argument_on_the_same_line, second_argument_makes_the_line_too_long): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def overly_long_function_name(first_argument_on_the_same_line, second_argument_makes_the_line_too_long): pass @@ -1114,7 +1193,8 @@ def overly_long_function_name(first_argument_on_the_same_line, # extra_options=['--style=facebook']) # line-break before the first argument, dedenting closing brackets if set - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def overly_long_function_name( first_argument_on_the_same_line, second_argument_makes_the_line_too_long): @@ -1126,7 +1206,8 @@ def overly_long_function_name( # second_argument_makes_the_line_too_long): # pass # """) - expected_formatted_fb_code = textwrap.dedent("""\ + expected_formatted_fb_code = textwrap.dedent( + """\ def overly_long_function_name( first_argument_on_the_same_line, second_argument_makes_the_line_too_long ): @@ -1144,14 +1225,16 @@ def overly_long_function_name( # extra_options=['--style=pep8']) def testCoalesceBrackets(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ some_long_function_name_foo( { 'first_argument_of_the_thing': id, 'second_argument_of_the_thing': "some thing" } )""") - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ some_long_function_name_foo({ 'first_argument_of_the_thing': id, 'second_argument_of_the_thing': "some thing" @@ -1159,7 +1242,8 @@ def testCoalesceBrackets(self): """) with utils.NamedTempFile(dirname=self.test_tmpdir, mode='w') as (f, name): f.write( - textwrap.dedent(u'''\ + textwrap.dedent( + u'''\ [style] column_limit=82 coalesce_brackets = True @@ -1171,12 +1255,14 @@ def testCoalesceBrackets(self): extra_options=['--style={0}'.format(name)]) def testPseudoParenSpaces(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo(): def bar(): return {msg_id: author for author, msg_id in reader} """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo(): def bar(): return {msg_id: author for author, msg_id in reader} @@ -1187,7 +1273,8 @@ def bar(): extra_options=['--lines', '1-1', '--style', 'yapf']) def testMultilineCommentFormattingDisabled(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ # This is a comment FOO = { aaaaaaaa.ZZZ: [ @@ -1201,7 +1288,8 @@ def testMultilineCommentFormattingDisabled(self): '#': lambda x: x # do nothing } """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ # This is a comment FOO = { aaaaaaaa.ZZZ: [ @@ -1221,14 +1309,16 @@ def testMultilineCommentFormattingDisabled(self): extra_options=['--lines', '1-1', '--style', 'yapf']) def testTrailingCommentsWithDisabledFormatting(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ import os SCOPES = [ 'hello world' # This is a comment. ] """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ import os SCOPES = [ @@ -1241,7 +1331,7 @@ def testTrailingCommentsWithDisabledFormatting(self): extra_options=['--lines', '1-1', '--style', 'yapf']) def testUseTabs(self): - unformatted_code = """\ + unformatted_code = """\ def foo_function(): if True: pass @@ -1251,7 +1341,7 @@ def foo_function(): if True: pass """ # noqa: W191,E101 - style_contents = u"""\ + style_contents = u"""\ [style] based_on_style = yapf USE_TABS = true @@ -1264,7 +1354,7 @@ def foo_function(): extra_options=['--style={0}'.format(stylepath)]) def testUseTabsWith(self): - unformatted_code = """\ + unformatted_code = """\ def f(): return ['hello', 'world',] """ @@ -1275,7 +1365,7 @@ def f(): 'world', ] """ # noqa: W191,E101 - style_contents = u"""\ + style_contents = u"""\ [style] based_on_style = yapf USE_TABS = true @@ -1288,7 +1378,7 @@ def f(): extra_options=['--style={0}'.format(stylepath)]) def testUseTabsContinuationAlignStyleFixed(self): - unformatted_code = """\ + unformatted_code = """\ def foo_function(arg1, arg2, arg3): return ['hello', 'world',] """ @@ -1300,7 +1390,7 @@ def foo_function( 'world', ] """ # noqa: W191,E101 - style_contents = u"""\ + style_contents = u"""\ [style] based_on_style = yapf USE_TABS = true @@ -1316,7 +1406,7 @@ def foo_function( extra_options=['--style={0}'.format(stylepath)]) def testUseTabsContinuationAlignStyleVAlignRight(self): - unformatted_code = """\ + unformatted_code = """\ def foo_function(arg1, arg2, arg3): return ['hello', 'world',] """ @@ -1328,7 +1418,7 @@ def foo_function(arg1, arg2, 'world', ] """ # noqa: W191,E101 - style_contents = u"""\ + style_contents = u"""\ [style] based_on_style = yapf USE_TABS = true @@ -1344,7 +1434,7 @@ def foo_function(arg1, arg2, extra_options=['--style={0}'.format(stylepath)]) def testUseSpacesContinuationAlignStyleFixed(self): - unformatted_code = """\ + unformatted_code = """\ def foo_function(arg1, arg2, arg3): return ['hello', 'world',] """ @@ -1356,7 +1446,7 @@ def foo_function( 'world', ] """ - style_contents = u"""\ + style_contents = u"""\ [style] based_on_style = yapf COLUMN_LIMIT=32 @@ -1371,7 +1461,7 @@ def foo_function( extra_options=['--style={0}'.format(stylepath)]) def testUseSpacesContinuationAlignStyleVAlignRight(self): - unformatted_code = """\ + unformatted_code = """\ def foo_function(arg1, arg2, arg3): return ['hello', 'world',] """ @@ -1383,7 +1473,7 @@ def foo_function(arg1, arg2, 'world', ] """ - style_contents = u"""\ + style_contents = u"""\ [style] based_on_style = yapf COLUMN_LIMIT=32 @@ -1398,11 +1488,13 @@ def foo_function(arg1, arg2, extra_options=['--style={0}'.format(stylepath)]) def testStyleOutputRoundTrip(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def foo_function(): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def foo_function(): pass """) @@ -1422,7 +1514,8 @@ def foo_function(): extra_options=['--style={0}'.format(stylepath)]) def testSpacingBeforeComments(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ A = 42 @@ -1432,7 +1525,8 @@ def x(): def _(): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ A = 42 @@ -1448,7 +1542,8 @@ def _(): extra_options=['--lines', '1-2']) def testSpacingBeforeCommentsInDicts(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ A=42 X = { @@ -1463,7 +1558,8 @@ def testSpacingBeforeCommentsInDicts(self): 'BROKEN' } """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ A = 42 X = { @@ -1484,7 +1580,8 @@ def testSpacingBeforeCommentsInDicts(self): extra_options=['--style', 'yapf', '--lines', '1-1']) def testDisableWithLinesOption(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ # yapf_lines_bug.py # yapf: disable def outer_func(): @@ -1493,7 +1590,8 @@ def inner_func(): return # yapf: enable """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ # yapf_lines_bug.py # yapf: disable def outer_func(): @@ -1509,7 +1607,7 @@ def inner_func(): @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testNoSpacesAroundBinaryOperators(self): - unformatted_code = """\ + unformatted_code = """\ a = 4-b/c@d**37 """ expected_formatted_code = """\ @@ -1526,7 +1624,7 @@ def testNoSpacesAroundBinaryOperators(self): @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testCP936Encoding(self): - unformatted_code = 'print("äž­æ–‡")\n' + unformatted_code = 'print("äž­æ–‡")\n' expected_formatted_code = 'print("äž­æ–‡")\n' self.assertYapfReformats( unformatted_code, @@ -1534,7 +1632,7 @@ def testCP936Encoding(self): env={'PYTHONIOENCODING': 'cp936'}) def testDisableWithLineRanges(self): - unformatted_code = """\ + unformatted_code = """\ # yapf: disable a = [ 1, @@ -1574,8 +1672,8 @@ class DiffIndentTest(unittest.TestCase): @staticmethod def _OwnStyle(): - my_style = style.CreatePEP8Style() - my_style['INDENT_WIDTH'] = 3 + my_style = style.CreatePEP8Style() + my_style['INDENT_WIDTH'] = 3 my_style['CONTINUATION_INDENT_WIDTH'] = 3 return my_style @@ -1585,11 +1683,13 @@ def _Check(self, unformatted_code, expected_formatted_code): self.assertEqual(expected_formatted_code, formatted_code) def testSimple(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ for i in range(5): print('bar') """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ for i in range(5): print('bar') """) @@ -1600,7 +1700,7 @@ class HorizontallyAlignedTrailingCommentsTest(yapf_test_helper.YAPFTest): @staticmethod def _OwnStyle(): - my_style = style.CreatePEP8Style() + my_style = style.CreatePEP8Style() my_style['SPACES_BEFORE_COMMENT'] = [ 15, 25, @@ -1614,7 +1714,8 @@ def _Check(self, unformatted_code, expected_formatted_code): self.assertCodeEqual(expected_formatted_code, formatted_code) def testSimple(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ foo = '1' # Aligned at first list value foo = '2__<15>' # Aligned at second list value @@ -1623,7 +1724,8 @@ def testSimple(self): foo = '4______________________<35>' # Aligned beyond list values """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ foo = '1' # Aligned at first list value foo = '2__<15>' # Aligned at second list value @@ -1635,7 +1737,8 @@ def testSimple(self): self._Check(unformatted_code, expected_formatted_code) def testBlock(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ func(1) # Line 1 func(2) # Line 2 # Line 3 @@ -1643,7 +1746,8 @@ def testBlock(self): # Line 5 # Line 6 """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ func(1) # Line 1 func(2) # Line 2 # Line 3 @@ -1654,7 +1758,8 @@ def testBlock(self): self._Check(unformatted_code, expected_formatted_code) def testBlockWithLongLine(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ func(1) # Line 1 func___________________(2) # Line 2 # Line 3 @@ -1662,7 +1767,8 @@ def testBlockWithLongLine(self): # Line 5 # Line 6 """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ func(1) # Line 1 func___________________(2) # Line 2 # Line 3 @@ -1673,7 +1779,8 @@ def testBlockWithLongLine(self): self._Check(unformatted_code, expected_formatted_code) def testBlockFuncSuffix(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ func(1) # Line 1 func(2) # Line 2 # Line 3 @@ -1684,7 +1791,8 @@ def testBlockFuncSuffix(self): def Func(): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ func(1) # Line 1 func(2) # Line 2 # Line 3 @@ -1699,7 +1807,8 @@ def Func(): self._Check(unformatted_code, expected_formatted_code) def testBlockCommentSuffix(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ func(1) # Line 1 func(2) # Line 2 # Line 3 @@ -1709,7 +1818,8 @@ def testBlockCommentSuffix(self): # Aligned with prev comment block """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ func(1) # Line 1 func(2) # Line 2 # Line 3 @@ -1722,7 +1832,8 @@ def testBlockCommentSuffix(self): self._Check(unformatted_code, expected_formatted_code) def testBlockIndentedFuncSuffix(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if True: func(1) # Line 1 func(2) # Line 2 @@ -1736,7 +1847,8 @@ def testBlockIndentedFuncSuffix(self): def Func(): pass """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if True: func(1) # Line 1 func(2) # Line 2 @@ -1755,7 +1867,8 @@ def Func(): self._Check(unformatted_code, expected_formatted_code) def testBlockIndentedCommentSuffix(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if True: func(1) # Line 1 func(2) # Line 2 @@ -1766,7 +1879,8 @@ def testBlockIndentedCommentSuffix(self): # Not aligned """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if True: func(1) # Line 1 func(2) # Line 2 @@ -1780,7 +1894,8 @@ def testBlockIndentedCommentSuffix(self): self._Check(unformatted_code, expected_formatted_code) def testBlockMultiIndented(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ if True: if True: if True: @@ -1793,7 +1908,8 @@ def testBlockMultiIndented(self): # Not aligned """) # noqa - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ if True: if True: if True: @@ -1809,7 +1925,8 @@ def testBlockMultiIndented(self): self._Check(unformatted_code, expected_formatted_code) def testArgs(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ def MyFunc( arg1, # Desc 1 arg2, # Desc 2 @@ -1820,7 +1937,8 @@ def MyFunc( ): pass """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ def MyFunc( arg1, # Desc 1 arg2, # Desc 2 @@ -1834,7 +1952,8 @@ def MyFunc( self._Check(unformatted_code, expected_formatted_code) def testDisableBlock(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ a() # comment 1 b() # comment 2 @@ -1846,7 +1965,8 @@ def testDisableBlock(self): e() # comment 5 f() # comment 6 """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ a() # comment 1 b() # comment 2 @@ -1861,13 +1981,15 @@ def testDisableBlock(self): self._Check(unformatted_code, expected_formatted_code) def testDisabledLine(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ short # comment 1 do_not_touch1 # yapf: disable do_not_touch2 # yapf: disable a_longer_statement # comment 2 """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ short # comment 1 do_not_touch1 # yapf: disable do_not_touch2 # yapf: disable @@ -1880,9 +2002,9 @@ class _SpacesAroundDictListTupleTestImpl(unittest.TestCase): @staticmethod def _OwnStyle(): - my_style = style.CreatePEP8Style() - my_style['DISABLE_ENDING_COMMA_HEURISTIC'] = True - my_style['SPLIT_ALL_COMMA_SEPARATED_VALUES'] = False + my_style = style.CreatePEP8Style() + my_style['DISABLE_ENDING_COMMA_HEURISTIC'] = True + my_style['SPLIT_ALL_COMMA_SEPARATED_VALUES'] = False my_style['SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED'] = False return my_style @@ -1899,13 +2021,14 @@ class SpacesAroundDictTest(_SpacesAroundDictListTupleTestImpl): @classmethod def _OwnStyle(cls): - style = super(SpacesAroundDictTest, cls)._OwnStyle() + style = super(SpacesAroundDictTest, cls)._OwnStyle() style['SPACES_AROUND_DICT_DELIMITERS'] = True return style def testStandard(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ {1 : 2} {k:v for k, v in other.items()} {k for k in [1, 2, 3]} @@ -1922,7 +2045,8 @@ def testStandard(self): [1, 2] (3, 4) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ { 1: 2 } { k: v for k, v in other.items() } { k for k in [1, 2, 3] } @@ -1947,13 +2071,14 @@ class SpacesAroundListTest(_SpacesAroundDictListTupleTestImpl): @classmethod def _OwnStyle(cls): - style = super(SpacesAroundListTest, cls)._OwnStyle() + style = super(SpacesAroundListTest, cls)._OwnStyle() style['SPACES_AROUND_LIST_DELIMITERS'] = True return style def testStandard(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ [a,b,c] [4,5,] [6, [7, 8], 9] @@ -1974,7 +2099,8 @@ def testStandard(self): {a: b} (1, 2) """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ [ a, b, c ] [ 4, 5, ] [ 6, [ 7, 8 ], 9 ] @@ -2003,13 +2129,14 @@ class SpacesAroundTupleTest(_SpacesAroundDictListTupleTestImpl): @classmethod def _OwnStyle(cls): - style = super(SpacesAroundTupleTest, cls)._OwnStyle() + style = super(SpacesAroundTupleTest, cls)._OwnStyle() style['SPACES_AROUND_TUPLE_DELIMITERS'] = True return style def testStandard(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent( + """\ (0, 1) (2, 3) (4, 5, 6,) @@ -2032,7 +2159,8 @@ def testStandard(self): {a: b} [3, 4] """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent( + """\ ( 0, 1 ) ( 2, 3 ) ( 4, 5, 6, ) diff --git a/yapftests/yapf_test_helper.py b/yapftests/yapf_test_helper.py index cb56ec865..b95212a8b 100644 --- a/yapftests/yapf_test_helper.py +++ b/yapftests/yapf_test_helper.py @@ -39,7 +39,7 @@ def __init__(self, *args): def assertCodeEqual(self, expected_code, code): if code != expected_code: - msg = ['Code format mismatch:', 'Expected:'] + msg = ['Code format mismatch:', 'Expected:'] linelen = style.Get('COLUMN_LIMIT') for line in expected_code.splitlines(): if len(line) > linelen: From 6531180b880ea32d7b8c3287b6fa1456f3e347ad Mon Sep 17 00:00:00 2001 From: Eric McDonald <221418+emcd@users.noreply.github.com> Date: Wed, 30 Nov 2022 14:23:50 -0800 Subject: [PATCH 573/719] Prevent crashes against valid 'pyproject.toml'. (#1040) * Replace 'toml' dependency with 'tomli', which fully supports TOML 1. Co-authored-by: Eric McDonald --- setup.py | 2 +- yapf/yapflib/file_resources.py | 15 ++++++++------- yapf/yapflib/style.py | 25 ++++++++++++++----------- yapftests/file_resources_test.py | 10 +++++----- yapftests/style_test.py | 4 ++-- 5 files changed, 30 insertions(+), 26 deletions(-) diff --git a/setup.py b/setup.py index 5ba8b7a16..013a23d64 100644 --- a/setup.py +++ b/setup.py @@ -81,6 +81,6 @@ def run(self): 'test': RunTests, }, extras_require={ - 'pyproject': ['toml'], + 'pyproject': ['tomli'], }, ) diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index b5e2612bd..6809ca9f8 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -49,14 +49,15 @@ def _GetExcludePatternsFromPyprojectToml(filename): """Get a list of file patterns to ignore from pyproject.toml.""" ignore_patterns = [] try: - import toml + import tomli as tomllib except ImportError: raise errors.YapfError( - "toml package is needed for using pyproject.toml as a " + "tomli package is needed for using pyproject.toml as a " "configuration file") if os.path.isfile(filename) and os.access(filename, os.R_OK): - pyproject_toml = toml.load(filename) + with open(filename, 'rb') as fd: + pyproject_toml = tomllib.load(fd) ignore_patterns = pyproject_toml.get('tool', {}).get('yapfignore', {}).get('ignore_patterns', []) @@ -127,19 +128,19 @@ def GetDefaultStyleForDir(dirname, default_style=style.DEFAULT_STYLE): # See if we have a pyproject.toml file with a '[tool.yapf]' section. config_file = os.path.join(dirname, style.PYPROJECT_TOML) try: - fd = open(config_file) + fd = open(config_file, 'rb') except IOError: pass # It's okay if it's not there. else: with fd: try: - import toml + import tomli as tomllib except ImportError: raise errors.YapfError( - "toml package is needed for using pyproject.toml as a " + "tomli package is needed for using pyproject.toml as a " "configuration file") - pyproject_toml = toml.load(config_file) + pyproject_toml = tomllib.load(fd) style_dict = pyproject_toml.get('tool', {}).get('yapf', None) if style_dict is not None: return config_file diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 233a64e6b..c8397b323 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -746,17 +746,18 @@ def _CreateConfigParserFromConfigFile(config_filename): # Provide a more meaningful error here. raise StyleConfigError( '"{0}" is not a valid style or file path'.format(config_filename)) - with open(config_filename) as style_file: - config = py3compat.ConfigParser() - if config_filename.endswith(PYPROJECT_TOML): - try: - import toml - except ImportError: - raise errors.YapfError( - "toml package is needed for using pyproject.toml as a " - "configuration file") - - pyproject_toml = toml.load(style_file) + config = py3compat.ConfigParser() + + if config_filename.endswith(PYPROJECT_TOML): + try: + import tomli as tomllib + except ImportError: + raise errors.YapfError( + "tomli package is needed for using pyproject.toml as a " + "configuration file") + + with open(config_filename, 'rb') as style_file: + pyproject_toml = tomllib.load(style_file) style_dict = pyproject_toml.get("tool", {}).get("yapf", None) if style_dict is None: raise StyleConfigError( @@ -766,7 +767,9 @@ def _CreateConfigParserFromConfigFile(config_filename): config.set('style', k, str(v)) return config + with open(config_filename) as style_file: config.read_file(style_file) + if config_filename.endswith(SETUP_CONFIG): if not config.has_section('yapf'): raise StyleConfigError( diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 31184c4a3..f54f393d6 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -75,7 +75,7 @@ def test_get_exclude_file_patterns_from_yapfignore_with_wrong_syntax(self): def test_get_exclude_file_patterns_from_pyproject(self): try: - import toml + import tomli except ImportError: return local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') @@ -93,7 +93,7 @@ def test_get_exclude_file_patterns_from_pyproject(self): @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def test_get_exclude_file_patterns_from_pyproject_with_wrong_syntax(self): try: - import toml + import tomli except ImportError: return local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') @@ -109,7 +109,7 @@ def test_get_exclude_file_patterns_from_pyproject_with_wrong_syntax(self): def test_get_exclude_file_patterns_from_pyproject_no_ignore_section(self): try: - import toml + import tomli except ImportError: return local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') @@ -122,7 +122,7 @@ def test_get_exclude_file_patterns_from_pyproject_no_ignore_section(self): def test_get_exclude_file_patterns_from_pyproject_ignore_section_empty(self): try: - import toml + import tomli except ImportError: return local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') @@ -192,7 +192,7 @@ def test_setup_config(self): def test_pyproject_toml(self): # An empty pyproject.toml file should not be used try: - import toml + import tomli except ImportError: return diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 8a37f9535..d2203d9ac 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -230,7 +230,7 @@ def testErrorUnknownStyleOption(self): def testPyprojectTomlNoYapfSection(self): try: - import toml + import tomli except ImportError: return @@ -242,7 +242,7 @@ def testPyprojectTomlNoYapfSection(self): def testPyprojectTomlParseYapfSection(self): try: - import toml + import tomli except ImportError: return From c285730bd775bcdf20dc75350883de24aa07b0b8 Mon Sep 17 00:00:00 2001 From: Xiao Wang Date: Tue, 3 Jan 2023 10:30:10 +0100 Subject: [PATCH 574/719] change the format back to yapf-based --- yapf/__init__.py | 98 +- yapf/pyparser/pyparser.py | 22 +- yapf/pyparser/pyparser_utils.py | 8 +- yapf/pyparser/split_penalty_visitor.py | 49 +- yapf/pytree/blank_line_calculator.py | 60 +- yapf/pytree/comment_splicer.py | 44 +- yapf/pytree/pytree_unwrapper.py | 42 +- yapf/pytree/pytree_utils.py | 36 +- yapf/pytree/pytree_visitor.py | 2 +- yapf/pytree/split_penalty.py | 87 +- yapf/pytree/subtype_assigner.py | 41 +- yapf/third_party/yapf_diff/yapf_diff.py | 7 +- yapf/yapflib/errors.py | 4 +- yapf/yapflib/file_resources.py | 26 +- yapf/yapflib/format_decision_state.py | 183 ++-- yapf/yapflib/format_token.py | 106 ++- yapf/yapflib/logical_line.py | 34 +- yapf/yapflib/object_state.py | 69 +- yapf/yapflib/py3compat.py | 14 +- yapf/yapflib/reformatter.py | 115 ++- yapf/yapflib/split_penalty.py | 16 +- yapf/yapflib/style.py | 256 ++---- yapf/yapflib/subtypes.py | 48 +- yapf/yapflib/verifier.py | 2 +- yapf/yapflib/yapf_api.py | 73 +- yapftests/blank_line_calculator_test.py | 69 +- yapftests/comment_splicer_test.py | 62 +- yapftests/file_resources_test.py | 137 +-- yapftests/format_decision_state_test.py | 8 +- yapftests/line_joiner_test.py | 18 +- yapftests/logical_line_test.py | 22 +- yapftests/main_test.py | 11 +- yapftests/pytree_unwrapper_test.py | 273 +++--- yapftests/pytree_utils_test.py | 62 +- yapftests/pytree_visitor_test.py | 10 +- yapftests/reformatter_basic_test.py | 981 ++++++++------------- yapftests/reformatter_buganizer_test.py | 513 ++++------- yapftests/reformatter_facebook_test.py | 93 +- yapftests/reformatter_pep8_test.py | 272 +++--- yapftests/reformatter_python3_test.py | 107 +-- yapftests/reformatter_style_config_test.py | 54 +- yapftests/reformatter_verify_test.py | 26 +- yapftests/split_penalty_test.py | 272 +++--- yapftests/style_test.py | 57 +- yapftests/subtype_assigner_test.py | 421 +++++---- yapftests/utils.py | 34 +- yapftests/yapf_test.py | 500 ++++------- yapftests/yapf_test_helper.py | 2 +- 48 files changed, 2276 insertions(+), 3170 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 2b69c1ddc..94e445b59 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -55,8 +55,8 @@ def main(argv): Raises: YapfError: if none of the supplied files were Python files. """ - parser = _BuildParser() - args = parser.parse_args(argv[1:]) + parser = _BuildParser() + args = parser.parse_args(argv[1:]) style_config = args.style if args.style_help: @@ -70,9 +70,8 @@ def main(argv): if not args.files: # No arguments specified. Read code from stdin. if args.in_place or args.diff: - parser.error( - 'cannot use --in-place or --diff flags when reading ' - 'from stdin') + parser.error('cannot use --in-place or --diff flags when reading ' + 'from stdin') original_source = [] while True: @@ -94,7 +93,7 @@ def main(argv): if style_config is None and not args.no_local_style: style_config = file_resources.GetDefaultStyleForDir(os.getcwd()) - source = [line.rstrip() for line in original_source] + source = [line.rstrip() for line in original_source] source[0] = py3compat.removeBOM(source[0]) try: @@ -116,9 +115,9 @@ def main(argv): exclude_patterns_from_ignore_file = file_resources.GetExcludePatternsForDir( os.getcwd()) - files = file_resources.GetCommandLineFiles( - args.files, args.recursive, - (args.exclude or []) + exclude_patterns_from_ignore_file) + files = file_resources.GetCommandLineFiles(args.files, args.recursive, + (args.exclude or []) + + exclude_patterns_from_ignore_file) if not files: raise errors.YapfError('input filenames did not match any python files') @@ -153,17 +152,16 @@ def _PrintHelp(args): print() -def FormatFiles( - filenames, - lines, - style_config=None, - no_local_style=False, - in_place=False, - print_diff=False, - verify=False, - parallel=False, - quiet=False, - verbose=False): +def FormatFiles(filenames, + lines, + style_config=None, + no_local_style=False, + in_place=False, + print_diff=False, + verify=False, + parallel=False, + quiet=False, + verbose=False): """Format a list of files. Arguments: @@ -193,31 +191,28 @@ def FormatFiles( workers = min(multiprocessing.cpu_count(), len(filenames)) with concurrent.futures.ProcessPoolExecutor(workers) as executor: future_formats = [ - executor.submit( - _FormatFile, filename, lines, style_config, no_local_style, - in_place, print_diff, verify, quiet, verbose) - for filename in filenames + executor.submit(_FormatFile, filename, lines, style_config, + no_local_style, in_place, print_diff, verify, quiet, + verbose) for filename in filenames ] for future in concurrent.futures.as_completed(future_formats): changed |= future.result() else: for filename in filenames: - changed |= _FormatFile( - filename, lines, style_config, no_local_style, in_place, print_diff, - verify, quiet, verbose) + changed |= _FormatFile(filename, lines, style_config, no_local_style, + in_place, print_diff, verify, quiet, verbose) return changed -def _FormatFile( - filename, - lines, - style_config=None, - no_local_style=False, - in_place=False, - print_diff=False, - verify=False, - quiet=False, - verbose=False): +def _FormatFile(filename, + lines, + style_config=None, + no_local_style=False, + in_place=False, + print_diff=False, + verify=False, + quiet=False, + verbose=False): """Format an individual file.""" if verbose and not quiet: print('Reformatting %s' % filename) @@ -241,8 +236,8 @@ def _FormatFile( raise errors.YapfError(errors.FormatErrorMsg(e)) if not in_place and not quiet and reformatted_code: - file_resources.WriteReformattedCode( - filename, reformatted_code, encoding, in_place) + file_resources.WriteReformattedCode(filename, reformatted_code, encoding, + in_place) return has_change @@ -326,20 +321,18 @@ def _BuildParser(): parser.add_argument( '--style', action='store', - help=( - 'specify formatting style: either a style name (for example "pep8" ' - 'or "google"), or the name of a file with style settings. The ' - 'default is pep8 unless a %s or %s or %s file located in the same ' - 'directory as the source or one of its parent directories ' - '(for stdin, the current directory is used).' % - (style.LOCAL_STYLE, style.SETUP_CONFIG, style.PYPROJECT_TOML))) + help=('specify formatting style: either a style name (for example "pep8" ' + 'or "google"), or the name of a file with style settings. The ' + 'default is pep8 unless a %s or %s or %s file located in the same ' + 'directory as the source or one of its parent directories ' + '(for stdin, the current directory is used).' % + (style.LOCAL_STYLE, style.SETUP_CONFIG, style.PYPROJECT_TOML))) parser.add_argument( '--style-help', action='store_true', - help=( - 'show style settings and exit; this output can be ' - 'saved to .style.yapf to make your settings ' - 'permanent')) + help=('show style settings and exit; this output can be ' + 'saved to .style.yapf to make your settings ' + 'permanent')) parser.add_argument( '--no-local-style', action='store_true', @@ -349,9 +342,8 @@ def _BuildParser(): '-p', '--parallel', action='store_true', - help=( - 'run YAPF in parallel when formatting multiple files. Requires ' - 'concurrent.futures in Python 2.X')) + help=('run YAPF in parallel when formatting multiple files. Requires ' + 'concurrent.futures in Python 2.X')) parser.add_argument( '-vv', '--verbose', diff --git a/yapf/pyparser/pyparser.py b/yapf/pyparser/pyparser.py index b2bffa283..a8a28ebc8 100644 --- a/yapf/pyparser/pyparser.py +++ b/yapf/pyparser/pyparser.py @@ -68,7 +68,7 @@ def ParseCode(unformatted_source, filename=''): ast_tree = ast.parse(unformatted_source, filename) ast.fix_missing_locations(ast_tree) readline = py3compat.StringIO(unformatted_source).readline - tokens = tokenize.generate_tokens(readline) + tokens = tokenize.generate_tokens(readline) except Exception: raise @@ -89,10 +89,10 @@ def _CreateLogicalLines(tokens): Returns: A list of LogicalLines. """ - logical_lines = [] + logical_lines = [] cur_logical_line = [] - prev_tok = None - depth = 0 + prev_tok = None + depth = 0 for tok in tokens: tok = py3compat.TokenInfo(*tok) @@ -100,7 +100,7 @@ def _CreateLogicalLines(tokens): # End of a logical line. logical_lines.append(logical_line.LogicalLine(depth, cur_logical_line)) cur_logical_line = [] - prev_tok = None + prev_tok = None elif tok.type == tokenize.INDENT: depth += 1 elif tok.type == tokenize.DEDENT: @@ -117,29 +117,29 @@ def _CreateLogicalLines(tokens): line=prev_tok.line) ctok.lineno = ctok.start[0] ctok.column = ctok.start[1] - ctok.value = '\\' + ctok.value = '\\' cur_logical_line.append(format_token.FormatToken(ctok, 'CONTINUATION')) tok.lineno = tok.start[0] tok.column = tok.start[1] - tok.value = tok.string + tok.value = tok.string cur_logical_line.append( format_token.FormatToken(tok, token.tok_name[tok.type])) prev_tok = tok # Link the FormatTokens in each line together to for a doubly linked list. for line in logical_lines: - previous = line.first + previous = line.first bracket_stack = [previous] if previous.OpensScope() else [] for tok in line.tokens[1:]: - tok.previous_token = previous + tok.previous_token = previous previous.next_token = tok - previous = tok + previous = tok # Set up the "matching_bracket" attribute. if tok.OpensScope(): bracket_stack.append(tok) elif tok.ClosesScope(): bracket_stack[-1].matching_bracket = tok - tok.matching_bracket = bracket_stack.pop() + tok.matching_bracket = bracket_stack.pop() return logical_lines diff --git a/yapf/pyparser/pyparser_utils.py b/yapf/pyparser/pyparser_utils.py index 149e0a280..3f17b15a4 100644 --- a/yapf/pyparser/pyparser_utils.py +++ b/yapf/pyparser/pyparser_utils.py @@ -31,8 +31,8 @@ def GetTokens(logical_lines, node): """Get a list of tokens within the node's range from the logical lines.""" - start = TokenStart(node) - end = TokenEnd(node) + start = TokenStart(node) + end = TokenEnd(node) tokens = [] for line in logical_lines: @@ -46,8 +46,8 @@ def GetTokens(logical_lines, node): def GetTokensInSubRange(tokens, node): """Get a subset of tokens representing the node.""" - start = TokenStart(node) - end = TokenEnd(node) + start = TokenStart(node) + end = TokenEnd(node) tokens_in_range = [] for tok in tokens: diff --git a/yapf/pyparser/split_penalty_visitor.py b/yapf/pyparser/split_penalty_visitor.py index 946bd949f..047b48a3d 100644 --- a/yapf/pyparser/split_penalty_visitor.py +++ b/yapf/pyparser/split_penalty_visitor.py @@ -67,14 +67,13 @@ def visit_FunctionDef(self, node): _SetPenalty(token, split_penalty.UNBREAKABLE) if node.returns: - start_index = pyutils.GetTokenIndex( - tokens, pyutils.TokenStart(node.returns)) - _IncreasePenalty( - tokens[start_index - 1:start_index + 1], - split_penalty.VERY_STRONGLY_CONNECTED) + start_index = pyutils.GetTokenIndex(tokens, + pyutils.TokenStart(node.returns)) + _IncreasePenalty(tokens[start_index - 1:start_index + 1], + split_penalty.VERY_STRONGLY_CONNECTED) end_index = pyutils.GetTokenIndex(tokens, pyutils.TokenEnd(node.returns)) - _IncreasePenalty( - tokens[start_index + 1:end_index], split_penalty.STRONGLY_CONNECTED) + _IncreasePenalty(tokens[start_index + 1:end_index], + split_penalty.STRONGLY_CONNECTED) return self.generic_visit(node) @@ -104,7 +103,7 @@ def visit_ClassDef(self, node): for decorator in node.decorator_list: # Don't split after the '@'. - decorator_range = self._GetTokens(decorator) + decorator_range = self._GetTokens(decorator) decorator_range[0].split_penalty = split_penalty.UNBREAKABLE return self.generic_visit(node) @@ -264,7 +263,7 @@ def visit_BoolOp(self, node): # Lower the split penalty to allow splitting before or after the logical # operator. split_before_operator = style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR') - operator_indices = [ + operator_indices = [ pyutils.GetNextTokenIndex(tokens, pyutils.TokenEnd(value)) for value in node.values[:-1] ] @@ -293,8 +292,8 @@ def visit_BinOp(self, node): # Lower the split penalty to allow splitting before or after the arithmetic # operator. - operator_index = pyutils.GetNextTokenIndex( - tokens, pyutils.TokenEnd(node.left)) + operator_index = pyutils.GetNextTokenIndex(tokens, + pyutils.TokenEnd(node.left)) if not style.Get('SPLIT_BEFORE_ARITHMETIC_OPERATOR'): operator_index += 1 @@ -371,7 +370,7 @@ def visit_ListComp(self, node): # is_async=0), # ... # ]) - tokens = self._GetTokens(node) + tokens = self._GetTokens(node) element = pyutils.GetTokensInSubRange(tokens, node.elt) _IncreasePenalty(element[1:], split_penalty.EXPR) @@ -395,7 +394,7 @@ def visit_SetComp(self, node): # is_async=0), # ... # ]) - tokens = self._GetTokens(node) + tokens = self._GetTokens(node) element = pyutils.GetTokensInSubRange(tokens, node.elt) _IncreasePenalty(element[1:], split_penalty.EXPR) @@ -421,7 +420,7 @@ def visit_DictComp(self, node): # ... # ]) tokens = self._GetTokens(node) - key = pyutils.GetTokensInSubRange(tokens, node.key) + key = pyutils.GetTokensInSubRange(tokens, node.key) _IncreasePenalty(key[1:], split_penalty.EXPR) value = pyutils.GetTokensInSubRange(tokens, node.value) @@ -447,7 +446,7 @@ def visit_GeneratorExp(self, node): # is_async=0), # ... # ]) - tokens = self._GetTokens(node) + tokens = self._GetTokens(node) element = pyutils.GetTokensInSubRange(tokens, node.elt) _IncreasePenalty(element[1:], split_penalty.EXPR) @@ -542,10 +541,10 @@ def visit_Constant(self, node): def visit_Attribute(self, node): # Attribute(value=Expr, # attr=Identifier) - tokens = self._GetTokens(node) + tokens = self._GetTokens(node) split_before = style.Get('SPLIT_BEFORE_DOT') - dot_indices = pyutils.GetNextTokenIndex( - tokens, pyutils.TokenEnd(node.value)) + dot_indices = pyutils.GetNextTokenIndex(tokens, + pyutils.TokenEnd(node.value)) if not split_before: dot_indices += 1 @@ -559,8 +558,8 @@ def visit_Subscript(self, node): tokens = self._GetTokens(node) # Don't split before the opening bracket of a subscript. - bracket_index = pyutils.GetNextTokenIndex( - tokens, pyutils.TokenEnd(node.value)) + bracket_index = pyutils.GetNextTokenIndex(tokens, + pyutils.TokenEnd(node.value)) _IncreasePenalty(tokens[bracket_index], split_penalty.UNBREAKABLE) return self.generic_visit(node) @@ -610,16 +609,16 @@ def visit_Slice(self, node): _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) if hasattr(node, 'upper') and node.upper: - colon_index = pyutils.GetPrevTokenIndex( - tokens, pyutils.TokenStart(node.upper)) + colon_index = pyutils.GetPrevTokenIndex(tokens, + pyutils.TokenStart(node.upper)) _IncreasePenalty(tokens[colon_index], split_penalty.UNBREAKABLE) subrange = pyutils.GetTokensInSubRange(tokens, node.upper) _IncreasePenalty(subrange, split_penalty.EXPR) _DecreasePenalty(subrange[0], split_penalty.EXPR // 2) if hasattr(node, 'step') and node.step: - colon_index = pyutils.GetPrevTokenIndex( - tokens, pyutils.TokenStart(node.step)) + colon_index = pyutils.GetPrevTokenIndex(tokens, + pyutils.TokenStart(node.step)) _IncreasePenalty(tokens[colon_index], split_penalty.UNBREAKABLE) subrange = pyutils.GetTokensInSubRange(tokens, node.step) _IncreasePenalty(subrange, split_penalty.EXPR) @@ -865,7 +864,7 @@ def visit_arg(self, node): # Process any annotations. if hasattr(node, 'annotation') and node.annotation: annotation = node.annotation - subrange = pyutils.GetTokensInSubRange(tokens, annotation) + subrange = pyutils.GetTokensInSubRange(tokens, annotation) _IncreasePenalty(subrange, split_penalty.ANNOTATION) return self.generic_visit(node) diff --git a/yapf/pytree/blank_line_calculator.py b/yapf/pytree/blank_line_calculator.py index 8aa20ec0a..9d218bf97 100644 --- a/yapf/pytree/blank_line_calculator.py +++ b/yapf/pytree/blank_line_calculator.py @@ -29,18 +29,17 @@ from yapf.yapflib import py3compat from yapf.yapflib import style -_NO_BLANK_LINES = 1 -_ONE_BLANK_LINE = 2 +_NO_BLANK_LINES = 1 +_ONE_BLANK_LINE = 2 _TWO_BLANK_LINES = 3 -_PYTHON_STATEMENTS = frozenset( - { - 'small_stmt', 'expr_stmt', 'print_stmt', 'del_stmt', 'pass_stmt', - 'break_stmt', 'continue_stmt', 'return_stmt', 'raise_stmt', - 'yield_stmt', 'import_stmt', 'global_stmt', 'exec_stmt', 'assert_stmt', - 'if_stmt', 'while_stmt', 'for_stmt', 'try_stmt', 'with_stmt', - 'nonlocal_stmt', 'async_stmt', 'simple_stmt' - }) +_PYTHON_STATEMENTS = frozenset({ + 'small_stmt', 'expr_stmt', 'print_stmt', 'del_stmt', 'pass_stmt', + 'break_stmt', 'continue_stmt', 'return_stmt', 'raise_stmt', 'yield_stmt', + 'import_stmt', 'global_stmt', 'exec_stmt', 'assert_stmt', 'if_stmt', + 'while_stmt', 'for_stmt', 'try_stmt', 'with_stmt', 'nonlocal_stmt', + 'async_stmt', 'simple_stmt' +}) def CalculateBlankLines(tree): @@ -59,10 +58,10 @@ class _BlankLineCalculator(pytree_visitor.PyTreeVisitor): """_BlankLineCalculator - see file-level docstring for a description.""" def __init__(self): - self.class_level = 0 - self.function_level = 0 - self.last_comment_lineno = 0 - self.last_was_decorator = False + self.class_level = 0 + self.function_level = 0 + self.last_comment_lineno = 0 + self.last_was_decorator = False self.last_was_class_or_function = False def Visit_simple_stmt(self, node): # pylint: disable=invalid-name @@ -82,17 +81,17 @@ def Visit_decorator(self, node): # pylint: disable=invalid-name def Visit_classdef(self, node): # pylint: disable=invalid-name self.last_was_class_or_function = False - index = self._SetBlankLinesBetweenCommentAndClassFunc(node) - self.last_was_decorator = False - self.class_level += 1 + index = self._SetBlankLinesBetweenCommentAndClassFunc(node) + self.last_was_decorator = False + self.class_level += 1 for child in node.children[index:]: self.Visit(child) - self.class_level -= 1 + self.class_level -= 1 self.last_was_class_or_function = True def Visit_funcdef(self, node): # pylint: disable=invalid-name self.last_was_class_or_function = False - index = self._SetBlankLinesBetweenCommentAndClassFunc(node) + index = self._SetBlankLinesBetweenCommentAndClassFunc(node) if _AsyncFunction(node): index = self._SetBlankLinesBetweenCommentAndClassFunc( node.prev_sibling.parent) @@ -100,10 +99,10 @@ def Visit_funcdef(self, node): # pylint: disable=invalid-name else: index = self._SetBlankLinesBetweenCommentAndClassFunc(node) self.last_was_decorator = False - self.function_level += 1 + self.function_level += 1 for child in node.children[index:]: self.Visit(child) - self.function_level -= 1 + self.function_level -= 1 self.last_was_class_or_function = True def DefaultNodeVisit(self, node): @@ -161,23 +160,20 @@ def _GetNumNewlines(self, node): return _ONE_BLANK_LINE def _IsTopLevel(self, node): - return ( - not (self.class_level or self.function_level) and - _StartsInZerothColumn(node)) + return (not (self.class_level or self.function_level) and + _StartsInZerothColumn(node)) def _SetNumNewlines(node, num_newlines): - pytree_utils.SetNodeAnnotation( - node, pytree_utils.Annotation.NEWLINES, num_newlines) + pytree_utils.SetNodeAnnotation(node, pytree_utils.Annotation.NEWLINES, + num_newlines) def _StartsInZerothColumn(node): - return ( - pytree_utils.FirstLeafNode(node).column == 0 or - (_AsyncFunction(node) and node.prev_sibling.column == 0)) + return (pytree_utils.FirstLeafNode(node).column == 0 or + (_AsyncFunction(node) and node.prev_sibling.column == 0)) def _AsyncFunction(node): - return ( - py3compat.PY3 and node.prev_sibling and - node.prev_sibling.type == grammar_token.ASYNC) + return (py3compat.PY3 and node.prev_sibling and + node.prev_sibling.type == grammar_token.ASYNC) diff --git a/yapf/pytree/comment_splicer.py b/yapf/pytree/comment_splicer.py index 01911c896..ae5ffe66f 100644 --- a/yapf/pytree/comment_splicer.py +++ b/yapf/pytree/comment_splicer.py @@ -60,7 +60,7 @@ def _VisitNodeRec(node): # Remember the leading indentation of this prefix and clear it. # Mopping up the prefix is important because we may go over this same # child in the next iteration... - child_prefix = child.prefix.lstrip('\n') + child_prefix = child.prefix.lstrip('\n') prefix_indent = child_prefix[:child_prefix.find('#')] if '\n' in prefix_indent: prefix_indent = prefix_indent[prefix_indent.rfind('\n') + 1:] @@ -171,23 +171,22 @@ def _VisitNodeRec(node): else: if comment_lineno == prev_leaf[0].lineno: comment_lines = comment_prefix.splitlines() - value = comment_lines[0].lstrip() + value = comment_lines[0].lstrip() if value.rstrip('\n'): - comment_column = prev_leaf[0].column + comment_column = prev_leaf[0].column comment_column += len(prev_leaf[0].value) - comment_column += ( + comment_column += ( len(comment_lines[0]) - len(comment_lines[0].lstrip())) comment_leaf = pytree.Leaf( type=token.COMMENT, value=value.rstrip('\n'), context=('', (comment_lineno, comment_column))) pytree_utils.InsertNodesAfter([comment_leaf], prev_leaf[0]) - comment_prefix = '\n'.join(comment_lines[1:]) + comment_prefix = '\n'.join(comment_lines[1:]) comment_lineno += 1 - rindex = ( - 0 if '\n' not in comment_prefix.rstrip() else - comment_prefix.rstrip().rindex('\n') + 1) + rindex = (0 if '\n' not in comment_prefix.rstrip() else + comment_prefix.rstrip().rindex('\n') + 1) comment_column = ( len(comment_prefix[rindex:]) - len(comment_prefix[rindex:].lstrip())) @@ -204,8 +203,10 @@ def _VisitNodeRec(node): _VisitNodeRec(tree) -def _CreateCommentsFromPrefix( - comment_prefix, comment_lineno, comment_column, standalone=False): +def _CreateCommentsFromPrefix(comment_prefix, + comment_lineno, + comment_column, + standalone=False): """Create pytree nodes to represent the given comment prefix. Args: @@ -233,10 +234,10 @@ def _CreateCommentsFromPrefix( index += 1 if comment_block: - new_lineno = comment_lineno + index - 1 - comment_block[0] = comment_block[0].strip() + new_lineno = comment_lineno + index - 1 + comment_block[0] = comment_block[0].strip() comment_block[-1] = comment_block[-1].strip() - comment_leaf = pytree.Leaf( + comment_leaf = pytree.Leaf( type=token.COMMENT, value='\n'.join(comment_block), context=('', (new_lineno, comment_column))) @@ -261,11 +262,10 @@ def _CreateCommentsFromPrefix( # line, not on the same line with other code), it's important to insert it into # an appropriate parent of the node it's attached to. An appropriate parent # is the first "standalone line node" in the parent chain of a node. -_STANDALONE_LINE_NODES = frozenset( - [ - 'suite', 'if_stmt', 'while_stmt', 'for_stmt', 'try_stmt', 'with_stmt', - 'funcdef', 'classdef', 'decorated', 'file_input' - ]) +_STANDALONE_LINE_NODES = frozenset([ + 'suite', 'if_stmt', 'while_stmt', 'for_stmt', 'try_stmt', 'with_stmt', + 'funcdef', 'classdef', 'decorated', 'file_input' +]) def _FindNodeWithStandaloneLineParent(node): @@ -352,14 +352,14 @@ def _AnnotateIndents(tree): """ # Annotate the root of the tree with zero indent. if tree.parent is None: - pytree_utils.SetNodeAnnotation( - tree, pytree_utils.Annotation.CHILD_INDENT, '') + pytree_utils.SetNodeAnnotation(tree, pytree_utils.Annotation.CHILD_INDENT, + '') for child in tree.children: if child.type == token.INDENT: child_indent = pytree_utils.GetNodeAnnotation( tree, pytree_utils.Annotation.CHILD_INDENT) if child_indent is not None and child_indent != child.value: raise RuntimeError('inconsistent indentation for child', (tree, child)) - pytree_utils.SetNodeAnnotation( - tree, pytree_utils.Annotation.CHILD_INDENT, child.value) + pytree_utils.SetNodeAnnotation(tree, pytree_utils.Annotation.CHILD_INDENT, + child.value) _AnnotateIndents(child) diff --git a/yapf/pytree/pytree_unwrapper.py b/yapf/pytree/pytree_unwrapper.py index 835ca60a1..3fe4ade08 100644 --- a/yapf/pytree/pytree_unwrapper.py +++ b/yapf/pytree/pytree_unwrapper.py @@ -61,11 +61,10 @@ def UnwrapPyTree(tree): # Grammar tokens considered as whitespace for the purpose of unwrapping. -_WHITESPACE_TOKENS = frozenset( - [ - grammar_token.NEWLINE, grammar_token.DEDENT, grammar_token.INDENT, - grammar_token.ENDMARKER - ]) +_WHITESPACE_TOKENS = frozenset([ + grammar_token.NEWLINE, grammar_token.DEDENT, grammar_token.INDENT, + grammar_token.ENDMARKER +]) class PyTreeUnwrapper(pytree_visitor.PyTreeVisitor): @@ -119,17 +118,16 @@ def _StartNewLine(self): _AdjustSplitPenalty(self._cur_logical_line) self._cur_logical_line = logical_line.LogicalLine(self._cur_depth) - _STMT_TYPES = frozenset( - { - 'if_stmt', - 'while_stmt', - 'for_stmt', - 'try_stmt', - 'expect_clause', - 'with_stmt', - 'funcdef', - 'classdef', - }) + _STMT_TYPES = frozenset({ + 'if_stmt', + 'while_stmt', + 'for_stmt', + 'try_stmt', + 'expect_clause', + 'with_stmt', + 'funcdef', + 'classdef', + }) # pylint: disable=invalid-name,missing-docstring def Visit_simple_stmt(self, node): @@ -322,7 +320,7 @@ def _MatchBrackets(line): bracket_stack.append(token) elif token.value in _CLOSING_BRACKETS: bracket_stack[-1].matching_bracket = token - token.matching_bracket = bracket_stack[-1] + token.matching_bracket = bracket_stack[-1] bracket_stack.pop() for bracket in bracket_stack: @@ -340,7 +338,7 @@ def _IdentifyParameterLists(line): Arguments: line: (LogicalLine) A logical line. """ - func_stack = [] + func_stack = [] param_stack = [] for tok in line.tokens: # Identify parameter list objects. @@ -376,9 +374,9 @@ def _AdjustSplitPenalty(line): bracket_level = 0 for index, token in enumerate(line.tokens): if index and not bracket_level: - pytree_utils.SetNodeAnnotation( - token.node, pytree_utils.Annotation.SPLIT_PENALTY, - split_penalty.UNBREAKABLE) + pytree_utils.SetNodeAnnotation(token.node, + pytree_utils.Annotation.SPLIT_PENALTY, + split_penalty.UNBREAKABLE) if token.value in _OPENING_BRACKETS: bracket_level += 1 elif token.value in _CLOSING_BRACKETS: @@ -398,7 +396,7 @@ def _DetermineMustSplitAnnotation(node): node.children[-1].value != ','): return num_children = len(node.children) - index = 0 + index = 0 _SetMustSplitOnFirstLeaf(node.children[0]) while index < num_children - 1: child = node.children[index] diff --git a/yapf/pytree/pytree_utils.py b/yapf/pytree/pytree_utils.py index 415011806..66a54e617 100644 --- a/yapf/pytree/pytree_utils.py +++ b/yapf/pytree/pytree_utils.py @@ -42,11 +42,11 @@ class Annotation(object): """Annotation names associated with pytrees.""" - CHILD_INDENT = 'child_indent' - NEWLINES = 'newlines' - MUST_SPLIT = 'must_split' + CHILD_INDENT = 'child_indent' + NEWLINES = 'newlines' + MUST_SPLIT = 'must_split' SPLIT_PENALTY = 'split_penalty' - SUBTYPE = 'subtype' + SUBTYPE = 'subtype' def NodeName(node): @@ -113,13 +113,13 @@ def ParseCodeToTree(code): # Try to parse using a Python 3 grammar, which is more permissive (print and # exec are not keywords). parser_driver = driver.Driver(_GRAMMAR_FOR_PY3, convert=pytree.convert) - tree = parser_driver.parse_string(code, debug=False) + tree = parser_driver.parse_string(code, debug=False) except parse.ParseError: # Now try to parse using a Python 2 grammar; If this fails, then # there's something else wrong with the code. try: parser_driver = driver.Driver(_GRAMMAR_FOR_PY2, convert=pytree.convert) - tree = parser_driver.parse_string(code, debug=False) + tree = parser_driver.parse_string(code, debug=False) except parse.ParseError: # Raise a syntax error if the code is invalid python syntax. try: @@ -195,9 +195,8 @@ def _InsertNodeAt(new_node, target, after=False): # Protect against attempts to insert nodes which already belong to some tree. if new_node.parent is not None: - raise RuntimeError( - 'inserting node which already has a parent', - (new_node, new_node.parent)) + raise RuntimeError('inserting node which already has a parent', + (new_node, new_node.parent)) # The code here is based on pytree.Base.next_sibling parent_of_target = target.parent @@ -210,8 +209,8 @@ def _InsertNodeAt(new_node, target, after=False): parent_of_target.insert_child(insertion_index, new_node) return - raise RuntimeError( - 'unable to find insertion point for target node', (target,)) + raise RuntimeError('unable to find insertion point for target node', + (target,)) # The following constant and functions implement a simple custom annotation @@ -317,9 +316,8 @@ def DumpNodeToString(node): The string representation. """ if isinstance(node, pytree.Leaf): - fmt = ( - '{name}({value}) [lineno={lineno}, column={column}, ' - 'prefix={prefix}, penalty={penalty}]') + fmt = ('{name}({value}) [lineno={lineno}, column={column}, ' + 'prefix={prefix}, penalty={penalty}]') return fmt.format( name=NodeName(node), value=_PytreeNodeRepr(node), @@ -338,14 +336,12 @@ def DumpNodeToString(node): def _PytreeNodeRepr(node): """Like pytree.Node.__repr__, but names instead of numbers for tokens.""" if isinstance(node, pytree.Node): - return '%s(%s, %r)' % ( - node.__class__.__name__, NodeName(node), - [_PytreeNodeRepr(c) for c in node.children]) + return '%s(%s, %r)' % (node.__class__.__name__, NodeName(node), + [_PytreeNodeRepr(c) for c in node.children]) if isinstance(node, pytree.Leaf): return '%s(%s, %r)' % (node.__class__.__name__, NodeName(node), node.value) def IsCommentStatement(node): - return ( - NodeName(node) == 'simple_stmt' and - node.children[0].type == token.COMMENT) + return (NodeName(node) == 'simple_stmt' and + node.children[0].type == token.COMMENT) diff --git a/yapf/pytree/pytree_visitor.py b/yapf/pytree/pytree_visitor.py index 1cc2819f6..314431e84 100644 --- a/yapf/pytree/pytree_visitor.py +++ b/yapf/pytree/pytree_visitor.py @@ -117,7 +117,7 @@ def __init__(self, target_stream=sys.stdout): target_stream: the stream to dump the tree to. A file-like object. By default will dump into stdout. """ - self._target_stream = target_stream + self._target_stream = target_stream self._current_indent = 0 def _DumpString(self, s): diff --git a/yapf/pytree/split_penalty.py b/yapf/pytree/split_penalty.py index 8dc8056d3..f51fe1b73 100644 --- a/yapf/pytree/split_penalty.py +++ b/yapf/pytree/split_penalty.py @@ -26,30 +26,30 @@ # TODO(morbo): Document the annotations in a centralized place. E.g., the # README file. -UNBREAKABLE = 1000 * 1000 -NAMED_ASSIGN = 15000 -DOTTED_NAME = 4000 +UNBREAKABLE = 1000 * 1000 +NAMED_ASSIGN = 15000 +DOTTED_NAME = 4000 VERY_STRONGLY_CONNECTED = 3500 -STRONGLY_CONNECTED = 3000 -CONNECTED = 500 -TOGETHER = 100 - -OR_TEST = 1000 -AND_TEST = 1100 -NOT_TEST = 1200 -COMPARISON = 1300 -STAR_EXPR = 1300 -EXPR = 1400 -XOR_EXPR = 1500 -AND_EXPR = 1700 -SHIFT_EXPR = 1800 -ARITH_EXPR = 1900 -TERM = 2000 -FACTOR = 2100 -POWER = 2200 -ATOM = 2300 +STRONGLY_CONNECTED = 3000 +CONNECTED = 500 +TOGETHER = 100 + +OR_TEST = 1000 +AND_TEST = 1100 +NOT_TEST = 1200 +COMPARISON = 1300 +STAR_EXPR = 1300 +EXPR = 1400 +XOR_EXPR = 1500 +AND_EXPR = 1700 +SHIFT_EXPR = 1800 +ARITH_EXPR = 1900 +TERM = 2000 +FACTOR = 2100 +POWER = 2200 +ATOM = 2300 ONE_ELEMENT_ARGUMENT = 500 -SUBSCRIPT = 6000 +SUBSCRIPT = 6000 def ComputeSplitPenalties(tree): @@ -210,10 +210,10 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name # trailer ::= '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME if node.children[0].value == '.': before = style.Get('SPLIT_BEFORE_DOT') - _SetSplitPenalty( - node.children[0], VERY_STRONGLY_CONNECTED if before else DOTTED_NAME) - _SetSplitPenalty( - node.children[1], DOTTED_NAME if before else VERY_STRONGLY_CONNECTED) + _SetSplitPenalty(node.children[0], + VERY_STRONGLY_CONNECTED if before else DOTTED_NAME) + _SetSplitPenalty(node.children[1], + DOTTED_NAME if before else VERY_STRONGLY_CONNECTED) elif len(node.children) == 2: # Don't split an empty argument list if at all possible. _SetSplitPenalty(node.children[1], VERY_STRONGLY_CONNECTED) @@ -237,12 +237,10 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name _SetStronglyConnected(node.children[1].children[2]) # Still allow splitting around the operator. - split_before = ( - ( - name.endswith('_test') and - style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR')) or ( - name.endswith('_expr') and - style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'))) + split_before = ((name.endswith('_test') and + style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR')) or + (name.endswith('_expr') and + style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'))) if split_before: _SetSplitPenalty( pytree_utils.LastLeafNode(node.children[1].children[1]), 0) @@ -251,11 +249,12 @@ def Visit_trailer(self, node): # pylint: disable=invalid-name pytree_utils.FirstLeafNode(node.children[1].children[2]), 0) # Don't split the ending bracket of a subscript list. - _RecAnnotate( - node.children[-1], pytree_utils.Annotation.SPLIT_PENALTY, - VERY_STRONGLY_CONNECTED) - elif name not in {'arglist', 'argument', 'term', 'or_test', 'and_test', - 'comparison', 'atom', 'power'}: + _RecAnnotate(node.children[-1], pytree_utils.Annotation.SPLIT_PENALTY, + VERY_STRONGLY_CONNECTED) + elif name not in { + 'arglist', 'argument', 'term', 'or_test', 'and_test', 'comparison', + 'atom', 'power' + }: # Don't split an argument list with one element if at all possible. stypes = pytree_utils.GetNodeAnnotation( pytree_utils.FirstLeafNode(node), pytree_utils.Annotation.SUBTYPE) @@ -296,7 +295,7 @@ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring prev_trailer_idx = 1 while prev_trailer_idx < len(node.children) - 1: cur_trailer_idx = prev_trailer_idx + 1 - cur_trailer = node.children[cur_trailer_idx] + cur_trailer = node.children[cur_trailer_idx] if pytree_utils.NodeName(cur_trailer) != 'trailer': break @@ -370,8 +369,8 @@ def Visit_old_comp_for(self, node): # pylint: disable=invalid-name def Visit_comp_if(self, node): # pylint: disable=invalid-name # comp_if ::= 'if' old_test [comp_iter] - _SetSplitPenalty( - node.children[0], style.Get('SPLIT_PENALTY_BEFORE_IF_EXPR')) + _SetSplitPenalty(node.children[0], + style.Get('SPLIT_PENALTY_BEFORE_IF_EXPR')) _SetStronglyConnected(*node.children[1:]) self.DefaultNodeVisit(node) @@ -515,8 +514,8 @@ def _SetUnbreakable(node): def _SetStronglyConnected(*nodes): """Set a STRONGLY_CONNECTED penalty annotation for the given nodes.""" for node in nodes: - _RecAnnotate( - node, pytree_utils.Annotation.SPLIT_PENALTY, STRONGLY_CONNECTED) + _RecAnnotate(node, pytree_utils.Annotation.SPLIT_PENALTY, + STRONGLY_CONNECTED) def _SetExpressionPenalty(node, penalty): @@ -630,5 +629,5 @@ def _DecrementSplitPenalty(node, amt): def _SetSplitPenalty(node, penalty): - pytree_utils.SetNodeAnnotation( - node, pytree_utils.Annotation.SPLIT_PENALTY, penalty) + pytree_utils.SetNodeAnnotation(node, pytree_utils.Annotation.SPLIT_PENALTY, + penalty) diff --git a/yapf/pytree/subtype_assigner.py b/yapf/pytree/subtype_assigner.py index 06d1411f8..5cd0aea37 100644 --- a/yapf/pytree/subtype_assigner.py +++ b/yapf/pytree/subtype_assigner.py @@ -66,7 +66,7 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name for child in node.children: self.Visit(child) - comp_for = False + comp_for = False dict_maker = False for child in node.children: @@ -78,7 +78,7 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name if not comp_for and dict_maker: last_was_colon = False - unpacking = False + unpacking = False for child in node.children: if child.type == grammar_token.DOUBLESTAR: _AppendFirstLeafTokenSubtype(child, subtypes.KWARGS_STAR_STAR) @@ -248,15 +248,13 @@ def Visit_arglist(self, node): # pylint: disable=invalid-name # | '*' test (',' argument)* [',' '**' test] # | '**' test) self._ProcessArgLists(node) - _SetArgListSubtype( - node, subtypes.DEFAULT_OR_NAMED_ASSIGN, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) + _SetArgListSubtype(node, subtypes.DEFAULT_OR_NAMED_ASSIGN, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) def Visit_tname(self, node): # pylint: disable=invalid-name self._ProcessArgLists(node) - _SetArgListSubtype( - node, subtypes.DEFAULT_OR_NAMED_ASSIGN, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) + _SetArgListSubtype(node, subtypes.DEFAULT_OR_NAMED_ASSIGN, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) def Visit_decorator(self, node): # pylint: disable=invalid-name # decorator ::= @@ -290,9 +288,8 @@ def Visit_typedargslist(self, node): # pylint: disable=invalid-name # | '**' tname) # | tfpdef ['=' test] (',' tfpdef ['=' test])* [',']) self._ProcessArgLists(node) - _SetArgListSubtype( - node, subtypes.DEFAULT_OR_NAMED_ASSIGN, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) + _SetArgListSubtype(node, subtypes.DEFAULT_OR_NAMED_ASSIGN, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST) tname = False if not node.children: return @@ -303,7 +300,7 @@ def Visit_typedargslist(self, node): # pylint: disable=invalid-name tname = pytree_utils.NodeName(node.children[0]) == 'tname' for i in range(1, len(node.children)): prev_child = node.children[i - 1] - child = node.children[i] + child = node.children[i] if prev_child.type == grammar_token.COMMA: _AppendFirstLeafTokenSubtype(child, subtypes.PARAMETER_START) elif child.type == grammar_token.COMMA: @@ -311,8 +308,8 @@ def Visit_typedargslist(self, node): # pylint: disable=invalid-name if pytree_utils.NodeName(child) == 'tname': tname = True - _SetArgListSubtype( - child, subtypes.TYPED_NAME, subtypes.TYPED_NAME_ARG_LIST) + _SetArgListSubtype(child, subtypes.TYPED_NAME, + subtypes.TYPED_NAME_ARG_LIST) elif child.type == grammar_token.COMMA: tname = False elif child.type == grammar_token.EQUAL and tname: @@ -336,8 +333,8 @@ def Visit_comp_for(self, node): # pylint: disable=invalid-name _AppendSubtypeRec(node, subtypes.COMP_FOR) # Mark the previous node as COMP_EXPR unless this is a nested comprehension # as these will have the outer comprehension as their previous node. - attr = pytree_utils.GetNodeAnnotation( - node.parent, pytree_utils.Annotation.SUBTYPE) + attr = pytree_utils.GetNodeAnnotation(node.parent, + pytree_utils.Annotation.SUBTYPE) if not attr or subtypes.COMP_FOR not in attr: _AppendSubtypeRec(node.parent.children[0], subtypes.COMP_EXPR) self.DefaultNodeVisit(node) @@ -393,8 +390,8 @@ def HasSubtype(node): def _AppendTokenSubtype(node, subtype): """Append the token's subtype only if it's not already set.""" - pytree_utils.AppendNodeAnnotation( - node, pytree_utils.Annotation.SUBTYPE, subtype) + pytree_utils.AppendNodeAnnotation(node, pytree_utils.Annotation.SUBTYPE, + subtype) def _AppendFirstLeafTokenSubtype(node, subtype): @@ -431,14 +428,14 @@ def _InsertPseudoParentheses(node): node.children[-1].remove() first = pytree_utils.FirstLeafNode(node) - last = pytree_utils.LastLeafNode(node) + last = pytree_utils.LastLeafNode(node) if first == last and first.type == grammar_token.COMMENT: # A comment was inserted before the value, which is a pytree.Leaf. # Encompass the dictionary's value into an ATOM node. - last = first.next_sibling + last = first.next_sibling last_clone = last.clone() - new_node = pytree.Node(syms.atom, [first.clone(), last_clone]) + new_node = pytree.Node(syms.atom, [first.clone(), last_clone]) for orig_leaf, clone_leaf in zip(last.leaves(), last_clone.leaves()): pytree_utils.CopyYapfAnnotations(orig_leaf, clone_leaf) if hasattr(orig_leaf, 'is_pseudo'): @@ -449,7 +446,7 @@ def _InsertPseudoParentheses(node): last.remove() first = pytree_utils.FirstLeafNode(node) - last = pytree_utils.LastLeafNode(node) + last = pytree_utils.LastLeafNode(node) lparen = pytree.Leaf( grammar_token.LPAR, diff --git a/yapf/third_party/yapf_diff/yapf_diff.py b/yapf/third_party/yapf_diff/yapf_diff.py index f069aedcb..810a6a2d4 100644 --- a/yapf/third_party/yapf_diff/yapf_diff.py +++ b/yapf/third_party/yapf_diff/yapf_diff.py @@ -83,7 +83,7 @@ def main(): args = parser.parse_args() # Extract changed lines for each file. - filename = None + filename = None lines_by_file = {} for line in sys.stdin: match = re.search(r'^\+\+\+\ (.*?/){%s}(\S*)' % args.prefix, line) @@ -134,9 +134,8 @@ def main(): with open(filename) as f: code = f.readlines() formatted_code = StringIO(stdout).readlines() - diff = difflib.unified_diff( - code, formatted_code, filename, filename, '(before formatting)', - '(after formatting)') + diff = difflib.unified_diff(code, formatted_code, filename, filename, + '(before formatting)', '(after formatting)') diff_string = ''.join(diff) if len(diff_string) > 0: sys.stdout.write(diff_string) diff --git a/yapf/yapflib/errors.py b/yapf/yapflib/errors.py index cb8694d2c..99e88d9c0 100644 --- a/yapf/yapflib/errors.py +++ b/yapf/yapflib/errors.py @@ -32,8 +32,8 @@ def FormatErrorMsg(e): if isinstance(e, SyntaxError): return '{}:{}:{}: {}'.format(e.filename, e.lineno, e.offset, e.msg) if isinstance(e, tokenize.TokenError): - return '{}:{}:{}: {}'.format( - e.filename, e.args[1][0], e.args[1][1], e.args[0]) + return '{}:{}:{}: {}'.format(e.filename, e.args[1][0], e.args[1][1], + e.args[0]) return '{}:{}:{}: {}'.format(e.args[1][0], e.args[1][1], e.args[1][2], e.msg) diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 9c071db3d..b5e2612bd 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -25,8 +25,8 @@ from yapf.yapflib import py3compat from yapf.yapflib import style -CR = '\r' -LF = '\n' +CR = '\r' +LF = '\n' CRLF = '\r\n' @@ -56,7 +56,7 @@ def _GetExcludePatternsFromPyprojectToml(filename): "configuration file") if os.path.isfile(filename) and os.access(filename, os.R_OK): - pyproject_toml = toml.load(filename) + pyproject_toml = toml.load(filename) ignore_patterns = pyproject_toml.get('tool', {}).get('yapfignore', {}).get('ignore_patterns', []) @@ -140,7 +140,7 @@ def GetDefaultStyleForDir(dirname, default_style=style.DEFAULT_STYLE): "configuration file") pyproject_toml = toml.load(config_file) - style_dict = pyproject_toml.get('tool', {}).get('yapf', None) + style_dict = pyproject_toml.get('tool', {}).get('yapf', None) if style_dict is not None: return config_file @@ -161,8 +161,10 @@ def GetCommandLineFiles(command_line_file_list, recursive, exclude): return _FindPythonFiles(command_line_file_list, recursive, exclude) -def WriteReformattedCode( - filename, reformatted_code, encoding='', in_place=False): +def WriteReformattedCode(filename, + reformatted_code, + encoding='', + in_place=False): """Emit the reformatted code. Write the reformatted code into the file, if in_place is True. Otherwise, @@ -175,8 +177,8 @@ def WriteReformattedCode( in_place: (bool) If True, then write the reformatted code to the file. """ if in_place: - with py3compat.open_with_encoding(filename, mode='w', encoding=encoding, - newline='') as fd: + with py3compat.open_with_encoding( + filename, mode='w', encoding=encoding, newline='') as fd: fd.write(reformatted_code) else: py3compat.EncodeAndWriteToStdout(reformatted_code) @@ -263,8 +265,8 @@ def IsPythonFile(filename): encoding = py3compat.detect_encoding(fd.readline)[0] # Check for correctness of encoding. - with py3compat.open_with_encoding(filename, mode='r', - encoding=encoding) as fd: + with py3compat.open_with_encoding( + filename, mode='r', encoding=encoding) as fd: fd.read() except UnicodeDecodeError: encoding = 'latin-1' @@ -275,8 +277,8 @@ def IsPythonFile(filename): return False try: - with py3compat.open_with_encoding(filename, mode='r', - encoding=encoding) as fd: + with py3compat.open_with_encoding( + filename, mode='r', encoding=encoding) as fd: first_line = fd.readline(256) except IOError: return False diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 40bf5e25b..efcef0ba4 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -66,62 +66,59 @@ def __init__(self, line, first_indent): line: (LogicalLine) The logical line we're currently processing. first_indent: (int) The indent of the first token. """ - self.next_token = line.first - self.column = first_indent - self.line = line - self.paren_level = 0 - self.lowest_level_on_line = 0 + self.next_token = line.first + self.column = first_indent + self.line = line + self.paren_level = 0 + self.lowest_level_on_line = 0 self.ignore_stack_for_comparison = False - self.stack = [_ParenState(first_indent, first_indent)] - self.comp_stack = [] - self.param_list_stack = [] - self.first_indent = first_indent - self.column_limit = style.Get('COLUMN_LIMIT') + self.stack = [_ParenState(first_indent, first_indent)] + self.comp_stack = [] + self.param_list_stack = [] + self.first_indent = first_indent + self.column_limit = style.Get('COLUMN_LIMIT') def Clone(self): """Clones a FormatDecisionState object.""" - new = FormatDecisionState(self.line, self.first_indent) - new.next_token = self.next_token - new.column = self.column - new.line = self.line - new.paren_level = self.paren_level - new.line.depth = self.line.depth - new.lowest_level_on_line = self.lowest_level_on_line + new = FormatDecisionState(self.line, self.first_indent) + new.next_token = self.next_token + new.column = self.column + new.line = self.line + new.paren_level = self.paren_level + new.line.depth = self.line.depth + new.lowest_level_on_line = self.lowest_level_on_line new.ignore_stack_for_comparison = self.ignore_stack_for_comparison - new.first_indent = self.first_indent - new.stack = [state.Clone() for state in self.stack] - new.comp_stack = [state.Clone() for state in self.comp_stack] - new.param_list_stack = [state.Clone() for state in self.param_list_stack] + new.first_indent = self.first_indent + new.stack = [state.Clone() for state in self.stack] + new.comp_stack = [state.Clone() for state in self.comp_stack] + new.param_list_stack = [state.Clone() for state in self.param_list_stack] return new def __eq__(self, other): # Note: 'first_indent' is implicit in the stack. Also, we ignore 'previous', # because it shouldn't have a bearing on this comparison. (I.e., it will # report equal if 'next_token' does.) - return ( - self.next_token == other.next_token and self.column == other.column and - self.paren_level == other.paren_level and - self.line.depth == other.line.depth and - self.lowest_level_on_line == other.lowest_level_on_line and ( - self.ignore_stack_for_comparison or - other.ignore_stack_for_comparison or self.stack == other.stack and - self.comp_stack == other.comp_stack and - self.param_list_stack == other.param_list_stack)) + return (self.next_token == other.next_token and + self.column == other.column and + self.paren_level == other.paren_level and + self.line.depth == other.line.depth and + self.lowest_level_on_line == other.lowest_level_on_line and + (self.ignore_stack_for_comparison or + other.ignore_stack_for_comparison or self.stack == other.stack and + self.comp_stack == other.comp_stack and + self.param_list_stack == other.param_list_stack)) def __ne__(self, other): return not self == other def __hash__(self): - return hash( - ( - self.next_token, self.column, self.paren_level, self.line.depth, - self.lowest_level_on_line)) + return hash((self.next_token, self.column, self.paren_level, + self.line.depth, self.lowest_level_on_line)) def __repr__(self): - return ( - 'column::%d, next_token::%s, paren_level::%d, stack::[\n\t%s' % ( - self.column, repr(self.next_token), self.paren_level, - '\n\t'.join(repr(s) for s in self.stack) + ']')) + return ('column::%d, next_token::%s, paren_level::%d, stack::[\n\t%s' % + (self.column, repr(self.next_token), self.paren_level, + '\n\t'.join(repr(s) for s in self.stack) + ']')) def CanSplit(self, must_split): """Determine if we can split before the next token. @@ -132,7 +129,7 @@ def CanSplit(self, must_split): Returns: True if the line can be split before the next token. """ - current = self.next_token + current = self.next_token previous = current.previous_token if current.is_pseudo: @@ -169,7 +166,7 @@ def CanSplit(self, must_split): def MustSplit(self): """Returns True if the line must split before the next token.""" - current = self.next_token + current = self.next_token previous = current.previous_token if current.is_pseudo: @@ -292,7 +289,7 @@ def SurroundedByParens(token): # # or when a string formatting syntax. func_call_or_string_format = False - tok = current.next_token + tok = current.next_token if current.is_name: while tok and (tok.is_name or tok.value == '.'): tok = tok.next_token @@ -424,7 +421,7 @@ def SurroundedByParens(token): (opening.previous_token.is_name or opening.previous_token.value in {'*', '**'})): is_func_call = False - opening = current + opening = current while opening: if opening.value == '(': is_func_call = True @@ -455,7 +452,7 @@ def SurroundedByParens(token): # default=False) if (current.value == '{' and previous.value == '(' and pprevious and pprevious.is_name): - dict_end = current.matching_bracket + dict_end = current.matching_bracket next_token = dict_end.next_token if next_token.value == ',' and not self._FitsOnLine(current, dict_end): return True @@ -486,7 +483,7 @@ def SurroundedByParens(token): (opening.previous_token.is_name or opening.previous_token.value in {'*', '**'})): is_func_call = False - opening = current + opening = current while opening: if opening.value == '(': is_func_call = True @@ -525,7 +522,7 @@ def SurroundedByParens(token): return False elements = previous.container_elements + [previous.matching_bracket] - i = 1 + i = 1 while i < len(elements): if (not elements[i - 1].OpensScope() and not self._FitsOnLine(elements[i - 1], elements[i])): @@ -597,7 +594,7 @@ def _AddTokenOnCurrentLine(self, dry_run): Arguments: dry_run: (bool) Commit whitespace changes to the FormatToken if True. """ - current = self.next_token + current = self.next_token previous = current.previous_token spaces = current.spaces_required_before @@ -640,14 +637,14 @@ def _AddTokenOnNewline(self, dry_run, must_split): Returns: The split penalty for splitting after the current state. """ - current = self.next_token + current = self.next_token previous = current.previous_token self.column = self._GetNewlineColumn() if not dry_run: indent_level = self.line.depth - spaces = self.column + spaces = self.column if spaces: spaces -= indent_level * style.Get('INDENT_WIDTH') current.AddWhitespacePrefix( @@ -660,7 +657,7 @@ def _AddTokenOnNewline(self, dry_run, must_split): if (previous.OpensScope() or (previous.is_comment and previous.previous_token is not None and previous.previous_token.OpensScope())): - dedent = (style.Get('CONTINUATION_INDENT_WIDTH'), + dedent = (style.Get('CONTINUATION_INDENT_WIDTH'), 0)[style.Get('INDENT_CLOSING_BRACKETS')] self.stack[-1].closing_scope_indent = ( max(0, self.stack[-1].indent - dedent)) @@ -680,9 +677,9 @@ def _AddTokenOnNewline(self, dry_run, must_split): # Add a penalty for each increasing newline we add, but don't penalize for # splitting before an if-expression or list comprehension. if current.value not in {'if', 'for'}: - last = self.stack[-1] + last = self.stack[-1] last.num_line_splits += 1 - penalty += ( + penalty += ( style.Get('SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT') * last.num_line_splits) @@ -707,13 +704,13 @@ def MoveStateToNextToken(self): """ current = self.next_token if not current.OpensScope() and not current.ClosesScope(): - self.lowest_level_on_line = min( - self.lowest_level_on_line, self.paren_level) + self.lowest_level_on_line = min(self.lowest_level_on_line, + self.paren_level) # If we encounter an opening bracket, we add a level to our stack to prepare # for the subsequent tokens. if current.OpensScope(): - last = self.stack[-1] + last = self.stack[-1] new_indent = style.Get('CONTINUATION_INDENT_WIDTH') + last.last_space self.stack.append(_ParenState(new_indent, self.stack[-1].last_space)) @@ -743,7 +740,7 @@ def MoveStateToNextToken(self): if (not current.is_pylint_comment and not current.is_pytype_comment and not current.is_copybara_comment and self.column > self.column_limit): excess_characters = self.column - self.column_limit - penalty += style.Get('SPLIT_PENALTY_EXCESS_CHARACTER') * excess_characters + penalty += style.Get('SPLIT_PENALTY_EXCESS_CHARACTER') * excess_characters if is_multiline_string: # If this is a multiline string, the column is actually the @@ -762,10 +759,10 @@ def _CalculateComprehensionState(self, newline): The penalty for the token-newline combination given the current comprehension state. """ - current = self.next_token - previous = current.previous_token + current = self.next_token + previous = current.previous_token top_of_stack = self.comp_stack[-1] if self.comp_stack else None - penalty = 0 + penalty = 0 if top_of_stack is not None: # Check if the token terminates the current comprehension. @@ -801,7 +798,7 @@ def _CalculateComprehensionState(self, newline): not top_of_stack.HasTrivialExpr())): penalty += split_penalty.UNBREAKABLE else: - top_of_stack.for_token = current + top_of_stack.for_token = current top_of_stack.has_split_at_for = newline # Try to keep trivial expressions on the same line as the comp_for. @@ -826,14 +823,14 @@ def _PushParameterListState(self, newline): Args: newline: Whether the current token is to be added on a newline. """ - current = self.next_token + current = self.next_token previous = current.previous_token if _IsFunctionDefinition(previous): first_param_column = previous.total_length + self.stack[-2].indent self.param_list_stack.append( - object_state.ParameterListState( - previous, newline, first_param_column)) + object_state.ParameterListState(previous, newline, + first_param_column)) def _CalculateParameterListState(self, newline): """Makes required changes to parameter list state. @@ -845,18 +842,18 @@ def _CalculateParameterListState(self, newline): The penalty for the token-newline combination given the current parameter state. """ - current = self.next_token + current = self.next_token previous = current.previous_token - penalty = 0 + penalty = 0 if _IsFunctionDefinition(previous): first_param_column = previous.total_length + self.stack[-2].indent if not newline: param_list = self.param_list_stack[-1] if param_list.parameters and param_list.has_typed_return: - last_param = param_list.parameters[-1].first_token - last_token = _LastTokenInLine(previous.matching_bracket) - total_length = last_token.total_length + last_param = param_list.parameters[-1].first_token + last_token = _LastTokenInLine(previous.matching_bracket) + total_length = last_token.total_length total_length -= last_param.total_length - len(last_param.value) if total_length + self.column > self.column_limit: # If we need to split before the trailing code of a function @@ -924,9 +921,8 @@ def _IndentWithContinuationAlignStyle(self, column): return column align_style = style.Get('CONTINUATION_ALIGN_STYLE') if align_style == 'FIXED': - return ( - (self.line.depth * style.Get('INDENT_WIDTH')) + - style.Get('CONTINUATION_INDENT_WIDTH')) + return ((self.line.depth * style.Get('INDENT_WIDTH')) + + style.Get('CONTINUATION_INDENT_WIDTH')) if align_style == 'VALIGN-RIGHT': indent_width = style.Get('INDENT_WIDTH') return indent_width * int((column + indent_width - 1) / indent_width) @@ -934,8 +930,8 @@ def _IndentWithContinuationAlignStyle(self, column): def _GetNewlineColumn(self): """Return the new column on the newline.""" - current = self.next_token - previous = current.previous_token + current = self.next_token + previous = current.previous_token top_of_stack = self.stack[-1] if isinstance(current.spaces_required_before, list): @@ -955,8 +951,8 @@ def _GetNewlineColumn(self): if (previous.OpensScope() or (previous.is_comment and previous.previous_token is not None and previous.previous_token.OpensScope())): - return max( - 0, top_of_stack.indent - style.Get('CONTINUATION_INDENT_WIDTH')) + return max(0, + top_of_stack.indent - style.Get('CONTINUATION_INDENT_WIDTH')) return top_of_stack.closing_scope_indent if (previous and previous.is_string and current.is_string and @@ -1012,7 +1008,7 @@ def ImplicitStringConcatenation(tok): tok = tok.next_token while tok.is_string: num_strings += 1 - tok = tok.next_token + tok = tok.next_token return num_strings > 1 def DictValueIsContainer(opening, closing): @@ -1031,9 +1027,9 @@ def DictValueIsContainer(opening, closing): return False return subtypes.DICTIONARY_KEY_PART in key.subtypes - closing = opening.matching_bracket + closing = opening.matching_bracket entry_start = opening.next_token - current = opening.next_token.next_token + current = opening.next_token.next_token while current and current != closing: if subtypes.DICTIONARY_KEY in current.subtypes: @@ -1041,7 +1037,7 @@ def DictValueIsContainer(opening, closing): if prev.value == ',': prev = PreviousNonCommentToken(prev.previous_token) if not DictValueIsContainer(prev.matching_bracket, prev): - length = prev.total_length - entry_start.total_length + length = prev.total_length - entry_start.total_length length += len(entry_start.value) if length + self.stack[-2].indent >= self.column_limit: return False @@ -1073,7 +1069,7 @@ def DictValueIsContainer(opening, closing): # At this point, current is the closing bracket. Go back one to get the end # of the dictionary entry. current = PreviousNonCommentToken(current) - length = current.total_length - entry_start.total_length + length = current.total_length - entry_start.total_length length += len(entry_start.value) return length + self.stack[-2].indent <= self.column_limit @@ -1093,9 +1089,8 @@ def _ArgumentListHasDictionaryEntry(self, token): def _ContainerFitsOnStartLine(self, opening): """Check if the container can fit on its starting line.""" - return ( - opening.matching_bracket.total_length - opening.total_length + - self.stack[-1].indent) <= self.column_limit + return (opening.matching_bracket.total_length - opening.total_length + + self.stack[-1].indent) <= self.column_limit _COMPOUND_STMTS = frozenset( @@ -1171,8 +1166,8 @@ def _IsLastScopeInLine(current): def _IsSingleElementTuple(token): """Check if it's a single-element tuple.""" - close = token.matching_bracket - token = token.next_token + close = token.matching_bracket + token = token.next_token num_commas = 0 while token != close: if token.value == ',': @@ -1213,17 +1208,17 @@ class _ParenState(object): # TODO(morbo): This doesn't track "bin packing." def __init__(self, indent, last_space): - self.indent = indent - self.last_space = last_space - self.closing_scope_indent = 0 + self.indent = indent + self.last_space = last_space + self.closing_scope_indent = 0 self.split_before_closing_bracket = False - self.num_line_splits = 0 + self.num_line_splits = 0 def Clone(self): - state = _ParenState(self.indent, self.last_space) - state.closing_scope_indent = self.closing_scope_indent + state = _ParenState(self.indent, self.last_space) + state.closing_scope_indent = self.closing_scope_indent state.split_before_closing_bracket = self.split_before_closing_bracket - state.num_line_splits = self.num_line_splits + state.num_line_splits = self.num_line_splits return state def __repr__(self): @@ -1237,7 +1232,5 @@ def __ne__(self, other): return not self == other def __hash__(self, *args, **kwargs): - return hash( - ( - self.indent, self.last_space, self.closing_scope_indent, - self.split_before_closing_bracket, self.num_line_splits)) + return hash((self.indent, self.last_space, self.closing_scope_indent, + self.split_before_closing_bracket, self.num_line_splits)) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 382f5f938..549271705 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -90,27 +90,27 @@ def __init__(self, node, name): node: (pytree.Leaf) The node that's being wrapped. name: (string) The name of the node. """ - self.node = node - self.name = name - self.type = node.type + self.node = node + self.name = name + self.type = node.type self.column = node.column self.lineno = node.lineno - self.value = node.value + self.value = node.value if self.is_continuation: self.value = node.value.rstrip() - self.next_token = None - self.previous_token = None - self.matching_bracket = None - self.parameters = [] - self.container_opening = None + self.next_token = None + self.previous_token = None + self.matching_bracket = None + self.parameters = [] + self.container_opening = None self.container_elements = [] - self.whitespace_prefix = '' - self.total_length = 0 - self.split_penalty = 0 - self.can_break_before = False - self.must_break_before = pytree_utils.GetNodeAnnotation( + self.whitespace_prefix = '' + self.total_length = 0 + self.split_penalty = 0 + self.can_break_before = False + self.must_break_before = pytree_utils.GetNodeAnnotation( node, pytree_utils.Annotation.MUST_SPLIT, default=False) self.newlines = pytree_utils.GetNodeAnnotation( node, pytree_utils.Annotation.NEWLINES) @@ -119,16 +119,16 @@ def __init__(self, node, name): if self.is_comment: self.spaces_required_before = style.Get('SPACES_BEFORE_COMMENT') - stypes = pytree_utils.GetNodeAnnotation( - node, pytree_utils.Annotation.SUBTYPE) - self.subtypes = {subtypes.NONE} if not stypes else stypes + stypes = pytree_utils.GetNodeAnnotation(node, + pytree_utils.Annotation.SUBTYPE) + self.subtypes = {subtypes.NONE} if not stypes else stypes self.is_pseudo = hasattr(node, 'is_pseudo') and node.is_pseudo @property def formatted_whitespace_prefix(self): if style.Get('INDENT_BLANK_LINES'): without_newlines = self.whitespace_prefix.lstrip('\n') - height = len(self.whitespace_prefix) - len(without_newlines) + height = len(self.whitespace_prefix) - len(without_newlines) if height: return ('\n' + without_newlines) * height return self.whitespace_prefix @@ -151,26 +151,26 @@ def AddWhitespacePrefix(self, newlines_before, spaces=0, indent_level=0): else: indent_before = '\t' * indent_level + ' ' * spaces else: - indent_before = ( - ' ' * indent_level * style.Get('INDENT_WIDTH') + ' ' * spaces) + indent_before = (' ' * indent_level * style.Get('INDENT_WIDTH') + + ' ' * spaces) if self.is_comment: comment_lines = [s.lstrip() for s in self.value.splitlines()] - self.value = ('\n' + indent_before).join(comment_lines) + self.value = ('\n' + indent_before).join(comment_lines) # Update our own value since we are changing node value self.value = self.value if not self.whitespace_prefix: - self.whitespace_prefix = ( - '\n' * (self.newlines or newlines_before) + indent_before) + self.whitespace_prefix = ('\n' * (self.newlines or newlines_before) + + indent_before) else: self.whitespace_prefix += indent_before def AdjustNewlinesBefore(self, newlines_before): """Change the number of newlines before this token.""" - self.whitespace_prefix = ( - '\n' * newlines_before + self.whitespace_prefix.lstrip('\n')) + self.whitespace_prefix = ('\n' * newlines_before + + self.whitespace_prefix.lstrip('\n')) def RetainHorizontalSpacing(self, first_column, depth): """Retains a token's horizontal spacing.""" @@ -183,7 +183,7 @@ def RetainHorizontalSpacing(self, first_column, depth): if not previous: return - cur_lineno = self.lineno + cur_lineno = self.lineno prev_lineno = previous.lineno if previous.is_multiline_string: prev_lineno += previous.value.count('\n') @@ -195,13 +195,13 @@ def RetainHorizontalSpacing(self, first_column, depth): self.column - first_column + depth * style.Get('INDENT_WIDTH')) return - cur_column = self.column + cur_column = self.column prev_column = previous.column - prev_len = len(previous.value) + prev_len = len(previous.value) if previous.is_pseudo and previous.value == ')': prev_column -= 1 - prev_len = 0 + prev_len = 0 if previous.is_multiline_string: prev_len = len(previous.value.split('\n')[-1]) @@ -220,11 +220,10 @@ def AddSubtype(self, subtype): self.subtypes.add(subtype) def __repr__(self): - msg = ( - 'FormatToken(name={0}, value={1}, column={2}, lineno={3}, ' - 'splitpenalty={4}'.format( - 'DOCSTRING' if self.is_docstring else self.name, self.value, - self.column, self.lineno, self.split_penalty)) + msg = ('FormatToken(name={0}, value={1}, column={2}, lineno={3}, ' + 'splitpenalty={4}'.format( + 'DOCSTRING' if self.is_docstring else self.name, self.value, + self.column, self.lineno, self.split_penalty)) msg += ', pseudo)' if self.is_pseudo else ')' return msg @@ -243,22 +242,21 @@ def is_binary_op(self): @py3compat.lru_cache() def is_arithmetic_op(self): """Token is an arithmetic operator.""" - return self.value in frozenset( - { - '+', # Add - '-', # Subtract - '*', # Multiply - '@', # Matrix Multiply - '/', # Divide - '//', # Floor Divide - '%', # Modulo - '<<', # Left Shift - '>>', # Right Shift - '|', # Bitwise Or - '&', # Bitwise Add - '^', # Bitwise Xor - '**', # Power - }) + return self.value in frozenset({ + '+', # Add + '-', # Subtract + '*', # Multiply + '@', # Matrix Multiply + '/', # Divide + '//', # Floor Divide + '%', # Modulo + '<<', # Left Shift + '>>', # Right Shift + '|', # Bitwise Or + '&', # Bitwise Add + '^', # Bitwise Xor + '**', # Power + }) @property def is_simple_expr(self): @@ -312,13 +310,13 @@ def is_docstring(self): @property def is_pylint_comment(self): - return self.is_comment and re.match( - r'#.*\bpylint:\s*(disable|enable)=', self.value) + return self.is_comment and re.match(r'#.*\bpylint:\s*(disable|enable)=', + self.value) @property def is_pytype_comment(self): - return self.is_comment and re.match( - r'#.*\bpytype:\s*(disable|enable)=', self.value) + return self.is_comment and re.match(r'#.*\bpytype:\s*(disable|enable)=', + self.value) @property def is_copybara_comment(self): diff --git a/yapf/yapflib/logical_line.py b/yapf/yapflib/logical_line.py index 477d4d625..8c84b7ba8 100644 --- a/yapf/yapflib/logical_line.py +++ b/yapf/yapflib/logical_line.py @@ -49,7 +49,7 @@ def __init__(self, depth, tokens=None): depth: indentation depth of this line tokens: initial list of tokens """ - self.depth = depth + self.depth = depth self._tokens = tokens or [] self.disable = False @@ -57,7 +57,7 @@ def __init__(self, depth, tokens=None): # Set up a doubly linked list. for index, tok in enumerate(self._tokens[1:]): # Note, 'index' is the index to the previous token. - tok.previous_token = self._tokens[index] + tok.previous_token = self._tokens[index] self._tokens[index].next_token = tok def CalculateFormattingInformation(self): @@ -66,9 +66,9 @@ def CalculateFormattingInformation(self): # means only that if this logical line is joined with a predecessor line, # then there will be a space between them. self.first.spaces_required_before = 1 - self.first.total_length = len(self.first.value) + self.first.total_length = len(self.first.value) - prev_token = self.first + prev_token = self.first prev_length = self.first.total_length for token in self._tokens[1:]: if (token.spaces_required_before == 0 and @@ -93,13 +93,13 @@ def CalculateFormattingInformation(self): # The split penalty has to be computed before {must|can}_break_before, # because these may use it for their decision. - token.split_penalty += _SplitPenalty(prev_token, token) + token.split_penalty += _SplitPenalty(prev_token, token) token.must_break_before = _MustBreakBefore(prev_token, token) - token.can_break_before = ( + token.can_break_before = ( token.must_break_before or _CanBreakBefore(prev_token, token)) prev_length = token.total_length - prev_token = token + prev_token = token def Split(self): """Split the line at semicolons.""" @@ -107,7 +107,7 @@ def Split(self): return [self] llines = [] - lline = LogicalLine(self.depth) + lline = LogicalLine(self.depth) for tok in self._tokens: if tok.value == ';': llines.append(lline) @@ -120,7 +120,7 @@ def Split(self): for lline in llines: lline.first.previous_token = None - lline.last.next_token = None + lline.last.next_token = None return llines @@ -164,7 +164,7 @@ def AsCode(self, indent_per_depth=2): Returns: A string representing the line as code. """ - indent = ' ' * indent_per_depth * self.depth + indent = ' ' * indent_per_depth * self.depth tokens_str = ' '.join(tok.value for tok in self._tokens) return indent + tokens_str @@ -544,10 +544,10 @@ def _CanBreakBefore(prev_token, cur_token): def IsSurroundedByBrackets(tok): """Return True if the token is surrounded by brackets.""" - paren_count = 0 - brace_count = 0 + paren_count = 0 + brace_count = 0 sq_bracket_count = 0 - previous_token = tok.previous_token + previous_token = tok.previous_token while previous_token: if previous_token.value == ')': paren_count -= 1 @@ -580,10 +580,10 @@ def _IsDictListTupleDelimiterTok(tok, is_opening): return False if is_opening: - open_tok = tok + open_tok = tok close_tok = tok.matching_bracket else: - open_tok = tok.matching_bracket + open_tok = tok.matching_bracket close_tok = tok # There must be something in between the tokens @@ -600,8 +600,8 @@ def _IsDictListTupleDelimiterTok(tok, is_opening): ] -_LOGICAL_OPERATORS = frozenset({'and', 'or'}) -_BITWISE_OPERATORS = frozenset({'&', '|', '^'}) +_LOGICAL_OPERATORS = frozenset({'and', 'or'}) +_BITWISE_OPERATORS = frozenset({'&', '|', '^'}) _ARITHMETIC_OPERATORS = frozenset({'+', '-', '*', '/', '%', '//', '@'}) diff --git a/yapf/yapflib/object_state.py b/yapf/yapflib/object_state.py index 0afdb6041..ec259e682 100644 --- a/yapf/yapflib/object_state.py +++ b/yapf/yapflib/object_state.py @@ -45,9 +45,9 @@ class ComprehensionState(object): """ def __init__(self, expr_token): - self.expr_token = expr_token - self.for_token = None - self.has_split_at_for = False + self.expr_token = expr_token + self.for_token = None + self.has_split_at_for = False self.has_interior_split = False def HasTrivialExpr(self): @@ -63,18 +63,17 @@ def closing_bracket(self): return self.opening_bracket.matching_bracket def Clone(self): - clone = ComprehensionState(self.expr_token) - clone.for_token = self.for_token - clone.has_split_at_for = self.has_split_at_for + clone = ComprehensionState(self.expr_token) + clone.for_token = self.for_token + clone.has_split_at_for = self.has_split_at_for clone.has_interior_split = self.has_interior_split return clone def __repr__(self): - return ( - '[opening_bracket::%s, for_token::%s, has_split_at_for::%s,' - ' has_interior_split::%s, has_trivial_expr::%s]' % ( - self.opening_bracket, self.for_token, self.has_split_at_for, - self.has_interior_split, self.HasTrivialExpr())) + return ('[opening_bracket::%s, for_token::%s, has_split_at_for::%s,' + ' has_interior_split::%s, has_trivial_expr::%s]' % + (self.opening_bracket, self.for_token, self.has_split_at_for, + self.has_interior_split, self.HasTrivialExpr())) def __eq__(self, other): return hash(self) == hash(other) @@ -83,10 +82,8 @@ def __ne__(self, other): return not self == other def __hash__(self, *args, **kwargs): - return hash( - ( - self.expr_token, self.for_token, self.has_split_at_for, - self.has_interior_split)) + return hash((self.expr_token, self.for_token, self.has_split_at_for, + self.has_interior_split)) class ParameterListState(object): @@ -108,10 +105,10 @@ class ParameterListState(object): """ def __init__(self, opening_bracket, newline, opening_column): - self.opening_bracket = opening_bracket + self.opening_bracket = opening_bracket self.has_split_before_first_param = newline - self.opening_column = opening_column - self.parameters = opening_bracket.parameters + self.opening_column = opening_column + self.parameters = opening_bracket.parameters self.split_before_closing_bracket = False @property @@ -149,8 +146,8 @@ def LastParamFitsOnLine(self, indent): return False if not self.parameters: return True - total_length = self.last_token.total_length - last_param = self.parameters[-1].first_token + total_length = self.last_token.total_length + last_param = self.parameters[-1].first_token total_length -= last_param.total_length - len(last_param.value) return total_length + indent <= style.Get('COLUMN_LIMIT') @@ -163,25 +160,24 @@ def SplitBeforeClosingBracket(self, indent): return True if not self.parameters: return False - total_length = self.last_token.total_length - last_param = self.parameters[-1].first_token + total_length = self.last_token.total_length + last_param = self.parameters[-1].first_token total_length -= last_param.total_length - len(last_param.value) return total_length + indent > style.Get('COLUMN_LIMIT') def Clone(self): - clone = ParameterListState( - self.opening_bracket, self.has_split_before_first_param, - self.opening_column) + clone = ParameterListState(self.opening_bracket, + self.has_split_before_first_param, + self.opening_column) clone.split_before_closing_bracket = self.split_before_closing_bracket - clone.parameters = [param.Clone() for param in self.parameters] + clone.parameters = [param.Clone() for param in self.parameters] return clone def __repr__(self): - return ( - '[opening_bracket::%s, has_split_before_first_param::%s, ' - 'opening_column::%d]' % ( - self.opening_bracket, self.has_split_before_first_param, - self.opening_column)) + return ('[opening_bracket::%s, has_split_before_first_param::%s, ' + 'opening_column::%d]' % + (self.opening_bracket, self.has_split_before_first_param, + self.opening_column)) def __eq__(self, other): return hash(self) == hash(other) @@ -191,9 +187,8 @@ def __ne__(self, other): def __hash__(self, *args, **kwargs): return hash( - ( - self.opening_bracket, self.has_split_before_first_param, - self.opening_column, (hash(param) for param in self.parameters))) + (self.opening_bracket, self.has_split_before_first_param, + self.opening_column, (hash(param) for param in self.parameters))) class Parameter(object): @@ -207,7 +202,7 @@ class Parameter(object): def __init__(self, first_token, last_token): self.first_token = first_token - self.last_token = last_token + self.last_token = last_token @property @py3compat.lru_cache() @@ -224,8 +219,8 @@ def Clone(self): return Parameter(self.first_token, self.last_token) def __repr__(self): - return '[first_token::%s, last_token:%s]' % ( - self.first_token, self.last_token) + return '[first_token::%s, last_token:%s]' % (self.first_token, + self.last_token) def __eq__(self, other): return hash(self) == hash(other) diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py index 2ea5910d1..e4cb9788f 100644 --- a/yapf/yapflib/py3compat.py +++ b/yapf/yapflib/py3compat.py @@ -18,14 +18,14 @@ import os import sys -PY3 = sys.version_info[0] >= 3 +PY3 = sys.version_info[0] >= 3 PY36 = sys.version_info[0] >= 3 and sys.version_info[1] >= 6 PY37 = sys.version_info[0] >= 3 and sys.version_info[1] >= 7 PY38 = sys.version_info[0] >= 3 and sys.version_info[1] >= 8 if PY3: StringIO = io.StringIO - BytesIO = io.BytesIO + BytesIO = io.BytesIO import codecs # noqa: F811 @@ -35,7 +35,7 @@ def open_with_encoding(filename, mode, encoding, newline=''): # pylint: disable import functools lru_cache = functools.lru_cache - range = range + range = range ifilter = filter def raw_input(): @@ -50,7 +50,7 @@ def raw_input(): import tokenize detect_encoding = tokenize.detect_encoding - TokenInfo = tokenize.TokenInfo + TokenInfo = tokenize.TokenInfo else: import __builtin__ import cStringIO @@ -80,8 +80,8 @@ def fake_wrapper(user_function): import collections - class TokenInfo(collections.namedtuple('TokenInfo', - 'type string start end line')): + class TokenInfo( + collections.namedtuple('TokenInfo', 'type string start end line')): pass @@ -116,7 +116,7 @@ def EncodeAndWriteToStdout(s, encoding='utf-8'): if PY3: basestring = str - unicode = str # pylint: disable=redefined-builtin,invalid-name + unicode = str # pylint: disable=redefined-builtin,invalid-name else: basestring = basestring diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index ec196d8b3..90823aed7 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -49,8 +49,8 @@ def Reformat(llines, verify=False, lines=None): Returns: A string representing the reformatted code. """ - final_lines = [] - prev_line = None # The previous line. + final_lines = [] + prev_line = None # The previous line. indent_width = style.Get('INDENT_WIDTH') for lline in _SingleOrMergedLines(llines): @@ -58,7 +58,7 @@ def Reformat(llines, verify=False, lines=None): _FormatFirstToken(first_token, lline.depth, prev_line, final_lines) indent_amt = indent_width * lline.depth - state = format_decision_state.FormatDecisionState(lline, indent_amt) + state = format_decision_state.FormatDecisionState(lline, indent_amt) state.MoveStateToNextToken() if not lline.disable: @@ -69,8 +69,8 @@ def Reformat(llines, verify=False, lines=None): if prev_line and prev_line.disable: # Keep the vertical spacing between a disabled and enabled formatting # region. - _RetainRequiredVerticalSpacingBetweenTokens( - lline.first, prev_line.last, lines) + _RetainRequiredVerticalSpacingBetweenTokens(lline.first, prev_line.last, + lines) if any(tok.is_comment for tok in lline.tokens): _RetainVerticalSpacingBeforeComments(lline) @@ -160,11 +160,11 @@ def _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines): # Don't adjust between a comment and non-comment. pass elif lines and lines.intersection(range(prev_lineno, cur_lineno + 1)): - desired_newlines = cur_tok.whitespace_prefix.count('\n') - whitespace_lines = range(prev_lineno + 1, cur_lineno) - deletable_lines = len(lines.intersection(whitespace_lines)) - required_newlines = max( - required_newlines - deletable_lines, desired_newlines) + desired_newlines = cur_tok.whitespace_prefix.count('\n') + whitespace_lines = range(prev_lineno + 1, cur_lineno) + deletable_lines = len(lines.intersection(whitespace_lines)) + required_newlines = max(required_newlines - deletable_lines, + desired_newlines) cur_tok.AdjustNewlinesBefore(required_newlines) @@ -193,7 +193,7 @@ def _EmitLineUnformatted(state): state. """ while state.next_token: - previous_token = state.next_token.previous_token + previous_token = state.next_token.previous_token previous_lineno = previous_token.lineno if previous_token.is_multiline_string or previous_token.is_string: @@ -257,17 +257,16 @@ def _CanPlaceOnSingleLine(line): if (style.Get('FORCE_MULTILINE_DICT') and 'LBRACE' in token_names): return False indent_amt = style.Get('INDENT_WIDTH') * line.depth - last = line.last + last = line.last last_index = -1 if (last.is_pylint_comment or last.is_pytype_comment or last.is_copybara_comment): - last = last.previous_token + last = last.previous_token last_index = -2 if last is None: return True - return ( - last.total_length + indent_amt <= style.Get('COLUMN_LIMIT') and - not any(tok.is_comment for tok in line.tokens[:last_index])) + return (last.total_length + indent_amt <= style.Get('COLUMN_LIMIT') and + not any(tok.is_comment for tok in line.tokens[:last_index])) def _AlignTrailingComments(final_lines): @@ -289,7 +288,7 @@ def _AlignTrailingComments(final_lines): # first col value greater than that value and create the necessary for # each line accordingly. all_pc_line_lengths = [] # All pre-comment line lengths - max_line_length = 0 + max_line_length = 0 while True: # EOF @@ -311,7 +310,7 @@ def _AlignTrailingComments(final_lines): continue # Calculate the length of each line in this logical line. - line_content = '' + line_content = '' pc_line_lengths = [] for line_tok in this_line.tokens: @@ -320,7 +319,7 @@ def _AlignTrailingComments(final_lines): newline_index = whitespace_prefix.rfind('\n') if newline_index != -1: max_line_length = max(max_line_length, len(line_content)) - line_content = '' + line_content = '' whitespace_prefix = whitespace_prefix[newline_index + 1:] @@ -370,8 +369,8 @@ def _AlignTrailingComments(final_lines): for comment_line_index, comment_line in enumerate( line_tok.value.split('\n')): - line_content.append( - '{}{}'.format(whitespace, comment_line.strip())) + line_content.append('{}{}'.format(whitespace, + comment_line.strip())) if comment_line_index == 0: whitespace = ' ' * (aligned_col - 1) @@ -413,7 +412,7 @@ def _AlignAssignment(final_lines): if tok.is_assign or tok.is_augassign: # all pre assignment variable lengths in one block of lines all_pa_variables_lengths = [] - max_variables_length = 0 + max_variables_length = 0 while True: # EOF @@ -422,7 +421,7 @@ def _AlignAssignment(final_lines): break this_line_index = final_lines_index + len(all_pa_variables_lengths) - this_line = final_lines[this_line_index] + this_line = final_lines[this_line_index] next_line = None if this_line_index < len(final_lines) - 1: @@ -439,9 +438,9 @@ def _AlignAssignment(final_lines): # if there is a standalone comment or keyword statement line # or other lines without assignment in between, break - elif (all_pa_variables_lengths and - True not in [tok.is_assign or tok.is_augassign - for tok in this_line.tokens]): + elif (all_pa_variables_lengths and True not in [ + tok.is_assign or tok.is_augassign for tok in this_line.tokens + ]): if this_line.tokens[0].is_comment: if style.Get('NEW_ALIGNMENT_AFTER_COMMENTLINE'): break @@ -452,19 +451,19 @@ def _AlignAssignment(final_lines): all_pa_variables_lengths.append([]) continue - variables_content = '' + variables_content = '' pa_variables_lengths = [] - contain_object = False - line_tokens = this_line.tokens + contain_object = False + line_tokens = this_line.tokens # only one assignment expression is on each line for index in range(len(line_tokens)): line_tok = line_tokens[index] - prefix = line_tok.formatted_whitespace_prefix + prefix = line_tok.formatted_whitespace_prefix newline_index = prefix.rfind('\n') if newline_index != -1: variables_content = '' - prefix = prefix[newline_index + 1:] + prefix = prefix[newline_index + 1:] if line_tok.is_assign or line_tok.is_augassign: next_toks = [ @@ -495,8 +494,8 @@ def _AlignAssignment(final_lines): variables_content += '{}{}'.format(prefix, line_tok.value) if pa_variables_lengths: - max_variables_length = max( - max_variables_length, max(pa_variables_lengths)) + max_variables_length = max(max_variables_length, + max(pa_variables_lengths)) all_pa_variables_lengths.append(pa_variables_lengths) @@ -537,8 +536,8 @@ def _AlignAssignment(final_lines): whitespace = ' ' * ( max_variables_length - pa_variables_lengths[0] - 1) - assign_content = '{}{}'.format( - whitespace, line_tok.value.strip()) + assign_content = '{}{}'.format(whitespace, + line_tok.value.strip()) existing_whitespace_prefix = \ line_tok.formatted_whitespace_prefix.lstrip('\n') @@ -548,8 +547,8 @@ def _AlignAssignment(final_lines): len(existing_whitespace_prefix) > len(whitespace)): line_tok.whitespace_prefix = '' elif assign_content.startswith(existing_whitespace_prefix): - assign_content = assign_content[ - len(existing_whitespace_prefix):] + assign_content = assign_content[len(existing_whitespace_prefix + ):] # update the assignment operator value line_tok.value = assign_content @@ -601,8 +600,8 @@ class _StateNode(object): # TODO(morbo): Add a '__cmp__' method. def __init__(self, state, newline, previous): - self.state = state.Clone() - self.newline = newline + self.state = state.Clone() + self.newline = newline self.previous = previous def __repr__(self): # pragma: no cover @@ -618,8 +617,8 @@ def __repr__(self): # pragma: no cover # An item in the prioritized BFS search queue. The 'StateNode's 'state' has # the given '_OrderedPenalty'. -_QueueItem = collections.namedtuple( - 'QueueItem', ['ordered_penalty', 'state_node']) +_QueueItem = collections.namedtuple('QueueItem', + ['ordered_penalty', 'state_node']) def _AnalyzeSolutionSpace(initial_state): @@ -637,8 +636,8 @@ def _AnalyzeSolutionSpace(initial_state): Returns: True if a formatting solution was found. False otherwise. """ - count = 0 - seen = set() + count = 0 + seen = set() p_queue = [] # Insert start element. @@ -647,9 +646,9 @@ def _AnalyzeSolutionSpace(initial_state): count += 1 while p_queue: - item = p_queue[0] + item = p_queue[0] penalty = item.ordered_penalty.penalty - node = item.state_node + node = item.state_node if not node.state.next_token: break heapq.heappop(p_queue) @@ -703,7 +702,7 @@ def _AddNextStateToQueue(penalty, previous_node, newline, count, p_queue): # Don't add a token we must split but where we aren't splitting. return count - node = _StateNode(previous_node.state, newline, previous_node) + node = _StateNode(previous_node.state, newline, previous_node) penalty += node.state.AddTokenToState( newline=newline, dry_run=True, must_split=must_split) heapq.heappush(p_queue, _QueueItem(_OrderedPenalty(penalty, count), node)) @@ -759,25 +758,25 @@ def _FormatFirstToken(first_token, indent_depth, prev_line, final_lines): NESTED_DEPTH.append(indent_depth) first_token.AddWhitespacePrefix( - _CalculateNumberOfNewlines( - first_token, indent_depth, prev_line, final_lines, first_nested), + _CalculateNumberOfNewlines(first_token, indent_depth, prev_line, + final_lines, first_nested), indent_level=indent_depth) -NO_BLANK_LINES = 1 -ONE_BLANK_LINE = 2 +NO_BLANK_LINES = 1 +ONE_BLANK_LINE = 2 TWO_BLANK_LINES = 3 def _IsClassOrDef(tok): if tok.value in {'class', 'def', '@'}: return True - return ( - tok.next_token and tok.value == 'async' and tok.next_token.value == 'def') + return (tok.next_token and tok.value == 'async' and + tok.next_token.value == 'def') -def _CalculateNumberOfNewlines( - first_token, indent_depth, prev_line, final_lines, first_nested): +def _CalculateNumberOfNewlines(first_token, indent_depth, prev_line, + final_lines, first_nested): """Calculate the number of newlines we need to add. Arguments: @@ -897,11 +896,11 @@ def _SingleOrMergedLines(lines): Either a single line, if the current line cannot be merged with the succeeding line, or the next two lines merged into one line. """ - index = 0 + index = 0 last_was_merged = False while index < len(lines): if lines[index].disable: - line = lines[index] + line = lines[index] index += 1 while index < len(lines): column = line.last.column + 2 @@ -927,11 +926,11 @@ def _SingleOrMergedLines(lines): # formatting. Otherwise, it could mess up the shell script's syntax. lines[index].disable = True yield lines[index] - index += 2 + index += 2 last_was_merged = True else: yield lines[index] - index += 1 + index += 1 last_was_merged = False diff --git a/yapf/yapflib/split_penalty.py b/yapf/yapflib/split_penalty.py index 8f93d3ade..79b68edcd 100644 --- a/yapf/yapflib/split_penalty.py +++ b/yapf/yapflib/split_penalty.py @@ -15,9 +15,9 @@ from yapf.yapflib import style # Generic split penalties -UNBREAKABLE = 1000**5 +UNBREAKABLE = 1000**5 VERY_STRONGLY_CONNECTED = 5000 -STRONGLY_CONNECTED = 2500 +STRONGLY_CONNECTED = 2500 ############################################################################# # Grammar-specific penalties - should be <= 1000 # @@ -25,15 +25,15 @@ # Lambdas shouldn't be split unless absolutely necessary or if # ALLOW_MULTILINE_LAMBDAS is True. -LAMBDA = 1000 +LAMBDA = 1000 MULTILINE_LAMBDA = 500 ANNOTATION = 100 -ARGUMENT = 25 +ARGUMENT = 25 # TODO: Assign real values. -RETURN_TYPE = 1 -DOTTED_NAME = 40 -EXPR = 10 -DICT_KEY_EXPR = 20 +RETURN_TYPE = 1 +DOTTED_NAME = 40 +EXPR = 10 +DICT_KEY_EXPR = 20 DICT_VALUE_EXPR = 11 diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 820952492..f2912f1ee 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -52,23 +52,18 @@ def SetGlobalStyle(style): _STYLE_HELP = dict( - ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=textwrap.dedent( - """\ + ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=textwrap.dedent("""\ Align closing bracket with visual indentation."""), - ALIGN_ASSIGNMENT=textwrap.dedent( - """\ + ALIGN_ASSIGNMENT=textwrap.dedent("""\ Align assignment or augmented assignment operators. If there is a blank line or newline comment or objects with newline entries in between, it will start new block alignment."""), - NEW_ALIGNMENT_AFTER_COMMENTLINE=textwrap.dedent( - """\ + NEW_ALIGNMENT_AFTER_COMMENTLINE=textwrap.dedent("""\ Start new assignment or colon alignment when there is a newline comment in between.""" - ), - ALLOW_MULTILINE_LAMBDAS=textwrap.dedent( - """\ + ), + ALLOW_MULTILINE_LAMBDAS=textwrap.dedent("""\ Allow lambdas to be formatted on more than one line."""), - ALLOW_MULTILINE_DICTIONARY_KEYS=textwrap.dedent( - """\ + ALLOW_MULTILINE_DICTIONARY_KEYS=textwrap.dedent("""\ Allow dictionary keys to exist on multiple lines. For example: x = { @@ -76,15 +71,12 @@ def SetGlobalStyle(style): 'this is the second element of a tuple'): value, }"""), - ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=textwrap.dedent( - """\ + ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=textwrap.dedent("""\ Allow splitting before a default / named assignment in an argument list. """), - ALLOW_SPLIT_BEFORE_DICT_VALUE=textwrap.dedent( - """\ + ALLOW_SPLIT_BEFORE_DICT_VALUE=textwrap.dedent("""\ Allow splits before the dictionary value."""), - ARITHMETIC_PRECEDENCE_INDICATION=textwrap.dedent( - """\ + ARITHMETIC_PRECEDENCE_INDICATION=textwrap.dedent("""\ Let spacing indicate operator precedence. For example: a = 1 * 2 + 3 / 4 @@ -104,8 +96,7 @@ def SetGlobalStyle(style): f = 1 + 2 + 3 + 4 """), - BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=textwrap.dedent( - """\ + BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=textwrap.dedent("""\ Insert a blank line before a 'def' or 'class' immediately nested within another 'def' or 'class'. For example: @@ -113,22 +104,17 @@ class Foo: # <------ this blank line def method(): ..."""), - BLANK_LINE_BEFORE_CLASS_DOCSTRING=textwrap.dedent( - """\ + BLANK_LINE_BEFORE_CLASS_DOCSTRING=textwrap.dedent("""\ Insert a blank line before a class-level docstring."""), - BLANK_LINE_BEFORE_MODULE_DOCSTRING=textwrap.dedent( - """\ + BLANK_LINE_BEFORE_MODULE_DOCSTRING=textwrap.dedent("""\ Insert a blank line before a module docstring."""), - BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=textwrap.dedent( - """\ + BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=textwrap.dedent("""\ Number of blank lines surrounding top-level function and class definitions."""), - BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES=textwrap.dedent( - """\ + BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES=textwrap.dedent("""\ Number of blank lines between top-level imports and variable definitions."""), - COALESCE_BRACKETS=textwrap.dedent( - """\ + COALESCE_BRACKETS=textwrap.dedent("""\ Do not split consecutive brackets. Only relevant when dedent_closing_brackets is set. For example: @@ -147,8 +133,7 @@ def method(): })"""), COLUMN_LIMIT=textwrap.dedent("""\ The column limit."""), - CONTINUATION_ALIGN_STYLE=textwrap.dedent( - """\ + CONTINUATION_ALIGN_STYLE=textwrap.dedent("""\ The style for continuation alignment. Possible values are: - SPACE: Use spaces for continuation alignment. This is default behavior. @@ -158,11 +143,9 @@ def method(): - VALIGN-RIGHT: Vertically align continuation lines to multiple of INDENT_WIDTH columns. Slightly right (one tab or a few spaces) if cannot vertically align continuation lines with indent characters."""), - CONTINUATION_INDENT_WIDTH=textwrap.dedent( - """\ + CONTINUATION_INDENT_WIDTH=textwrap.dedent("""\ Indent width used for line continuations."""), - DEDENT_CLOSING_BRACKETS=textwrap.dedent( - """\ + DEDENT_CLOSING_BRACKETS=textwrap.dedent("""\ Put closing brackets on a separate line, dedented, if the bracketed expression can't fit in a single line. Applies to all kinds of brackets, including function definitions and calls. For example: @@ -180,33 +163,27 @@ def method(): end_ts=now(), ) # <--- this bracket is dedented and on a separate line """), - DISABLE_ENDING_COMMA_HEURISTIC=textwrap.dedent( - """\ + DISABLE_ENDING_COMMA_HEURISTIC=textwrap.dedent("""\ Disable the heuristic which places each list element on a separate line if the list is comma-terminated."""), - EACH_DICT_ENTRY_ON_SEPARATE_LINE=textwrap.dedent( - """\ + EACH_DICT_ENTRY_ON_SEPARATE_LINE=textwrap.dedent("""\ Place each dictionary entry onto its own line."""), - FORCE_MULTILINE_DICT=textwrap.dedent( - """\ + FORCE_MULTILINE_DICT=textwrap.dedent("""\ Require multiline dictionary even if it would normally fit on one line. For example: config = { 'key1': 'value1' }"""), - I18N_COMMENT=textwrap.dedent( - """\ + I18N_COMMENT=textwrap.dedent("""\ The regex for an i18n comment. The presence of this comment stops reformatting of that line, because the comments are required to be next to the string they translate."""), - I18N_FUNCTION_CALL=textwrap.dedent( - """\ + I18N_FUNCTION_CALL=textwrap.dedent("""\ The i18n function call names. The presence of this function stops reformattting on that line, because the string it has cannot be moved away from the i18n comment."""), - INDENT_CLOSING_BRACKETS=textwrap.dedent( - """\ + INDENT_CLOSING_BRACKETS=textwrap.dedent("""\ Put closing brackets on a separate line, indented, if the bracketed expression can't fit in a single line. Applies to all kinds of brackets, including function definitions and calls. For example: @@ -224,8 +201,7 @@ def method(): end_ts=now(), ) # <--- this bracket is indented and on a separate line """), - INDENT_DICTIONARY_VALUE=textwrap.dedent( - """\ + INDENT_DICTIONARY_VALUE=textwrap.dedent("""\ Indent the dictionary value if it cannot fit on the same line as the dictionary key. For example: @@ -236,16 +212,13 @@ def method(): value2, } """), - INDENT_WIDTH=textwrap.dedent( - """\ + INDENT_WIDTH=textwrap.dedent("""\ The number of columns to use for indentation."""), INDENT_BLANK_LINES=textwrap.dedent("""\ Indent blank lines."""), - JOIN_MULTIPLE_LINES=textwrap.dedent( - """\ + JOIN_MULTIPLE_LINES=textwrap.dedent("""\ Join short lines into one line. E.g., single line 'if' statements."""), - NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=textwrap.dedent( - """\ + NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=textwrap.dedent("""\ Do not include spaces around selected binary operators. For example: 1 + 2 * 3 - 4 / 5 @@ -254,26 +227,21 @@ def method(): 1 + 2*3 - 4/5 """), - SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=textwrap.dedent( - """\ + SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=textwrap.dedent("""\ Insert a space between the ending comma and closing bracket of a list, etc."""), - SPACE_INSIDE_BRACKETS=textwrap.dedent( - """\ + SPACE_INSIDE_BRACKETS=textwrap.dedent("""\ Use spaces inside brackets, braces, and parentheses. For example: method_call( 1 ) my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] my_set = { 1, 2, 3 } """), - SPACES_AROUND_POWER_OPERATOR=textwrap.dedent( - """\ + SPACES_AROUND_POWER_OPERATOR=textwrap.dedent("""\ Use spaces around the power operator."""), - SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=textwrap.dedent( - """\ + SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=textwrap.dedent("""\ Use spaces around default or named assigns."""), - SPACES_AROUND_DICT_DELIMITERS=textwrap.dedent( - """\ + SPACES_AROUND_DICT_DELIMITERS=textwrap.dedent("""\ Adds a space after the opening '{' and before the ending '}' dict delimiters. @@ -283,8 +251,7 @@ def method(): { 1: 2 } """), - SPACES_AROUND_LIST_DELIMITERS=textwrap.dedent( - """\ + SPACES_AROUND_LIST_DELIMITERS=textwrap.dedent("""\ Adds a space after the opening '[' and before the ending ']' list delimiters. @@ -294,14 +261,12 @@ def method(): [ 1, 2 ] """), - SPACES_AROUND_SUBSCRIPT_COLON=textwrap.dedent( - """\ + SPACES_AROUND_SUBSCRIPT_COLON=textwrap.dedent("""\ Use spaces around the subscript / slice operator. For example: my_list[1 : 10 : 2] """), - SPACES_AROUND_TUPLE_DELIMITERS=textwrap.dedent( - """\ + SPACES_AROUND_TUPLE_DELIMITERS=textwrap.dedent("""\ Adds a space after the opening '(' and before the ending ')' tuple delimiters. @@ -311,8 +276,7 @@ def method(): ( 1, 2, 3 ) """), - SPACES_BEFORE_COMMENT=textwrap.dedent( - """\ + SPACES_BEFORE_COMMENT=textwrap.dedent("""\ The number of spaces required before a trailing comment. This can be a single value (representing the number of spaces before each trailing comment) or list of values (representing @@ -354,31 +318,24 @@ def method(): short # This is a shorter statement """), # noqa - SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=textwrap.dedent( - """\ + SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=textwrap.dedent("""\ Split before arguments if the argument list is terminated by a comma."""), - SPLIT_ALL_COMMA_SEPARATED_VALUES=textwrap.dedent( - """\ + SPLIT_ALL_COMMA_SEPARATED_VALUES=textwrap.dedent("""\ Split before arguments"""), - SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=textwrap.dedent( - """\ + SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=textwrap.dedent("""\ Split before arguments, but do not split all subexpressions recursively (unless needed)."""), - SPLIT_BEFORE_ARITHMETIC_OPERATOR=textwrap.dedent( - """\ + SPLIT_BEFORE_ARITHMETIC_OPERATOR=textwrap.dedent("""\ Set to True to prefer splitting before '+', '-', '*', '/', '//', or '@' rather than after."""), - SPLIT_BEFORE_BITWISE_OPERATOR=textwrap.dedent( - """\ + SPLIT_BEFORE_BITWISE_OPERATOR=textwrap.dedent("""\ Set to True to prefer splitting before '&', '|' or '^' rather than after."""), - SPLIT_BEFORE_CLOSING_BRACKET=textwrap.dedent( - """\ + SPLIT_BEFORE_CLOSING_BRACKET=textwrap.dedent("""\ Split before the closing bracket if a list or dict literal doesn't fit on a single line."""), - SPLIT_BEFORE_DICT_SET_GENERATOR=textwrap.dedent( - """\ + SPLIT_BEFORE_DICT_SET_GENERATOR=textwrap.dedent("""\ Split before a dictionary or set generator (comp_for). For example, note the split before the 'for': @@ -386,8 +343,7 @@ def method(): variable: 'Hello world, have a nice day!' for variable in bar if variable != 42 }"""), - SPLIT_BEFORE_DOT=textwrap.dedent( - """\ + SPLIT_BEFORE_DOT=textwrap.dedent("""\ Split before the '.' if we need to split a longer expression: foo = ('This is a really long string: {}, {}, {}, {}'.format(a, b, c, d)) @@ -397,24 +353,19 @@ def method(): foo = ('This is a really long string: {}, {}, {}, {}' .format(a, b, c, d)) """), # noqa - SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=textwrap.dedent( - """\ + SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=textwrap.dedent("""\ Split after the opening paren which surrounds an expression if it doesn't fit on a single line. """), - SPLIT_BEFORE_FIRST_ARGUMENT=textwrap.dedent( - """\ + SPLIT_BEFORE_FIRST_ARGUMENT=textwrap.dedent("""\ If an argument / parameter list is going to be split, then split before the first argument."""), - SPLIT_BEFORE_LOGICAL_OPERATOR=textwrap.dedent( - """\ + SPLIT_BEFORE_LOGICAL_OPERATOR=textwrap.dedent("""\ Set to True to prefer splitting before 'and' or 'or' rather than after."""), - SPLIT_BEFORE_NAMED_ASSIGNS=textwrap.dedent( - """\ + SPLIT_BEFORE_NAMED_ASSIGNS=textwrap.dedent("""\ Split named assignments onto individual lines."""), - SPLIT_COMPLEX_COMPREHENSION=textwrap.dedent( - """\ + SPLIT_COMPLEX_COMPREHENSION=textwrap.dedent("""\ Set to True to split list comprehensions and generators that have non-trivial expressions and multiple clauses before each of these clauses. For example: @@ -430,36 +381,27 @@ def method(): for a_long_var in xrange(1000) if a_long_var % 10] """), - SPLIT_PENALTY_AFTER_OPENING_BRACKET=textwrap.dedent( - """\ + SPLIT_PENALTY_AFTER_OPENING_BRACKET=textwrap.dedent("""\ The penalty for splitting right after the opening bracket."""), - SPLIT_PENALTY_AFTER_UNARY_OPERATOR=textwrap.dedent( - """\ + SPLIT_PENALTY_AFTER_UNARY_OPERATOR=textwrap.dedent("""\ The penalty for splitting the line after a unary operator."""), - SPLIT_PENALTY_ARITHMETIC_OPERATOR=textwrap.dedent( - """\ + SPLIT_PENALTY_ARITHMETIC_OPERATOR=textwrap.dedent("""\ The penalty of splitting the line around the '+', '-', '*', '/', '//', ``%``, and '@' operators."""), - SPLIT_PENALTY_BEFORE_IF_EXPR=textwrap.dedent( - """\ + SPLIT_PENALTY_BEFORE_IF_EXPR=textwrap.dedent("""\ The penalty for splitting right before an if expression."""), - SPLIT_PENALTY_BITWISE_OPERATOR=textwrap.dedent( - """\ + SPLIT_PENALTY_BITWISE_OPERATOR=textwrap.dedent("""\ The penalty of splitting the line around the '&', '|', and '^' operators."""), - SPLIT_PENALTY_COMPREHENSION=textwrap.dedent( - """\ + SPLIT_PENALTY_COMPREHENSION=textwrap.dedent("""\ The penalty for splitting a list comprehension or generator expression."""), - SPLIT_PENALTY_EXCESS_CHARACTER=textwrap.dedent( - """\ + SPLIT_PENALTY_EXCESS_CHARACTER=textwrap.dedent("""\ The penalty for characters over the column limit."""), - SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=textwrap.dedent( - """\ + SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=textwrap.dedent("""\ The penalty incurred by adding a line split to the logical line. The more line splits added the higher the penalty."""), - SPLIT_PENALTY_IMPORT_NAMES=textwrap.dedent( - """\ + SPLIT_PENALTY_IMPORT_NAMES=textwrap.dedent("""\ The penalty of splitting a list of "import as" names. For example: from a_very_long_or_indented_module_name_yada_yad import (long_argument_1, @@ -471,12 +413,10 @@ def method(): from a_very_long_or_indented_module_name_yada_yad import ( long_argument_1, long_argument_2, long_argument_3) """), # noqa - SPLIT_PENALTY_LOGICAL_OPERATOR=textwrap.dedent( - """\ + SPLIT_PENALTY_LOGICAL_OPERATOR=textwrap.dedent("""\ The penalty of splitting the line around the 'and' and 'or' operators."""), - USE_TABS=textwrap.dedent( - """\ + USE_TABS=textwrap.dedent("""\ Use the Tab character for indentation."""), # BASED_ON_STYLE='Which predefined style this style is based on', ) @@ -552,51 +492,51 @@ def CreatePEP8Style(): def CreateGoogleStyle(): """Create the Google formatting style.""" - style = CreatePEP8Style() - style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False - style['COLUMN_LIMIT'] = 80 - style['INDENT_DICTIONARY_VALUE'] = True - style['INDENT_WIDTH'] = 4 - style['I18N_COMMENT'] = r'#\..*' - style['I18N_FUNCTION_CALL'] = ['N_', '_'] - style['JOIN_MULTIPLE_LINES'] = False + style = CreatePEP8Style() + style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False + style['COLUMN_LIMIT'] = 80 + style['INDENT_DICTIONARY_VALUE'] = True + style['INDENT_WIDTH'] = 4 + style['I18N_COMMENT'] = r'#\..*' + style['I18N_FUNCTION_CALL'] = ['N_', '_'] + style['JOIN_MULTIPLE_LINES'] = False style['SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET'] = False - style['SPLIT_BEFORE_BITWISE_OPERATOR'] = False - style['SPLIT_BEFORE_DICT_SET_GENERATOR'] = False - style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False - style['SPLIT_COMPLEX_COMPREHENSION'] = True - style['SPLIT_PENALTY_COMPREHENSION'] = 2100 + style['SPLIT_BEFORE_BITWISE_OPERATOR'] = False + style['SPLIT_BEFORE_DICT_SET_GENERATOR'] = False + style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False + style['SPLIT_COMPLEX_COMPREHENSION'] = True + style['SPLIT_PENALTY_COMPREHENSION'] = 2100 return style def CreateYapfStyle(): """Create the YAPF formatting style.""" - style = CreateGoogleStyle() - style['ALLOW_MULTILINE_DICTIONARY_KEYS'] = True + style = CreateGoogleStyle() + style['ALLOW_MULTILINE_DICTIONARY_KEYS'] = True style['ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS'] = False - style['INDENT_WIDTH'] = 2 - style['SPLIT_BEFORE_BITWISE_OPERATOR'] = True - style['SPLIT_BEFORE_DOT'] = True + style['INDENT_WIDTH'] = 2 + style['SPLIT_BEFORE_BITWISE_OPERATOR'] = True + style['SPLIT_BEFORE_DOT'] = True style['SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN'] = True return style def CreateFacebookStyle(): """Create the Facebook formatting style.""" - style = CreatePEP8Style() + style = CreatePEP8Style() style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False - style['BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'] = False - style['COLUMN_LIMIT'] = 80 - style['DEDENT_CLOSING_BRACKETS'] = True - style['INDENT_CLOSING_BRACKETS'] = False - style['INDENT_DICTIONARY_VALUE'] = True - style['JOIN_MULTIPLE_LINES'] = False - style['SPACES_BEFORE_COMMENT'] = 2 - style['SPLIT_PENALTY_AFTER_OPENING_BRACKET'] = 0 - style['SPLIT_PENALTY_BEFORE_IF_EXPR'] = 30 - style['SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT'] = 30 - style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False - style['SPLIT_BEFORE_BITWISE_OPERATOR'] = False + style['BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'] = False + style['COLUMN_LIMIT'] = 80 + style['DEDENT_CLOSING_BRACKETS'] = True + style['INDENT_CLOSING_BRACKETS'] = False + style['INDENT_DICTIONARY_VALUE'] = True + style['JOIN_MULTIPLE_LINES'] = False + style['SPACES_BEFORE_COMMENT'] = 2 + style['SPLIT_PENALTY_AFTER_OPENING_BRACKET'] = 0 + style['SPLIT_PENALTY_BEFORE_IF_EXPR'] = 30 + style['SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT'] = 30 + style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False + style['SPLIT_BEFORE_BITWISE_OPERATOR'] = False return style @@ -828,7 +768,7 @@ def _CreateConfigParserFromConfigFile(config_filename): "configuration file") pyproject_toml = toml.load(style_file) - style_dict = pyproject_toml.get("tool", {}).get("yapf", None) + style_dict = pyproject_toml.get("tool", {}).get("yapf", None) if style_dict is None: raise StyleConfigError( 'Unable to find section [tool.yapf] in {0}'.format(config_filename)) @@ -871,10 +811,10 @@ def _CreateStyleFromConfigParser(config): # Initialize the base style. section = 'yapf' if config.has_section('yapf') else 'style' if config.has_option('style', 'based_on_style'): - based_on = config.get('style', 'based_on_style').lower() + based_on = config.get('style', 'based_on_style').lower() base_style = _STYLE_NAME_TO_FACTORY[based_on]() elif config.has_option('yapf', 'based_on_style'): - based_on = config.get('yapf', 'based_on_style').lower() + based_on = config.get('yapf', 'based_on_style').lower() base_style = _STYLE_NAME_TO_FACTORY[based_on]() else: base_style = _GLOBAL_STYLE_FACTORY() @@ -891,14 +831,14 @@ def _CreateStyleFromConfigParser(config): try: base_style[option] = _STYLE_OPTION_VALUE_CONVERTER[option](value) except ValueError: - raise StyleConfigError( - "'{}' is not a valid setting for {}.".format(value, option)) + raise StyleConfigError("'{}' is not a valid setting for {}.".format( + value, option)) return base_style # The default style - used if yapf is not invoked without specifically # requesting a formatting style. -DEFAULT_STYLE = 'pep8' +DEFAULT_STYLE = 'pep8' DEFAULT_STYLE_FACTORY = CreatePEP8Style _GLOBAL_STYLE_FACTORY = CreatePEP8Style diff --git a/yapf/yapflib/subtypes.py b/yapf/yapflib/subtypes.py index e675c41c1..b4b7efe75 100644 --- a/yapf/yapflib/subtypes.py +++ b/yapf/yapflib/subtypes.py @@ -13,28 +13,28 @@ # limitations under the License. """Token subtypes used to improve formatting.""" -NONE = 0 -UNARY_OPERATOR = 1 -BINARY_OPERATOR = 2 -SUBSCRIPT_COLON = 3 -SUBSCRIPT_BRACKET = 4 -DEFAULT_OR_NAMED_ASSIGN = 5 +NONE = 0 +UNARY_OPERATOR = 1 +BINARY_OPERATOR = 2 +SUBSCRIPT_COLON = 3 +SUBSCRIPT_BRACKET = 4 +DEFAULT_OR_NAMED_ASSIGN = 5 DEFAULT_OR_NAMED_ASSIGN_ARG_LIST = 6 -VARARGS_LIST = 7 -VARARGS_STAR = 8 -KWARGS_STAR_STAR = 9 -ASSIGN_OPERATOR = 10 -DICTIONARY_KEY = 11 -DICTIONARY_KEY_PART = 12 -DICTIONARY_VALUE = 13 -DICT_SET_GENERATOR = 14 -COMP_EXPR = 15 -COMP_FOR = 16 -COMP_IF = 17 -FUNC_DEF = 18 -DECORATOR = 19 -TYPED_NAME = 20 -TYPED_NAME_ARG_LIST = 21 -SIMPLE_EXPRESSION = 22 -PARAMETER_START = 23 -PARAMETER_STOP = 24 +VARARGS_LIST = 7 +VARARGS_STAR = 8 +KWARGS_STAR_STAR = 9 +ASSIGN_OPERATOR = 10 +DICTIONARY_KEY = 11 +DICTIONARY_KEY_PART = 12 +DICTIONARY_VALUE = 13 +DICT_SET_GENERATOR = 14 +COMP_EXPR = 15 +COMP_FOR = 16 +COMP_IF = 17 +FUNC_DEF = 18 +DECORATOR = 19 +TYPED_NAME = 20 +TYPED_NAME_ARG_LIST = 21 +SIMPLE_EXPRESSION = 22 +PARAMETER_START = 23 +PARAMETER_STOP = 24 diff --git a/yapf/yapflib/verifier.py b/yapf/yapflib/verifier.py index 01dccc0b0..bcbe6fb6b 100644 --- a/yapf/yapflib/verifier.py +++ b/yapf/yapflib/verifier.py @@ -59,7 +59,7 @@ def _NormalizeCode(code): # Split the code to lines and get rid of all leading full-comment lines as # they can mess up the normalization attempt. lines = code.split('\n') - i = 0 + i = 0 for i, line in enumerate(lines): line = line.strip() if line and not line.startswith('#'): diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index e0098ddd2..c17451434 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -51,14 +51,13 @@ from yapf.yapflib import style -def FormatFile( - filename, - style_config=None, - lines=None, - print_diff=False, - verify=False, - in_place=False, - logger=None): +def FormatFile(filename, + style_config=None, + lines=None, + print_diff=False, + verify=False, + in_place=False, + logger=None): """Format a single Python file and return the formatted code. Arguments: @@ -91,7 +90,7 @@ def FormatFile( raise ValueError('Cannot pass both in_place and print_diff.') original_source, newline, encoding = ReadFile(filename, logger) - reformatted_source, changed = FormatCode( + reformatted_source, changed = FormatCode( original_source, style_config=style_config, filename=filename, @@ -99,12 +98,12 @@ def FormatFile( print_diff=print_diff, verify=verify) if reformatted_source.rstrip('\n'): - lines = reformatted_source.rstrip('\n').split('\n') + lines = reformatted_source.rstrip('\n').split('\n') reformatted_source = newline.join(iter(lines)) + newline if in_place: if original_source and original_source != reformatted_source: - file_resources.WriteReformattedCode( - filename, reformatted_source, encoding, in_place) + file_resources.WriteReformattedCode(filename, reformatted_source, + encoding, in_place) return None, encoding, changed return reformatted_source, encoding, changed @@ -149,13 +148,12 @@ def FormatTree(tree, style_config=None, lines=None, verify=False): return reformatter.Reformat(_SplitSemicolons(llines), verify, lines) -def FormatCode( - unformatted_source, - filename='', - style_config=None, - lines=None, - print_diff=False, - verify=False): +def FormatCode(unformatted_source, + filename='', + style_config=None, + lines=None, + print_diff=False, + verify=False): """Format a string of Python code. This provides an alternative entry point to YAPF. @@ -230,12 +228,12 @@ def ReadFile(filename, logger=None): encoding = file_resources.FileEncoding(filename) # Preserves line endings. - with py3compat.open_with_encoding(filename, mode='r', encoding=encoding, - newline='') as fd: + with py3compat.open_with_encoding( + filename, mode='r', encoding=encoding, newline='') as fd: lines = fd.readlines() line_ending = file_resources.LineEnding(lines) - source = '\n'.join(line.rstrip('\r\n') for line in lines) + '\n' + source = '\n'.join(line.rstrip('\r\n') for line in lines) + '\n' return source, line_ending, encoding except IOError as e: # pragma: no cover if logger: @@ -244,9 +242,8 @@ def ReadFile(filename, logger=None): raise except UnicodeDecodeError as e: # pragma: no cover if logger: - logger( - 'Could not parse %s! Consider excluding this file with --exclude.', - filename) + logger('Could not parse %s! Consider excluding this file with --exclude.', + filename) logger(e) e.args = (e.args[0], (filename, e.args[1][1], e.args[1][2], e.args[1][3])) raise @@ -260,7 +257,7 @@ def _SplitSemicolons(lines): DISABLE_PATTERN = r'^#.*\byapf:\s*disable\b' -ENABLE_PATTERN = r'^#.*\byapf:\s*enable\b' +ENABLE_PATTERN = r'^#.*\byapf:\s*enable\b' def _LineRangesToSet(line_ranges): @@ -293,31 +290,29 @@ def _MarkLinesToFormat(llines, lines): index += 1 while index < len(llines): uwline = llines[index] - line = uwline.first.value.strip() + line = uwline.first.value.strip() if uwline.is_comment and _EnableYAPF(line): if not _DisableYAPF(line): break uwline.disable = True - index += 1 + index += 1 elif re.search(DISABLE_PATTERN, uwline.last.value.strip(), re.IGNORECASE): uwline.disable = True index += 1 def _DisableYAPF(line): - return ( - re.search(DISABLE_PATTERN, - line.split('\n')[0].strip(), re.IGNORECASE) or - re.search(DISABLE_PATTERN, - line.split('\n')[-1].strip(), re.IGNORECASE)) + return (re.search(DISABLE_PATTERN, + line.split('\n')[0].strip(), re.IGNORECASE) or + re.search(DISABLE_PATTERN, + line.split('\n')[-1].strip(), re.IGNORECASE)) def _EnableYAPF(line): - return ( - re.search(ENABLE_PATTERN, - line.split('\n')[0].strip(), re.IGNORECASE) or - re.search(ENABLE_PATTERN, - line.split('\n')[-1].strip(), re.IGNORECASE)) + return (re.search(ENABLE_PATTERN, + line.split('\n')[0].strip(), re.IGNORECASE) or + re.search(ENABLE_PATTERN, + line.split('\n')[-1].strip(), re.IGNORECASE)) def _GetUnifiedDiff(before, after, filename='code'): @@ -332,7 +327,7 @@ def _GetUnifiedDiff(before, after, filename='code'): The unified diff text. """ before = before.splitlines() - after = after.splitlines() + after = after.splitlines() return '\n'.join( difflib.unified_diff( before, diff --git a/yapftests/blank_line_calculator_test.py b/yapftests/blank_line_calculator_test.py index d5d97d794..18fa83e0b 100644 --- a/yapftests/blank_line_calculator_test.py +++ b/yapftests/blank_line_calculator_test.py @@ -30,15 +30,13 @@ def setUpClass(cls): style.SetGlobalStyle(style.CreateYapfStyle()) def testDecorators(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ @bork() def foo(): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ @bork() def foo(): pass @@ -47,8 +45,7 @@ def foo(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testComplexDecorators(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ import sys @bork() @@ -63,8 +60,7 @@ class moo(object): def method(self): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ import sys @@ -85,8 +81,7 @@ def method(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testCodeAfterFunctionsAndClasses(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo(): pass top_level_code = True @@ -102,8 +97,7 @@ def method_2(self): except Error as error: pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo(): pass @@ -132,8 +126,7 @@ def method_2(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testCommentSpacing(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ # This is the first comment # And it's multiline @@ -162,8 +155,7 @@ def foo(self): # comment pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ # This is the first comment # And it's multiline @@ -200,8 +192,7 @@ def foo(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testCommentBeforeMethod(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class foo(object): # pylint: disable=invalid-name @@ -212,8 +203,7 @@ def f(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentsBeforeClassDefs(self): - code = textwrap.dedent( - '''\ + code = textwrap.dedent('''\ """Test.""" # Comment @@ -226,8 +216,7 @@ class Foo(object): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentsBeforeDecorator(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ # The @foo operator adds bork to a(). @foo() def a(): @@ -236,8 +225,7 @@ def a(): llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ # Hello world @@ -249,8 +237,7 @@ def a(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentsAfterDecorator(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class _(): def _(): @@ -267,8 +254,7 @@ def test_unicode_filename_in_sdist(self, sdist_unicode, tmpdir, monkeypatch): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testInnerClasses(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class DeployAPIClient(object): class Error(Exception): pass @@ -276,8 +262,7 @@ class TaskValidationError(Error): pass class DeployAPIHTTPError(Error): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class DeployAPIClient(object): class Error(Exception): @@ -293,8 +278,7 @@ class DeployAPIHTTPError(Error): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testLinesOnRangeBoundary(self): - unformatted_code = textwrap.dedent( - u"""\ + unformatted_code = textwrap.dedent(u"""\ def A(): pass @@ -308,8 +292,7 @@ def D(): # 9 def E(): pass """) - expected_formatted_code = textwrap.dedent( - u"""\ + expected_formatted_code = textwrap.dedent(u"""\ def A(): pass @@ -332,8 +315,7 @@ def E(): self.assertTrue(changed) def testLinesRangeBoundaryNotOutside(self): - unformatted_code = textwrap.dedent( - u"""\ + unformatted_code = textwrap.dedent(u"""\ def A(): pass @@ -347,8 +329,7 @@ def B(): # 6 def C(): pass """) - expected_formatted_code = textwrap.dedent( - u"""\ + expected_formatted_code = textwrap.dedent(u"""\ def A(): pass @@ -367,8 +348,7 @@ def C(): self.assertFalse(changed) def testLinesRangeRemove(self): - unformatted_code = textwrap.dedent( - u"""\ + unformatted_code = textwrap.dedent(u"""\ def A(): pass @@ -383,8 +363,7 @@ def B(): # 6 def C(): pass """) - expected_formatted_code = textwrap.dedent( - u"""\ + expected_formatted_code = textwrap.dedent(u"""\ def A(): pass @@ -403,8 +382,7 @@ def C(): self.assertTrue(changed) def testLinesRangeRemoveSome(self): - unformatted_code = textwrap.dedent( - u"""\ + unformatted_code = textwrap.dedent(u"""\ def A(): pass @@ -420,8 +398,7 @@ def B(): # 7 def C(): pass """) - expected_formatted_code = textwrap.dedent( - u"""\ + expected_formatted_code = textwrap.dedent(u"""\ def A(): pass diff --git a/yapftests/comment_splicer_test.py b/yapftests/comment_splicer_test.py index 985ea88b7..2e0141bd4 100644 --- a/yapftests/comment_splicer_test.py +++ b/yapftests/comment_splicer_test.py @@ -38,8 +38,9 @@ def _AssertNodeIsComment(self, node, text_in_comment=None): self.assertIn(text_in_comment, node_value) def _FindNthChildNamed(self, node, name, n=1): - for i, child in enumerate(py3compat.ifilter( - lambda c: pytree_utils.NodeName(c) == name, node.pre_order())): + for i, child in enumerate( + py3compat.ifilter(lambda c: pytree_utils.NodeName(c) == name, + node.pre_order())): if i == n - 1: return child raise RuntimeError('No Nth child for n={0}'.format(n)) @@ -58,8 +59,7 @@ def testSimpleInline(self): self._AssertNodeIsComment(comment_node, '# and a comment') def testSimpleSeparateLine(self): - code = textwrap.dedent( - r''' + code = textwrap.dedent(r''' foo = 1 # first comment bar = 2 @@ -74,8 +74,7 @@ def testSimpleSeparateLine(self): self._AssertNodeIsComment(comment_node) def testTwoLineComment(self): - code = textwrap.dedent( - r''' + code = textwrap.dedent(r''' foo = 1 # first comment # second comment @@ -89,8 +88,7 @@ def testTwoLineComment(self): self._AssertNodeIsComment(tree.children[1]) def testCommentIsFirstChildInCompound(self): - code = textwrap.dedent( - r''' + code = textwrap.dedent(r''' if x: # a comment foo = 1 @@ -106,8 +104,7 @@ def testCommentIsFirstChildInCompound(self): self._AssertNodeIsComment(if_suite.children[1]) def testCommentIsLastChildInCompound(self): - code = textwrap.dedent( - r''' + code = textwrap.dedent(r''' if x: foo = 1 # a comment @@ -123,8 +120,7 @@ def testCommentIsLastChildInCompound(self): self._AssertNodeIsComment(if_suite.children[-2]) def testInlineAfterSeparateLine(self): - code = textwrap.dedent( - r''' + code = textwrap.dedent(r''' bar = 1 # line comment foo = 1 # inline comment @@ -137,13 +133,12 @@ def testInlineAfterSeparateLine(self): sep_comment_node = tree.children[1] self._AssertNodeIsComment(sep_comment_node, '# line comment') - expr = tree.children[2].children[0] + expr = tree.children[2].children[0] inline_comment_node = expr.children[-1] self._AssertNodeIsComment(inline_comment_node, '# inline comment') def testSeparateLineAfterInline(self): - code = textwrap.dedent( - r''' + code = textwrap.dedent(r''' bar = 1 foo = 1 # inline comment # line comment @@ -156,13 +151,12 @@ def testSeparateLineAfterInline(self): sep_comment_node = tree.children[-2] self._AssertNodeIsComment(sep_comment_node, '# line comment') - expr = tree.children[1].children[0] + expr = tree.children[1].children[0] inline_comment_node = expr.children[-1] self._AssertNodeIsComment(inline_comment_node, '# inline comment') def testCommentBeforeDedent(self): - code = textwrap.dedent( - r''' + code = textwrap.dedent(r''' if bar: z = 1 # a comment @@ -177,8 +171,7 @@ def testCommentBeforeDedent(self): self._AssertNodeType('DEDENT', if_suite.children[-1]) def testCommentBeforeDedentTwoLevel(self): - code = textwrap.dedent( - r''' + code = textwrap.dedent(r''' if foo: if bar: z = 1 @@ -195,8 +188,7 @@ def testCommentBeforeDedentTwoLevel(self): self._AssertNodeType('DEDENT', if_suite.children[-1]) def testCommentBeforeDedentTwoLevelImproperlyIndented(self): - code = textwrap.dedent( - r''' + code = textwrap.dedent(r''' if foo: if bar: z = 1 @@ -216,8 +208,7 @@ def testCommentBeforeDedentTwoLevelImproperlyIndented(self): self._AssertNodeType('DEDENT', if_suite.children[-1]) def testCommentBeforeDedentThreeLevel(self): - code = textwrap.dedent( - r''' + code = textwrap.dedent(r''' if foo: if bar: z = 1 @@ -244,8 +235,7 @@ def testCommentBeforeDedentThreeLevel(self): self._AssertNodeType('DEDENT', if_suite_2.children[-1]) def testCommentsInClass(self): - code = textwrap.dedent( - r''' + code = textwrap.dedent(r''' class Foo: """docstring abc...""" # top-level comment @@ -256,19 +246,18 @@ def foo(): pass tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) - class_suite = tree.children[0].children[3] + class_suite = tree.children[0].children[3] another_comment = class_suite.children[-2] self._AssertNodeIsComment(another_comment, '# another') # It's OK for the comment to be a child of funcdef, as long as it's # the first child and thus comes before the 'def'. - funcdef = class_suite.children[3] + funcdef = class_suite.children[3] toplevel_comment = funcdef.children[0] self._AssertNodeIsComment(toplevel_comment, '# top-level') def testMultipleBlockComments(self): - code = textwrap.dedent( - r''' + code = textwrap.dedent(r''' # Block comment number 1 # Block comment number 2 @@ -279,7 +268,7 @@ def f(): tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) - funcdef = tree.children[0] + funcdef = tree.children[0] block_comment_1 = funcdef.children[0] self._AssertNodeIsComment(block_comment_1, '# Block comment number 1') @@ -287,8 +276,7 @@ def f(): self._AssertNodeIsComment(block_comment_2, '# Block comment number 2') def testCommentsOnDedents(self): - code = textwrap.dedent( - r''' + code = textwrap.dedent(r''' class Foo(object): # A comment for qux. def qux(self): @@ -303,7 +291,7 @@ def mux(self): tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) - classdef = tree.children[0] + classdef = tree.children[0] class_suite = classdef.children[6] qux_comment = class_suite.children[1] self._AssertNodeIsComment(qux_comment, '# A comment for qux.') @@ -312,8 +300,7 @@ def mux(self): self._AssertNodeIsComment(interim_comment, '# Interim comment.') def testExprComments(self): - code = textwrap.dedent( - r''' + code = textwrap.dedent(r''' foo( # Request fractions of an hour. 948.0/3600, 20) ''') @@ -325,8 +312,7 @@ def testExprComments(self): self._AssertNodeIsComment(comment, '# Request fractions of an hour.') def testMultipleCommentsInOneExpr(self): - code = textwrap.dedent( - r''' + code = textwrap.dedent(r''' foo( # com 1 948.0/3600, # com 2 20 + 12 # com 3 diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 9e8c568ea..31184c4a3 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -56,7 +56,7 @@ def tearDown(self): # pylint: disable=g-missing-super-call def test_get_exclude_file_patterns_from_yapfignore(self): local_ignore_file = os.path.join(self.test_tmpdir, '.yapfignore') - ignore_patterns = ['temp/**/*.py', 'temp2/*.py'] + ignore_patterns = ['temp/**/*.py', 'temp2/*.py'] with open(local_ignore_file, 'w') as f: f.writelines('\n'.join(ignore_patterns)) @@ -66,7 +66,7 @@ def test_get_exclude_file_patterns_from_yapfignore(self): def test_get_exclude_file_patterns_from_yapfignore_with_wrong_syntax(self): local_ignore_file = os.path.join(self.test_tmpdir, '.yapfignore') - ignore_patterns = ['temp/**/*.py', './wrong/syntax/*.py'] + ignore_patterns = ['temp/**/*.py', './wrong/syntax/*.py'] with open(local_ignore_file, 'w') as f: f.writelines('\n'.join(ignore_patterns)) @@ -79,7 +79,7 @@ def test_get_exclude_file_patterns_from_pyproject(self): except ImportError: return local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') - ignore_patterns = ['temp/**/*.py', 'temp2/*.py'] + ignore_patterns = ['temp/**/*.py', 'temp2/*.py'] with open(local_ignore_file, 'w') as f: f.write('[tool.yapfignore]\n') f.write('ignore_patterns=[') @@ -97,7 +97,7 @@ def test_get_exclude_file_patterns_from_pyproject_with_wrong_syntax(self): except ImportError: return local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') - ignore_patterns = ['temp/**/*.py', './wrong/syntax/*.py'] + ignore_patterns = ['temp/**/*.py', './wrong/syntax/*.py'] with open(local_ignore_file, 'w') as f: f.write('[tool.yapfignore]\n') f.write('ignore_patterns=[') @@ -113,7 +113,7 @@ def test_get_exclude_file_patterns_from_pyproject_no_ignore_section(self): except ImportError: return local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') - ignore_patterns = [] + ignore_patterns = [] open(local_ignore_file, 'w').close() self.assertEqual( @@ -126,7 +126,7 @@ def test_get_exclude_file_patterns_from_pyproject_ignore_section_empty(self): except ImportError: return local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') - ignore_patterns = [] + ignore_patterns = [] with open(local_ignore_file, 'w') as f: f.write('[tool.yapfignore]\n') @@ -151,12 +151,12 @@ def tearDown(self): # pylint: disable=g-missing-super-call shutil.rmtree(self.test_tmpdir) def test_no_local_style(self): - test_file = os.path.join(self.test_tmpdir, 'file.py') + test_file = os.path.join(self.test_tmpdir, 'file.py') style_name = file_resources.GetDefaultStyleForDir(test_file) self.assertEqual(style_name, 'pep8') def test_no_local_style_custom_default(self): - test_file = os.path.join(self.test_tmpdir, 'file.py') + test_file = os.path.join(self.test_tmpdir, 'file.py') style_name = file_resources.GetDefaultStyleForDir( test_file, default_style='custom-default') self.assertEqual(style_name, 'custom-default') @@ -167,27 +167,27 @@ def test_with_local_style(self): open(style_file, 'w').close() test_filename = os.path.join(self.test_tmpdir, 'file.py') - self.assertEqual( - style_file, file_resources.GetDefaultStyleForDir(test_filename)) + self.assertEqual(style_file, + file_resources.GetDefaultStyleForDir(test_filename)) test_filename = os.path.join(self.test_tmpdir, 'dir1', 'file.py') - self.assertEqual( - style_file, file_resources.GetDefaultStyleForDir(test_filename)) + self.assertEqual(style_file, + file_resources.GetDefaultStyleForDir(test_filename)) def test_setup_config(self): # An empty setup.cfg file should not be used setup_config = os.path.join(self.test_tmpdir, 'setup.cfg') open(setup_config, 'w').close() - test_dir = os.path.join(self.test_tmpdir, 'dir1') + test_dir = os.path.join(self.test_tmpdir, 'dir1') style_name = file_resources.GetDefaultStyleForDir(test_dir) self.assertEqual(style_name, 'pep8') # One with a '[yapf]' section should be used with open(setup_config, 'w') as f: f.write('[yapf]\n') - self.assertEqual( - setup_config, file_resources.GetDefaultStyleForDir(test_dir)) + self.assertEqual(setup_config, + file_resources.GetDefaultStyleForDir(test_dir)) def test_pyproject_toml(self): # An empty pyproject.toml file should not be used @@ -199,20 +199,20 @@ def test_pyproject_toml(self): pyproject_toml = os.path.join(self.test_tmpdir, 'pyproject.toml') open(pyproject_toml, 'w').close() - test_dir = os.path.join(self.test_tmpdir, 'dir1') + test_dir = os.path.join(self.test_tmpdir, 'dir1') style_name = file_resources.GetDefaultStyleForDir(test_dir) self.assertEqual(style_name, 'pep8') # One with a '[tool.yapf]' section should be used with open(pyproject_toml, 'w') as f: f.write('[tool.yapf]\n') - self.assertEqual( - pyproject_toml, file_resources.GetDefaultStyleForDir(test_dir)) + self.assertEqual(pyproject_toml, + file_resources.GetDefaultStyleForDir(test_dir)) def test_local_style_at_root(self): # Test behavior of files located on the root, and under root. - rootdir = os.path.abspath(os.path.sep) - test_dir_at_root = os.path.join(rootdir, 'dir1') + rootdir = os.path.abspath(os.path.sep) + test_dir_at_root = os.path.join(rootdir, 'dir1') test_dir_under_root = os.path.join(rootdir, 'dir1', 'dir2') # Fake placing only a style file at the root by mocking `os.path.exists`. @@ -241,7 +241,7 @@ class GetCommandLineFilesTest(unittest.TestCase): def setUp(self): # pylint: disable=g-missing-super-call self.test_tmpdir = tempfile.mkdtemp() - self.old_dir = os.getcwd() + self.old_dir = os.getcwd() def tearDown(self): # pylint: disable=g-missing-super-call os.chdir(self.old_dir) @@ -260,11 +260,13 @@ def test_find_files_not_dirs(self): _touch_files([file1, file2]) self.assertEqual( - file_resources.GetCommandLineFiles( - [file1, file2], recursive=False, exclude=None), [file1, file2]) + file_resources.GetCommandLineFiles([file1, file2], + recursive=False, + exclude=None), [file1, file2]) self.assertEqual( - file_resources.GetCommandLineFiles( - [file1, file2], recursive=True, exclude=None), [file1, file2]) + file_resources.GetCommandLineFiles([file1, file2], + recursive=True, + exclude=None), [file1, file2]) def test_nonrecursive_find_in_dir(self): tdir1 = self._make_test_dir('test1') @@ -293,9 +295,9 @@ def test_recursive_find_in_dir(self): self.assertEqual( sorted( - file_resources.GetCommandLineFiles( - [self.test_tmpdir], recursive=True, exclude=None)), - sorted(files)) + file_resources.GetCommandLineFiles([self.test_tmpdir], + recursive=True, + exclude=None)), sorted(files)) def test_recursive_find_in_dir_with_exclude(self): tdir1 = self._make_test_dir('test1') @@ -310,13 +312,13 @@ def test_recursive_find_in_dir_with_exclude(self): self.assertEqual( sorted( - file_resources.GetCommandLineFiles( - [self.test_tmpdir], recursive=True, exclude=['*test*3.py'])), - sorted( - [ - os.path.join(tdir1, 'testfile1.py'), - os.path.join(tdir2, 'testfile2.py'), - ])) + file_resources.GetCommandLineFiles([self.test_tmpdir], + recursive=True, + exclude=['*test*3.py'])), + sorted([ + os.path.join(tdir1, 'testfile1.py'), + os.path.join(tdir2, 'testfile2.py'), + ])) def test_find_with_excluded_hidden_dirs(self): tdir1 = self._make_test_dir('.test1') @@ -329,16 +331,16 @@ def test_find_with_excluded_hidden_dirs(self): ] _touch_files(files) - actual = file_resources.GetCommandLineFiles( - [self.test_tmpdir], recursive=True, exclude=['*.test1*']) + actual = file_resources.GetCommandLineFiles([self.test_tmpdir], + recursive=True, + exclude=['*.test1*']) self.assertEqual( sorted(actual), - sorted( - [ - os.path.join(tdir2, 'testfile2.py'), - os.path.join(tdir3, 'testfile3.py'), - ])) + sorted([ + os.path.join(tdir2, 'testfile2.py'), + os.path.join(tdir3, 'testfile3.py'), + ])) def test_find_with_excluded_hidden_dirs_relative(self): """Test find with excluded hidden dirs. @@ -373,15 +375,14 @@ def test_find_with_excluded_hidden_dirs_relative(self): self.assertEqual( sorted(actual), - sorted( - [ - os.path.join( - os.path.relpath(self.test_tmpdir), - os.path.basename(tdir2), 'testfile2.py'), - os.path.join( - os.path.relpath(self.test_tmpdir), - os.path.basename(tdir3), 'testfile3.py'), - ])) + sorted([ + os.path.join( + os.path.relpath(self.test_tmpdir), os.path.basename(tdir2), + 'testfile2.py'), + os.path.join( + os.path.relpath(self.test_tmpdir), os.path.basename(tdir3), + 'testfile3.py'), + ])) def test_find_with_excluded_dirs(self): tdir1 = self._make_test_dir('test1') @@ -397,23 +398,23 @@ def test_find_with_excluded_dirs(self): os.chdir(self.test_tmpdir) found = sorted( - file_resources.GetCommandLineFiles( - ['test1', 'test2', 'test3'], - recursive=True, - exclude=[ - 'test1', - 'test2/testinner/', - ])) + file_resources.GetCommandLineFiles(['test1', 'test2', 'test3'], + recursive=True, + exclude=[ + 'test1', + 'test2/testinner/', + ])) self.assertEqual( found, ['test3/foo/bar/bas/xxx/testfile3.py'.replace("/", os.path.sep)]) found = sorted( - file_resources.GetCommandLineFiles( - ['.'], recursive=True, exclude=[ - 'test1', - 'test3', - ])) + file_resources.GetCommandLineFiles(['.'], + recursive=True, + exclude=[ + 'test1', + 'test3', + ])) self.assertEqual( found, ['./test2/testinner/testfile2.py'.replace("/", os.path.sep)]) @@ -516,7 +517,7 @@ def test_write_to_file(self): self.assertEqual(f2.read(), s) def test_write_to_stdout(self): - s = u'foobar' + s = u'foobar' stream = BufferedByteStream() if py3compat.PY3 else py3compat.StringIO() with utils.stdout_redirector(stream): file_resources.WriteReformattedCode( @@ -524,7 +525,7 @@ def test_write_to_stdout(self): self.assertEqual(stream.getvalue(), s) def test_write_encoded_to_stdout(self): - s = '\ufeff# -*- coding: utf-8 -*-\nresult = "passed"\n' # pylint: disable=anomalous-unicode-escape-in-string # noqa + s = '\ufeff# -*- coding: utf-8 -*-\nresult = "passed"\n' # pylint: disable=anomalous-unicode-escape-in-string # noqa stream = BufferedByteStream() if py3compat.PY3 else py3compat.StringIO() with utils.stdout_redirector(stream): file_resources.WriteReformattedCode( @@ -535,17 +536,17 @@ def test_write_encoded_to_stdout(self): class LineEndingTest(unittest.TestCase): def test_line_ending_linefeed(self): - lines = ['spam\n', 'spam\n'] + lines = ['spam\n', 'spam\n'] actual = file_resources.LineEnding(lines) self.assertEqual(actual, '\n') def test_line_ending_carriage_return(self): - lines = ['spam\r', 'spam\r'] + lines = ['spam\r', 'spam\r'] actual = file_resources.LineEnding(lines) self.assertEqual(actual, '\r') def test_line_ending_combo(self): - lines = ['spam\r\n', 'spam\r\n'] + lines = ['spam\r\n', 'spam\r\n'] actual = file_resources.LineEnding(lines) self.assertEqual(actual, '\r\n') diff --git a/yapftests/format_decision_state_test.py b/yapftests/format_decision_state_test.py index d9cdefe8c..63961f332 100644 --- a/yapftests/format_decision_state_test.py +++ b/yapftests/format_decision_state_test.py @@ -32,12 +32,12 @@ def setUpClass(cls): style.SetGlobalStyle(style.CreateYapfStyle()) def testSimpleFunctionDefWithNoSplitting(self): - code = textwrap.dedent(r""" + code = textwrap.dedent(r""" def f(a, b): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) - lline = logical_line.LogicalLine(0, _FilterLine(llines[0])) + lline = logical_line.LogicalLine(0, _FilterLine(llines[0])) lline.CalculateFormattingInformation() # Add: 'f' @@ -86,12 +86,12 @@ def f(a, b): self.assertEqual(repr(state), repr(clone)) def testSimpleFunctionDefWithSplitting(self): - code = textwrap.dedent(r""" + code = textwrap.dedent(r""" def f(a, b): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) - lline = logical_line.LogicalLine(0, _FilterLine(llines[0])) + lline = logical_line.LogicalLine(0, _FilterLine(llines[0])) lline.CalculateFormattingInformation() # Add: 'f' diff --git a/yapftests/line_joiner_test.py b/yapftests/line_joiner_test.py index ea6186693..2eaf16478 100644 --- a/yapftests/line_joiner_test.py +++ b/yapftests/line_joiner_test.py @@ -39,23 +39,20 @@ def _CheckLineJoining(self, code, join_lines): self.assertCodeEqual(line_joiner.CanMergeMultipleLines(llines), join_lines) def testSimpleSingleLineStatement(self): - code = textwrap.dedent( - u"""\ + code = textwrap.dedent(u"""\ if isinstance(a, int): continue """) self._CheckLineJoining(code, join_lines=True) def testSimpleMultipleLineStatement(self): - code = textwrap.dedent( - u"""\ + code = textwrap.dedent(u"""\ if isinstance(b, int): continue """) self._CheckLineJoining(code, join_lines=False) def testSimpleMultipleLineComplexStatement(self): - code = textwrap.dedent( - u"""\ + code = textwrap.dedent(u"""\ if isinstance(c, int): while True: continue @@ -63,22 +60,19 @@ def testSimpleMultipleLineComplexStatement(self): self._CheckLineJoining(code, join_lines=False) def testSimpleMultipleLineStatementWithComment(self): - code = textwrap.dedent( - u"""\ + code = textwrap.dedent(u"""\ if isinstance(d, int): continue # We're pleased that d's an int. """) self._CheckLineJoining(code, join_lines=True) def testSimpleMultipleLineStatementWithLargeIndent(self): - code = textwrap.dedent( - u"""\ + code = textwrap.dedent(u"""\ if isinstance(e, int): continue """) self._CheckLineJoining(code, join_lines=True) def testOverColumnLimit(self): - code = textwrap.dedent( - u"""\ + code = textwrap.dedent(u"""\ if instance(bbbbbbbbbbbbbbbbbbbbbbbbb, int): cccccccccccccccccccccccccc = ddddddddddddddddddddd """) # noqa self._CheckLineJoining(code, join_lines=False) diff --git a/yapftests/logical_line_test.py b/yapftests/logical_line_test.py index 695f88bd5..d18262a7c 100644 --- a/yapftests/logical_line_test.py +++ b/yapftests/logical_line_test.py @@ -29,29 +29,25 @@ class LogicalLineBasicTest(unittest.TestCase): def testConstruction(self): - toks = _MakeFormatTokenList( - [(token.DOT, '.', 'DOT'), (token.VBAR, '|', 'VBAR')]) + toks = _MakeFormatTokenList([(token.DOT, '.', 'DOT'), + (token.VBAR, '|', 'VBAR')]) lline = logical_line.LogicalLine(20, toks) self.assertEqual(20, lline.depth) self.assertEqual(['DOT', 'VBAR'], [tok.name for tok in lline.tokens]) def testFirstLast(self): - toks = _MakeFormatTokenList( - [ - (token.DOT, '.', 'DOT'), (token.LPAR, '(', 'LPAR'), - (token.VBAR, '|', 'VBAR') - ]) + toks = _MakeFormatTokenList([(token.DOT, '.', 'DOT'), + (token.LPAR, '(', 'LPAR'), + (token.VBAR, '|', 'VBAR')]) lline = logical_line.LogicalLine(20, toks) self.assertEqual(20, lline.depth) self.assertEqual('DOT', lline.first.name) self.assertEqual('VBAR', lline.last.name) def testAsCode(self): - toks = _MakeFormatTokenList( - [ - (token.DOT, '.', 'DOT'), (token.LPAR, '(', 'LPAR'), - (token.VBAR, '|', 'VBAR') - ]) + toks = _MakeFormatTokenList([(token.DOT, '.', 'DOT'), + (token.LPAR, '(', 'LPAR'), + (token.VBAR, '|', 'VBAR')]) lline = logical_line.LogicalLine(2, toks) self.assertEqual(' . ( |', lline.AsCode()) @@ -65,7 +61,7 @@ def testAppendToken(self): class LogicalLineFormattingInformationTest(yapf_test_helper.YAPFTest): def testFuncDef(self): - code = textwrap.dedent(r""" + code = textwrap.dedent(r""" def f(a, b): pass """) diff --git a/yapftests/main_test.py b/yapftests/main_test.py index ea6892f5a..c83b8b66a 100644 --- a/yapftests/main_test.py +++ b/yapftests/main_test.py @@ -78,7 +78,7 @@ def patch_raw_input(lines=lines()): return next(lines) try: - orig_raw_import = yapf.py3compat.raw_input + orig_raw_import = yapf.py3compat.raw_input yapf.py3compat.raw_input = patch_raw_input yield finally: @@ -90,7 +90,7 @@ class RunMainTest(yapf_test_helper.YAPFTest): def testShouldHandleYapfError(self): """run_main should handle YapfError and sys.exit(1).""" expected_message = 'yapf: input filenames did not match any python files\n' - sys.argv = ['yapf', 'foo.c'] + sys.argv = ['yapf', 'foo.c'] with captured_output() as (out, err): with self.assertRaises(SystemExit): yapf.run_main() @@ -114,7 +114,7 @@ def testEchoInput(self): self.assertEqual(out.getvalue(), code) def testEchoInputWithStyle(self): - code = 'def f(a = 1\n\n):\n return 2*a\n' + code = 'def f(a = 1\n\n):\n return 2*a\n' yapf_code = 'def f(a=1):\n return 2 * a\n' with patched_input(code): with captured_output() as (out, _): @@ -135,6 +135,5 @@ def testHelp(self): self.assertEqual(ret, 0) help_message = out.getvalue() self.assertIn('indent_width=4', help_message) - self.assertIn( - 'The number of spaces required before a trailing comment.', - help_message) + self.assertIn('The number of spaces required before a trailing comment.', + help_message) diff --git a/yapftests/pytree_unwrapper_test.py b/yapftests/pytree_unwrapper_test.py index cd67e0de1..525278def 100644 --- a/yapftests/pytree_unwrapper_test.py +++ b/yapftests/pytree_unwrapper_test.py @@ -43,79 +43,69 @@ def _CheckLogicalLines(self, llines, list_of_expected): self.assertEqual(list_of_expected, actual) def testSimpleFileScope(self): - code = textwrap.dedent( - r""" + code = textwrap.dedent(r""" x = 1 # a comment y = 2 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines( - llines, [ - (0, ['x', '=', '1']), - (0, ['# a comment']), - (0, ['y', '=', '2']), - ]) + self._CheckLogicalLines(llines, [ + (0, ['x', '=', '1']), + (0, ['# a comment']), + (0, ['y', '=', '2']), + ]) def testSimpleMultilineStatement(self): - code = textwrap.dedent(r""" + code = textwrap.dedent(r""" y = (1 + x) """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines( - llines, [ - (0, ['y', '=', '(', '1', '+', 'x', ')']), - ]) + self._CheckLogicalLines(llines, [ + (0, ['y', '=', '(', '1', '+', 'x', ')']), + ]) def testFileScopeWithInlineComment(self): - code = textwrap.dedent( - r""" + code = textwrap.dedent(r""" x = 1 # a comment y = 2 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines( - llines, [ - (0, ['x', '=', '1', '# a comment']), - (0, ['y', '=', '2']), - ]) + self._CheckLogicalLines(llines, [ + (0, ['x', '=', '1', '# a comment']), + (0, ['y', '=', '2']), + ]) def testSimpleIf(self): - code = textwrap.dedent( - r""" + code = textwrap.dedent(r""" if foo: x = 1 y = 2 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines( - llines, [ - (0, ['if', 'foo', ':']), - (1, ['x', '=', '1']), - (1, ['y', '=', '2']), - ]) + self._CheckLogicalLines(llines, [ + (0, ['if', 'foo', ':']), + (1, ['x', '=', '1']), + (1, ['y', '=', '2']), + ]) def testSimpleIfWithComments(self): - code = textwrap.dedent( - r""" + code = textwrap.dedent(r""" # c1 if foo: # c2 x = 1 y = 2 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines( - llines, [ - (0, ['# c1']), - (0, ['if', 'foo', ':', '# c2']), - (1, ['x', '=', '1']), - (1, ['y', '=', '2']), - ]) + self._CheckLogicalLines(llines, [ + (0, ['# c1']), + (0, ['if', 'foo', ':', '# c2']), + (1, ['x', '=', '1']), + (1, ['y', '=', '2']), + ]) def testIfWithCommentsInside(self): - code = textwrap.dedent( - r""" + code = textwrap.dedent(r""" if foo: # c1 x = 1 # c2 @@ -123,18 +113,16 @@ def testIfWithCommentsInside(self): y = 2 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines( - llines, [ - (0, ['if', 'foo', ':']), - (1, ['# c1']), - (1, ['x', '=', '1', '# c2']), - (1, ['# c3']), - (1, ['y', '=', '2']), - ]) + self._CheckLogicalLines(llines, [ + (0, ['if', 'foo', ':']), + (1, ['# c1']), + (1, ['x', '=', '1', '# c2']), + (1, ['# c3']), + (1, ['y', '=', '2']), + ]) def testIfElifElse(self): - code = textwrap.dedent( - r""" + code = textwrap.dedent(r""" if x: x = 1 # c1 elif y: # c2 @@ -144,20 +132,18 @@ def testIfElifElse(self): z = 1 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines( - llines, [ - (0, ['if', 'x', ':']), - (1, ['x', '=', '1', '# c1']), - (0, ['elif', 'y', ':', '# c2']), - (1, ['y', '=', '1']), - (0, ['else', ':']), - (1, ['# c3']), - (1, ['z', '=', '1']), - ]) + self._CheckLogicalLines(llines, [ + (0, ['if', 'x', ':']), + (1, ['x', '=', '1', '# c1']), + (0, ['elif', 'y', ':', '# c2']), + (1, ['y', '=', '1']), + (0, ['else', ':']), + (1, ['# c3']), + (1, ['z', '=', '1']), + ]) def testNestedCompoundTwoLevel(self): - code = textwrap.dedent( - r""" + code = textwrap.dedent(r""" if x: x = 1 # c1 while t: @@ -166,34 +152,30 @@ def testNestedCompoundTwoLevel(self): k = 1 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines( - llines, [ - (0, ['if', 'x', ':']), - (1, ['x', '=', '1', '# c1']), - (1, ['while', 't', ':']), - (2, ['# c2']), - (2, ['j', '=', '1']), - (1, ['k', '=', '1']), - ]) + self._CheckLogicalLines(llines, [ + (0, ['if', 'x', ':']), + (1, ['x', '=', '1', '# c1']), + (1, ['while', 't', ':']), + (2, ['# c2']), + (2, ['j', '=', '1']), + (1, ['k', '=', '1']), + ]) def testSimpleWhile(self): - code = textwrap.dedent( - r""" + code = textwrap.dedent(r""" while x > 1: # c1 # c2 x = 1 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines( - llines, [ - (0, ['while', 'x', '>', '1', ':', '# c1']), - (1, ['# c2']), - (1, ['x', '=', '1']), - ]) + self._CheckLogicalLines(llines, [ + (0, ['while', 'x', '>', '1', ':', '# c1']), + (1, ['# c2']), + (1, ['x', '=', '1']), + ]) def testSimpleTry(self): - code = textwrap.dedent( - r""" + code = textwrap.dedent(r""" try: pass except: @@ -206,38 +188,34 @@ def testSimpleTry(self): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines( - llines, [ - (0, ['try', ':']), - (1, ['pass']), - (0, ['except', ':']), - (1, ['pass']), - (0, ['except', ':']), - (1, ['pass']), - (0, ['else', ':']), - (1, ['pass']), - (0, ['finally', ':']), - (1, ['pass']), - ]) + self._CheckLogicalLines(llines, [ + (0, ['try', ':']), + (1, ['pass']), + (0, ['except', ':']), + (1, ['pass']), + (0, ['except', ':']), + (1, ['pass']), + (0, ['else', ':']), + (1, ['pass']), + (0, ['finally', ':']), + (1, ['pass']), + ]) def testSimpleFuncdef(self): - code = textwrap.dedent( - r""" + code = textwrap.dedent(r""" def foo(x): # c1 # c2 return x """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines( - llines, [ - (0, ['def', 'foo', '(', 'x', ')', ':', '# c1']), - (1, ['# c2']), - (1, ['return', 'x']), - ]) + self._CheckLogicalLines(llines, [ + (0, ['def', 'foo', '(', 'x', ')', ':', '# c1']), + (1, ['# c2']), + (1, ['return', 'x']), + ]) def testTwoFuncDefs(self): - code = textwrap.dedent( - r""" + code = textwrap.dedent(r""" def foo(x): # c1 # c2 return x @@ -247,45 +225,40 @@ def bar(): # c3 return x """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines( - llines, [ - (0, ['def', 'foo', '(', 'x', ')', ':', '# c1']), - (1, ['# c2']), - (1, ['return', 'x']), - (0, ['def', 'bar', '(', ')', ':', '# c3']), - (1, ['# c4']), - (1, ['return', 'x']), - ]) + self._CheckLogicalLines(llines, [ + (0, ['def', 'foo', '(', 'x', ')', ':', '# c1']), + (1, ['# c2']), + (1, ['return', 'x']), + (0, ['def', 'bar', '(', ')', ':', '# c3']), + (1, ['# c4']), + (1, ['return', 'x']), + ]) def testSimpleClassDef(self): - code = textwrap.dedent( - r""" + code = textwrap.dedent(r""" class Klass: # c1 # c2 p = 1 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines( - llines, [ - (0, ['class', 'Klass', ':', '# c1']), - (1, ['# c2']), - (1, ['p', '=', '1']), - ]) + self._CheckLogicalLines(llines, [ + (0, ['class', 'Klass', ':', '# c1']), + (1, ['# c2']), + (1, ['p', '=', '1']), + ]) def testSingleLineStmtInFunc(self): - code = textwrap.dedent(r""" + code = textwrap.dedent(r""" def f(): return 37 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines( - llines, [ - (0, ['def', 'f', '(', ')', ':']), - (1, ['return', '37']), - ]) + self._CheckLogicalLines(llines, [ + (0, ['def', 'f', '(', ')', ':']), + (1, ['return', '37']), + ]) def testMultipleComments(self): - code = textwrap.dedent( - r""" + code = textwrap.dedent(r""" # Comment #1 # Comment #2 @@ -293,17 +266,15 @@ def f(): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines( - llines, [ - (0, ['# Comment #1']), - (0, ['# Comment #2']), - (0, ['def', 'f', '(', ')', ':']), - (1, ['pass']), - ]) + self._CheckLogicalLines(llines, [ + (0, ['# Comment #1']), + (0, ['# Comment #2']), + (0, ['def', 'f', '(', ')', ':']), + (1, ['pass']), + ]) def testSplitListWithComment(self): - code = textwrap.dedent( - r""" + code = textwrap.dedent(r""" a = [ 'a', 'b', @@ -311,14 +282,9 @@ def testSplitListWithComment(self): ] """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckLogicalLines( - llines, [ - ( - 0, [ - 'a', '=', '[', "'a'", ',', "'b'", ',', "'c'", ',', - '# hello world', ']' - ]) - ]) + self._CheckLogicalLines(llines, [(0, [ + 'a', '=', '[', "'a'", ',', "'b'", ',', "'c'", ',', '# hello world', ']' + ])]) class MatchBracketsTest(yapf_test_helper.YAPFTest): @@ -334,11 +300,9 @@ def _CheckMatchingBrackets(self, llines, list_of_expected): """ actual = [] for lline in llines: - filtered_values = [ - (ft, ft.matching_bracket) - for ft in lline.tokens - if ft.name not in pytree_utils.NONSEMANTIC_TOKENS - ] + filtered_values = [(ft, ft.matching_bracket) + for ft in lline.tokens + if ft.name not in pytree_utils.NONSEMANTIC_TOKENS] if filtered_values: actual.append(filtered_values) @@ -353,8 +317,7 @@ def _CheckMatchingBrackets(self, llines, list_of_expected): self.assertEqual(lline[close_bracket][0], lline[open_bracket][1]) def testFunctionDef(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def foo(a, b=['w','d'], c=[42, 37]): pass """) @@ -365,8 +328,7 @@ def foo(a, b=['w','d'], c=[42, 37]): ]) def testDecorator(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ @bar() def foo(a, b, c): pass @@ -379,8 +341,7 @@ def foo(a, b, c): ]) def testClassDef(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class A(B, C, D): pass """) diff --git a/yapftests/pytree_utils_test.py b/yapftests/pytree_utils_test.py index ec61f75d2..c175f833e 100644 --- a/yapftests/pytree_utils_test.py +++ b/yapftests/pytree_utils_test.py @@ -25,7 +25,7 @@ # module. _GRAMMAR_SYMBOL2NUMBER = pygram.python_grammar.symbol2number -_FOO = 'foo' +_FOO = 'foo' _FOO1 = 'foo1' _FOO2 = 'foo2' _FOO3 = 'foo3' @@ -87,12 +87,12 @@ def _BuildSimpleTree(self): # simple_stmt: # NAME('foo') # - lpar1 = pytree.Leaf(token.LPAR, '(') - lpar2 = pytree.Leaf(token.LPAR, '(') - simple_stmt = pytree.Node( - _GRAMMAR_SYMBOL2NUMBER['simple_stmt'], [pytree.Leaf(token.NAME, 'foo')]) - return pytree.Node( - _GRAMMAR_SYMBOL2NUMBER['suite'], [lpar1, lpar2, simple_stmt]) + lpar1 = pytree.Leaf(token.LPAR, '(') + lpar2 = pytree.Leaf(token.LPAR, '(') + simple_stmt = pytree.Node(_GRAMMAR_SYMBOL2NUMBER['simple_stmt'], + [pytree.Leaf(token.NAME, 'foo')]) + return pytree.Node(_GRAMMAR_SYMBOL2NUMBER['suite'], + [lpar1, lpar2, simple_stmt]) def _MakeNewNodeRPAR(self): return pytree.Leaf(token.RPAR, ')') @@ -102,18 +102,18 @@ def setUp(self): def testInsertNodesBefore(self): # Insert before simple_stmt and make sure it went to the right place - pytree_utils.InsertNodesBefore( - [self._MakeNewNodeRPAR()], self._simple_tree.children[2]) + pytree_utils.InsertNodesBefore([self._MakeNewNodeRPAR()], + self._simple_tree.children[2]) self.assertEqual(4, len(self._simple_tree.children)) - self.assertEqual( - 'RPAR', pytree_utils.NodeName(self._simple_tree.children[2])) - self.assertEqual( - 'simple_stmt', pytree_utils.NodeName(self._simple_tree.children[3])) + self.assertEqual('RPAR', + pytree_utils.NodeName(self._simple_tree.children[2])) + self.assertEqual('simple_stmt', + pytree_utils.NodeName(self._simple_tree.children[3])) def testInsertNodesBeforeFirstChild(self): # Insert before the first child of its parent simple_stmt = self._simple_tree.children[2] - foo_child = simple_stmt.children[0] + foo_child = simple_stmt.children[0] pytree_utils.InsertNodesBefore([self._MakeNewNodeRPAR()], foo_child) self.assertEqual(3, len(self._simple_tree.children)) self.assertEqual(2, len(simple_stmt.children)) @@ -122,18 +122,18 @@ def testInsertNodesBeforeFirstChild(self): def testInsertNodesAfter(self): # Insert after and make sure it went to the right place - pytree_utils.InsertNodesAfter( - [self._MakeNewNodeRPAR()], self._simple_tree.children[2]) + pytree_utils.InsertNodesAfter([self._MakeNewNodeRPAR()], + self._simple_tree.children[2]) self.assertEqual(4, len(self._simple_tree.children)) - self.assertEqual( - 'simple_stmt', pytree_utils.NodeName(self._simple_tree.children[2])) - self.assertEqual( - 'RPAR', pytree_utils.NodeName(self._simple_tree.children[3])) + self.assertEqual('simple_stmt', + pytree_utils.NodeName(self._simple_tree.children[2])) + self.assertEqual('RPAR', + pytree_utils.NodeName(self._simple_tree.children[3])) def testInsertNodesAfterLastChild(self): # Insert after the last child of its parent simple_stmt = self._simple_tree.children[2] - foo_child = simple_stmt.children[0] + foo_child = simple_stmt.children[0] pytree_utils.InsertNodesAfter([self._MakeNewNodeRPAR()], foo_child) self.assertEqual(3, len(self._simple_tree.children)) self.assertEqual(2, len(simple_stmt.children)) @@ -143,16 +143,16 @@ def testInsertNodesAfterLastChild(self): def testInsertNodesWhichHasParent(self): # Try to insert an existing tree node into another place and fail. with self.assertRaises(RuntimeError): - pytree_utils.InsertNodesAfter( - [self._simple_tree.children[1]], self._simple_tree.children[0]) + pytree_utils.InsertNodesAfter([self._simple_tree.children[1]], + self._simple_tree.children[0]) class AnnotationsTest(unittest.TestCase): def setUp(self): self._leaf = pytree.Leaf(token.LPAR, '(') - self._node = pytree.Node( - _GRAMMAR_SYMBOL2NUMBER['simple_stmt'], [pytree.Leaf(token.NAME, 'foo')]) + self._node = pytree.Node(_GRAMMAR_SYMBOL2NUMBER['simple_stmt'], + [pytree.Leaf(token.NAME, 'foo')]) def testGetWhenNone(self): self.assertIsNone(pytree_utils.GetNodeAnnotation(self._leaf, _FOO)) @@ -183,18 +183,18 @@ def testMultiple(self): self.assertEqual(pytree_utils.GetNodeAnnotation(self._leaf, _FOO5), 5) def testSubtype(self): - pytree_utils.AppendNodeAnnotation( - self._leaf, pytree_utils.Annotation.SUBTYPE, _FOO) + pytree_utils.AppendNodeAnnotation(self._leaf, + pytree_utils.Annotation.SUBTYPE, _FOO) self.assertSetEqual( - pytree_utils.GetNodeAnnotation( - self._leaf, pytree_utils.Annotation.SUBTYPE), {_FOO}) + pytree_utils.GetNodeAnnotation(self._leaf, + pytree_utils.Annotation.SUBTYPE), {_FOO}) pytree_utils.RemoveSubtypeAnnotation(self._leaf, _FOO) self.assertSetEqual( - pytree_utils.GetNodeAnnotation( - self._leaf, pytree_utils.Annotation.SUBTYPE), set()) + pytree_utils.GetNodeAnnotation(self._leaf, + pytree_utils.Annotation.SUBTYPE), set()) def testSetOnNode(self): pytree_utils.SetNodeAnnotation(self._node, _FOO, 20) diff --git a/yapftests/pytree_visitor_test.py b/yapftests/pytree_visitor_test.py index 231183030..45a83b113 100644 --- a/yapftests/pytree_visitor_test.py +++ b/yapftests/pytree_visitor_test.py @@ -31,7 +31,7 @@ class _NodeNameCollector(pytree_visitor.PyTreeVisitor): """ def __init__(self): - self.all_node_names = [] + self.all_node_names = [] self.name_node_values = [] def DefaultNodeVisit(self, node): @@ -61,7 +61,7 @@ def Visit_NAME(self, leaf): class PytreeVisitorTest(unittest.TestCase): def testCollectAllNodeNamesSimpleCode(self): - tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_SIMPLE_CODE) + tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_SIMPLE_CODE) collector = _NodeNameCollector() collector.Visit(tree) expected_names = [ @@ -76,7 +76,7 @@ def testCollectAllNodeNamesSimpleCode(self): self.assertEqual(expected_name_node_values, collector.name_node_values) def testCollectAllNodeNamesNestedCode(self): - tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_NESTED_CODE) + tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_NESTED_CODE) collector = _NodeNameCollector() collector.Visit(tree) expected_names = [ @@ -95,7 +95,7 @@ def testCollectAllNodeNamesNestedCode(self): def testDumper(self): # PyTreeDumper is mainly a debugging utility, so only do basic sanity # checking. - tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_SIMPLE_CODE) + tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_SIMPLE_CODE) stream = py3compat.StringIO() pytree_visitor.PyTreeDumper(target_stream=stream).Visit(tree) @@ -106,7 +106,7 @@ def testDumper(self): def testDumpPyTree(self): # Similar sanity checking for the convenience wrapper DumpPyTree - tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_SIMPLE_CODE) + tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_SIMPLE_CODE) stream = py3compat.StringIO() pytree_visitor.DumpPyTree(tree, target_stream=stream) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 7f1e1a43e..f7bb4c5f5 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -33,12 +33,10 @@ def testSplittingAllArgs(self): style.SetGlobalStyle( style.CreateStyleFromConfig( '{split_all_comma_separated_values: true, column_limit: 40}')) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ responseDict = {"timestamp": timestamp, "someValue": value, "whatever": 120} """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ responseDict = { "timestamp": timestamp, "someValue": value, @@ -48,12 +46,10 @@ def testSplittingAllArgs(self): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ yes = { 'yes': 'no', 'no': 'yes', } """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ yes = { 'yes': 'no', 'no': 'yes', @@ -61,13 +57,11 @@ def testSplittingAllArgs(self): """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo(long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args): pass """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo(long_arg, really_long_arg, really_really_long_arg, @@ -76,12 +70,10 @@ def foo(long_arg, """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ foo_tuple = [long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args] """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ foo_tuple = [ long_arg, really_long_arg, @@ -91,25 +83,21 @@ def foo(long_arg, """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ foo_tuple = [short, arg] """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ foo_tuple = [short, arg] """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # There is a test for split_all_top_level_comma_separated_values, with # different expected value - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ someLongFunction(this_is_a_very_long_parameter, abc=(a, this_will_just_fit_xxxxxxx)) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ someLongFunction( this_is_a_very_long_parameter, abc=(a, @@ -124,12 +112,10 @@ def testSplittingTopLevelAllArgs(self): '{split_all_top_level_comma_separated_values: true, ' 'column_limit: 40}')) # Works the same way as split_all_comma_separated_values - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ responseDict = {"timestamp": timestamp, "someValue": value, "whatever": 120} """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ responseDict = { "timestamp": timestamp, "someValue": value, @@ -139,13 +125,11 @@ def testSplittingTopLevelAllArgs(self): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Works the same way as split_all_comma_separated_values - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo(long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args): pass """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo(long_arg, really_long_arg, really_really_long_arg, @@ -155,12 +139,10 @@ def foo(long_arg, llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Works the same way as split_all_comma_separated_values - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ foo_tuple = [long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args] """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ foo_tuple = [ long_arg, really_long_arg, @@ -171,41 +153,35 @@ def foo(long_arg, llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Works the same way as split_all_comma_separated_values - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ foo_tuple = [short, arg] """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ foo_tuple = [short, arg] """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # There is a test for split_all_comma_separated_values, with different # expected value - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ someLongFunction(this_is_a_very_long_parameter, abc=(a, this_will_just_fit_xxxxxxx)) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ someLongFunction( this_is_a_very_long_parameter, abc=(a, this_will_just_fit_xxxxxxx)) """) - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) actual_formatted_code = reformatter.Reformat(llines) self.assertEqual(40, len(actual_formatted_code.splitlines()[-1])) self.assertCodeEqual(expected_formatted_code, actual_formatted_code) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ someLongFunction(this_is_a_very_long_parameter, abc=(a, this_will_not_fit_xxxxxxxxx)) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ someLongFunction( this_is_a_very_long_parameter, abc=(a, @@ -215,13 +191,11 @@ def foo(long_arg, self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Exercise the case where there's no opening bracket (for a, b) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ a, b = f( a_very_long_parameter, yet_another_one, and_another) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ a, b = f( a_very_long_parameter, yet_another_one, and_another) """) @@ -229,8 +203,7 @@ def foo(long_arg, self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Don't require splitting before comments. - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ KO = { 'ABC': Abc, # abc 'DEF': Def, # def @@ -239,8 +212,7 @@ def foo(long_arg, 'JKL': Jkl, } """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ KO = { 'ABC': Abc, # abc 'DEF': Def, # def @@ -253,8 +225,7 @@ def foo(long_arg, self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSimpleFunctionsWithTrailingComments(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def g(): # Trailing comment if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -266,8 +237,7 @@ def f( # Intermediate comment xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def g(): # Trailing comment if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -284,13 +254,11 @@ def f( # Intermediate comment self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBlankLinesBetweenTopLevelImportsAndVariables(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ import foo as bar VAR = 'baz' """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ import foo as bar VAR = 'baz' @@ -298,14 +266,12 @@ def testBlankLinesBetweenTopLevelImportsAndVariables(self): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ import foo as bar VAR = 'baz' """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ import foo as bar @@ -317,32 +283,28 @@ def testBlankLinesBetweenTopLevelImportsAndVariables(self): '{based_on_style: yapf, ' 'blank_lines_between_top_level_imports_and_variables: 2}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ import foo as bar # Some comment """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ import foo as bar # Some comment """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ import foo as bar class Baz(): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ import foo as bar @@ -352,14 +314,12 @@ class Baz(): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ import foo as bar def foobar(): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ import foo as bar @@ -369,14 +329,12 @@ def foobar(): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foobar(): from foo import Bar Bar.baz() """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foobar(): from foo import Bar Bar.baz() @@ -385,39 +343,34 @@ def foobar(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBlankLinesAtEndOfFile(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foobar(): # foo pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foobar(): # foo pass """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ x = { 'a':37,'b':42, 'c':927} """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ x = {'a': 37, 'b': 42, 'c': 927} """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testIndentBlankLines(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class foo(object): def foobar(self): @@ -445,19 +398,18 @@ class foo(object):\n \n def foobar(self):\n \n pass\n \n def barfoo(se '{based_on_style: yapf, indent_blank_lines: true}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) - unformatted_code, expected_formatted_code = ( - expected_formatted_code, unformatted_code) + unformatted_code, expected_formatted_code = (expected_formatted_code, + unformatted_code) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMultipleUgliness(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ x = { 'a':37,'b':42, 'c':927} @@ -473,8 +425,7 @@ def g(self, x,y=42): def f ( a ) : return 37+-+a[42-x : y**3] """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ x = {'a': 37, 'b': 42, 'c': 927} y = 'hello ' 'world' @@ -498,8 +449,7 @@ def f(a): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testComments(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class Foo(object): pass @@ -521,8 +471,7 @@ class Baz(object): class Qux(object): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class Foo(object): pass @@ -553,18 +502,16 @@ class Qux(object): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSingleComment(self): - code = textwrap.dedent("""\ + code = textwrap.dedent("""\ # Thing 1 """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentsWithTrailingSpaces(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ # Thing 1 \n# Thing 2 \n""") - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ # Thing 1 # Thing 2 """) @@ -572,8 +519,7 @@ def testCommentsWithTrailingSpaces(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testCommentsInDataLiteral(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def f(): return collections.OrderedDict({ # First comment. @@ -590,8 +536,7 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testEndingWhitespaceAfterSimpleStatement(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ import foo as bar # Thing 1 # Thing 2 @@ -600,8 +545,7 @@ def testEndingWhitespaceAfterSimpleStatement(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDocstrings(self): - unformatted_code = textwrap.dedent( - '''\ + unformatted_code = textwrap.dedent('''\ u"""Module-level docstring.""" import os class Foo(object): @@ -618,8 +562,7 @@ def qux(self): print('hello {}'.format('world')) return 42 ''') - expected_formatted_code = textwrap.dedent( - '''\ + expected_formatted_code = textwrap.dedent('''\ u"""Module-level docstring.""" import os @@ -640,8 +583,7 @@ def qux(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDocstringAndMultilineComment(self): - unformatted_code = textwrap.dedent( - '''\ + unformatted_code = textwrap.dedent('''\ """Hello world""" # A multiline # comment @@ -655,8 +597,7 @@ def foo(self): # comment pass ''') - expected_formatted_code = textwrap.dedent( - '''\ + expected_formatted_code = textwrap.dedent('''\ """Hello world""" @@ -677,8 +618,7 @@ def foo(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMultilineDocstringAndMultilineComment(self): - unformatted_code = textwrap.dedent( - '''\ + unformatted_code = textwrap.dedent('''\ """Hello world RIP Dennis Richie. @@ -701,8 +641,7 @@ def foo(self): # comment pass ''') - expected_formatted_code = textwrap.dedent( - '''\ + expected_formatted_code = textwrap.dedent('''\ """Hello world RIP Dennis Richie. @@ -732,26 +671,24 @@ def foo(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testTupleCommaBeforeLastParen(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ a = ( 1, ) """) expected_formatted_code = textwrap.dedent("""\ a = (1,) """) - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoBreakOutsideOfBracket(self): # FIXME(morbo): How this is formatted is not correct. But it's syntactically # correct. - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def f(): assert port >= minimum, \ 'Unexpected port %d when minimum was %d.' % (port, minimum) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def f(): assert port >= minimum, 'Unexpected port %d when minimum was %d.' % (port, minimum) @@ -760,8 +697,7 @@ def f(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBlankLinesBeforeDecorators(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ @foo() class A(object): @bar() @@ -769,8 +705,7 @@ class A(object): def x(self): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ @foo() class A(object): @@ -783,16 +718,14 @@ def x(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testCommentBetweenDecorators(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ @foo() # frob @bar def x (self): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ @foo() # frob @bar @@ -803,14 +736,12 @@ def x(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testListComprehension(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def given(y): [k for k in () if k in y] """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def given(y): [k for k in () if k in y] """) @@ -818,16 +749,14 @@ def given(y): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testListComprehensionPreferOneLine(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def given(y): long_variable_name = [ long_var_name + 1 for long_var_name in () if long_var_name == 2] """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def given(y): long_variable_name = [ long_var_name + 1 for long_var_name in () if long_var_name == 2 @@ -837,14 +766,12 @@ def given(y): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testListComprehensionPreferOneLineOverArithmeticSplit(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def given(used_identifiers): return (sum(len(identifier) for identifier in used_identifiers) / len(used_identifiers)) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def given(used_identifiers): return (sum(len(identifier) for identifier in used_identifiers) / len(used_identifiers)) @@ -853,16 +780,14 @@ def given(used_identifiers): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testListComprehensionPreferThreeLinesForLineWrap(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def given(y): long_variable_name = [ long_var_name + 1 for long_var_name, number_two in () if long_var_name == 2 and number_two == 3] """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def given(y): long_variable_name = [ long_var_name + 1 @@ -874,16 +799,14 @@ def given(y): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testListComprehensionPreferNoBreakForTrivialExpression(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def given(y): long_variable_name = [ long_var_name for long_var_name, number_two in () if long_var_name == 2 and number_two == 3] """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def given(y): long_variable_name = [ long_var_name for long_var_name, number_two in () @@ -894,7 +817,7 @@ def given(y): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testOpeningAndClosingBrackets(self): - unformatted_code = """\ + unformatted_code = """\ foo( (1, ) ) foo( ( 1, 2, 3 ) ) foo( ( 1, 2, 3, ) ) @@ -908,16 +831,14 @@ def testOpeningAndClosingBrackets(self): 3, )) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSingleLineFunctions(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo(): return 42 """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo(): return 42 """) @@ -935,16 +856,14 @@ def testNoQueueSeletionInMiddleOfLine(self): find_symbol(node.type) + "< " + " ".join( find_pattern(n) for n in node.child) + " >" """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoSpacesBetweenSubscriptsAndCalls(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ aaaaaaaaaa = bbbbbbbb.ccccccccc() [42] (a, 2) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaa = bbbbbbbb.ccccccccc()[42](a, 2) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) @@ -952,25 +871,21 @@ def testNoSpacesBetweenSubscriptsAndCalls(self): def testNoSpacesBetweenOpeningBracketAndStartingOperator(self): # Unary operator. - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ aaaaaaaaaa = bbbbbbbb.ccccccccc[ -1 ]( -42 ) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaa = bbbbbbbb.ccccccccc[-1](-42) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Varargs and kwargs. - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ aaaaaaaaaa = bbbbbbbb.ccccccccc( *varargs ) aaaaaaaaaa = bbbbbbbb.ccccccccc( **kwargs ) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaa = bbbbbbbb.ccccccccc(*varargs) aaaaaaaaaa = bbbbbbbb.ccccccccc(**kwargs) """) @@ -978,15 +893,13 @@ def testNoSpacesBetweenOpeningBracketAndStartingOperator(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMultilineCommentReformatted(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if True: # This is a multiline # comment. pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if True: # This is a multiline # comment. @@ -996,8 +909,7 @@ def testMultilineCommentReformatted(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDictionaryMakerFormatting(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ _PYTHON_STATEMENTS = frozenset({ lambda x, y: 'simple_stmt': 'small_stmt', 'expr_stmt': 'print_stmt', 'del_stmt': 'pass_stmt', lambda: 'break_stmt': 'continue_stmt', 'return_stmt': 'raise_stmt', @@ -1005,8 +917,7 @@ def testDictionaryMakerFormatting(self): 'if_stmt', 'while_stmt': 'for_stmt', }) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ _PYTHON_STATEMENTS = frozenset({ lambda x, y: 'simple_stmt': 'small_stmt', 'expr_stmt': 'print_stmt', @@ -1023,16 +934,14 @@ def testDictionaryMakerFormatting(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSimpleMultilineCode(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if True: aaaaaaaaaaaaaa.bbbbbbbbbbbbbb.ccccccc(zzzzzzzzzzzz, \ xxxxxxxxxxx, yyyyyyyyyyyy, vvvvvvvvv) aaaaaaaaaaaaaa.bbbbbbbbbbbbbb.ccccccc(zzzzzzzzzzzz, \ xxxxxxxxxxx, yyyyyyyyyyyy, vvvvvvvvv) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if True: aaaaaaaaaaaaaa.bbbbbbbbbbbbbb.ccccccc(zzzzzzzzzzzz, xxxxxxxxxxx, yyyyyyyyyyyy, vvvvvvvvv) @@ -1043,8 +952,7 @@ def testSimpleMultilineCode(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMultilineComment(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ if Foo: # Hello world # Yo man. @@ -1057,15 +965,14 @@ def testMultilineComment(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testSpaceBetweenStringAndParentheses(self): - code = textwrap.dedent("""\ + code = textwrap.dedent("""\ b = '0' ('hello') """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testMultilineString(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ code = textwrap.dedent('''\ if Foo: # Hello world @@ -1079,8 +986,7 @@ def testMultilineString(self): llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - '''\ + unformatted_code = textwrap.dedent('''\ def f(): email_text += """This is a really long docstring that goes over the column limit and is multi-line.

Czar: """+despot["Nicholas"]+"""
@@ -1089,8 +995,7 @@ def f(): """ ''') # noqa - expected_formatted_code = textwrap.dedent( - '''\ + expected_formatted_code = textwrap.dedent('''\ def f(): email_text += """This is a really long docstring that goes over the column limit and is multi-line.

Czar: """ + despot["Nicholas"] + """
@@ -1103,8 +1008,7 @@ def f(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSimpleMultilineWithComments(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ if ( # This is the first comment a and # This is the second comment # This is the third comment @@ -1116,14 +1020,12 @@ def testSimpleMultilineWithComments(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testMatchingParenSplittingMatching(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def f(): raise RuntimeError('unable to find insertion point for target node', (target,)) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def f(): raise RuntimeError('unable to find insertion point for target node', (target,)) @@ -1132,8 +1034,7 @@ def f(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testContinuationIndent(self): - unformatted_code = textwrap.dedent( - '''\ + unformatted_code = textwrap.dedent('''\ class F: def _ProcessArgLists(self, node): """Common method for processing argument lists.""" @@ -1143,8 +1044,7 @@ def _ProcessArgLists(self, node): child, subtype=_ARGLIST_TOKEN_TO_SUBTYPE.get( child.value, format_token.Subtype.NONE)) ''') - expected_formatted_code = textwrap.dedent( - '''\ + expected_formatted_code = textwrap.dedent('''\ class F: def _ProcessArgLists(self, node): @@ -1160,14 +1060,12 @@ def _ProcessArgLists(self, node): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testTrailingCommaAndBracket(self): - unformatted_code = textwrap.dedent( - '''\ + unformatted_code = textwrap.dedent('''\ a = { 42, } b = ( 42, ) c = [ 42, ] ''') - expected_formatted_code = textwrap.dedent( - '''\ + expected_formatted_code = textwrap.dedent('''\ a = { 42, } @@ -1180,23 +1078,20 @@ def testTrailingCommaAndBracket(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testI18n(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ N_('Some years ago - never mind how long precisely - having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world.') # A comment is here. """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ foo('Fake function call') #. Some years ago - never mind how long precisely - having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testI18nCommentsInDataLiteral(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def f(): return collections.OrderedDict({ #. First i18n comment. @@ -1210,8 +1105,7 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testClosingBracketIndent(self): - code = textwrap.dedent( - '''\ + code = textwrap.dedent('''\ def f(): def g(): @@ -1224,8 +1118,7 @@ def g(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testClosingBracketsInlinedInCall(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class Foo(object): def bar(self): @@ -1239,8 +1132,7 @@ def bar(self): "porkporkpork": 5, }) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class Foo(object): def bar(self): @@ -1258,8 +1150,7 @@ def bar(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testLineWrapInForExpression(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class A: def x(self, node, name, n=1): @@ -1272,7 +1163,7 @@ def x(self, node, name, n=1): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionCallContinuationLine(self): - code = """\ + code = """\ class foo: def bar(self, node, name, n=1): @@ -1286,8 +1177,7 @@ def bar(self, node, name, n=1): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testI18nNonFormatting(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class F(object): def __init__(self, fieldname, @@ -1299,8 +1189,7 @@ def __init__(self, fieldname, self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSpaceBetweenUnaryOpAndOpeningParen(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ if ~(a or b): pass """) @@ -1308,8 +1197,7 @@ def testNoSpaceBetweenUnaryOpAndOpeningParen(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentBeforeFuncDef(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class Foo(object): a = 42 @@ -1327,8 +1215,7 @@ def __init__(self, self.assertCodeEqual(code, reformatter.Reformat(llines)) def testExcessLineCountWithDefaultKeywords(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class Fnord(object): def Moo(self): aaaaaaaaaaaaaaaa = self._bbbbbbbbbbbbbbbbbbbbbbb( @@ -1336,8 +1223,7 @@ def Moo(self): fffff=fffff, ggggggg=ggggggg, hhhhhhhhhhhhh=hhhhhhhhhhhhh, iiiiiii=iiiiiiiiiiiiii) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class Fnord(object): def Moo(self): @@ -1354,8 +1240,7 @@ def Moo(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSpaceAfterNotOperator(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ if not (this and that): pass """) @@ -1363,8 +1248,7 @@ def testSpaceAfterNotOperator(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoPenaltySplitting(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def f(): if True: if True: @@ -1377,8 +1261,7 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testExpressionPenalties(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def f(): if ((left.value == '(' and right.value == ')') or (left.value == '[' and right.value == ']') or @@ -1389,16 +1272,14 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testLineDepthOfSingleLineStatement(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ while True: continue for x in range(3): continue try: a = 42 except: b = 42 with open(a) as fd: a = fd.read() """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ while True: continue for x in range(3): @@ -1414,13 +1295,11 @@ def testLineDepthOfSingleLineStatement(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplitListWithTerminatingComma(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ FOO = ['bar', 'baz', 'mux', 'qux', 'quux', 'quuux', 'quuuux', 'quuuuux', 'quuuuuux', 'quuuuuuux', lambda a, b: 37,] """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ FOO = [ 'bar', 'baz', @@ -1439,8 +1318,7 @@ def testSplitListWithTerminatingComma(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplitListWithInterspersedComments(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ FOO = [ 'bar', # bar 'baz', # baz @@ -1459,7 +1337,7 @@ def testSplitListWithInterspersedComments(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testRelativeImportStatements(self): - code = textwrap.dedent("""\ + code = textwrap.dedent("""\ from ... import bork """) llines = yapf_test_helper.ParseAndUnwrap(code) @@ -1467,15 +1345,13 @@ def testRelativeImportStatements(self): def testSingleLineList(self): # A list on a single line should prefer to remain contiguous. - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = aaaaaaaaaaa( ("...", "."), "..", ".............................................." ) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = aaaaaaaaaaa( ("...", "."), "..", "..............................................") """) # noqa @@ -1483,8 +1359,7 @@ def testSingleLineList(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBlankLinesBeforeFunctionsNotInColumnZero(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ import signal @@ -1499,8 +1374,7 @@ def timeout(seconds=1): except: pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ import signal try: @@ -1519,8 +1393,7 @@ def timeout(seconds=1): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoKeywordArgumentBreakage(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class A(object): def b(self): @@ -1532,7 +1405,7 @@ def b(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testTrailerOnSingleLine(self): - code = """\ + code = """\ urlpatterns = patterns('', url(r'^$', 'homepage_view'), url(r'^/login/$', 'login_view'), url(r'^/login/$', 'logout_view'), @@ -1542,8 +1415,7 @@ def testTrailerOnSingleLine(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testIfConditionalParens(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class Foo: def bar(): @@ -1556,8 +1428,7 @@ def bar(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testContinuationMarkers(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. "\\ "Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur "\\ "ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis "\\ @@ -1567,16 +1438,14 @@ def testContinuationMarkers(self): llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ from __future__ import nested_scopes, generators, division, absolute_import, with_statement, \\ print_function, unicode_literals """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ if aaaaaaaaa == 42 and bbbbbbbbbbbbbb == 42 and \\ cccccccc == 42: pass @@ -1585,8 +1454,7 @@ def testContinuationMarkers(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentsWithContinuationMarkers(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def fn(arg): v = fn2(key1=True, #c1 @@ -1597,8 +1465,7 @@ def fn(arg): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testMultipleContinuationMarkers(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ xyz = \\ \\ some_thing() @@ -1607,7 +1474,7 @@ def testMultipleContinuationMarkers(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testContinuationMarkerAfterStringWithContinuation(self): - code = """\ + code = """\ s = 'foo \\ bar' \\ .format() @@ -1616,8 +1483,7 @@ def testContinuationMarkerAfterStringWithContinuation(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testEmptyContainers(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ flags.DEFINE_list( 'output_dirs', [], 'Lorem ipsum dolor sit amet, consetetur adipiscing elit. Donec a diam lectus. ' @@ -1627,12 +1493,10 @@ def testEmptyContainers(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testSplitStringsIfSurroundedByParens(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ a = foo.bar({'xxxxxxxxxxxxxxxxxxxxxxx' 'yyyyyyyyyyyyyyyyyyyyyyyyyy': baz[42]} + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbb' 'cccccccccccccccccccccccccccccccc' 'ddddddddddddddddddddddddddddd') """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ a = foo.bar({'xxxxxxxxxxxxxxxxxxxxxxx' 'yyyyyyyyyyyyyyyyyyyyyyyyyy': baz[42]} + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' @@ -1643,8 +1507,7 @@ def testSplitStringsIfSurroundedByParens(self): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ a = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' \ 'bbbbbbbbbbbbbbbbbbbbbbbbbb' 'cccccccccccccccccccccccccccccccc' \ 'ddddddddddddddddddddddddddddd' @@ -1653,8 +1516,7 @@ def testSplitStringsIfSurroundedByParens(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testMultilineShebang(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ #!/bin/sh if "true" : '''\' then @@ -1674,8 +1536,7 @@ def testMultilineShebang(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSplittingAroundTermOperators(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ a_very_long_function_call_yada_yada_etc_etc_etc(long_arg1, long_arg2 / long_arg3) """) @@ -1683,8 +1544,7 @@ def testNoSplittingAroundTermOperators(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSplittingAroundCompOperators(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa is not bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa in bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa not in bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) @@ -1692,8 +1552,7 @@ def testNoSplittingAroundCompOperators(self): c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa is bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa <= bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) """) # noqa - expected_code = textwrap.dedent( - """\ + expected_code = textwrap.dedent("""\ c = ( aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa is not bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) @@ -1715,8 +1574,7 @@ def testNoSplittingAroundCompOperators(self): self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testNoSplittingWithinSubscriptList(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ somequitelongvariablename.somemember[(a, b)] = { 'somelongkey': 1, 'someotherlongkey': 2 @@ -1726,8 +1584,7 @@ def testNoSplittingWithinSubscriptList(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testExcessCharacters(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class foo: def bar(self): @@ -1738,16 +1595,14 @@ def bar(self): llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def _(): if True: if True: if contract == allow_contract and attr_dict.get(if_attribute) == has_value: return True """) # noqa - expected_code = textwrap.dedent( - """\ + expected_code = textwrap.dedent("""\ def _(): if True: if True: @@ -1759,8 +1614,7 @@ def _(): self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testDictSetGenerator(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ foo = { variable: 'hello world. How are you today?' for variable in fnord @@ -1771,8 +1625,7 @@ def testDictSetGenerator(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testUnaryOpInDictionaryValue(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ beta = "123" test = {'alpha': beta[-1]} @@ -1783,8 +1636,7 @@ def testUnaryOpInDictionaryValue(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testUnaryNotOperator(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ if True: if True: if True: @@ -1796,7 +1648,7 @@ def testUnaryNotOperator(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testRelaxArraySubscriptAffinity(self): - code = """\ + code = """\ class A(object): def f(self, aaaaaaaaa, bbbbbbbbbbbbb, row): @@ -1812,18 +1664,17 @@ def f(self, aaaaaaaaa, bbbbbbbbbbbbb, row): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionCallInDict(self): - code = "a = {'a': b(c=d, **e)}\n" + code = "a = {'a': b(c=d, **e)}\n" llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionCallInNestedDict(self): - code = "a = {'a': {'a': {'a': b(c=d, **e)}}}\n" + code = "a = {'a': {'a': {'a': b(c=d, **e)}}}\n" llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testUnbreakableNot(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def test(): if not "Foooooooooooooooooooooooooooooo" or "Foooooooooooooooooooooooooooooo" == "Foooooooooooooooooooooooooooooo": pass @@ -1832,8 +1683,7 @@ def test(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testSplitListWithComment(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ a = [ 'a', 'b', @@ -1844,8 +1694,7 @@ def testSplitListWithComment(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testOverColumnLimit(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class Test: def testSomething(self): @@ -1855,8 +1704,7 @@ def testSomething(self): ('aaaaaaaaaaaaa', 'bbbb'): 'ccccccccccccccccccccccccccccccccccccccccccc', } """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class Test: def testSomething(self): @@ -1873,8 +1721,7 @@ def testSomething(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testEndingComment(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ a = f( a="something", b="something requiring comment which is quite long", # comment about b (pushes line over 79) @@ -1884,8 +1731,7 @@ def testEndingComment(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testContinuationSpaceRetention(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def fn(): return module \\ .method(Object(data, @@ -1896,8 +1742,7 @@ def fn(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testIfExpressionWithFunctionCall(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ if x or z.y( a, c, @@ -1909,8 +1754,7 @@ def testIfExpressionWithFunctionCall(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testUnformattedAfterMultilineString(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def foo(): com_text = \\ ''' @@ -1921,8 +1765,7 @@ def foo(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSpacesAroundKeywordDefaultValues(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ sources = { 'json': request.get_json(silent=True) or {}, 'json2': request.get_json(silent=True), @@ -1933,14 +1776,12 @@ def testNoSpacesAroundKeywordDefaultValues(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSplittingBeforeEndingSubscriptBracket(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if True: if True: status = cf.describe_stacks(StackName=stackname)[u'Stacks'][0][u'StackStatus'] """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if True: if True: status = cf.describe_stacks( @@ -1950,8 +1791,7 @@ def testNoSplittingBeforeEndingSubscriptBracket(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoSplittingOnSingleArgument(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ xxxxxxxxxxxxxx = (re.search(r'(\\d+\\.\\d+\\.\\d+\\.)\\d+', aaaaaaa.bbbbbbbbbbbb).group(1) + re.search(r'\\d+\\.\\d+\\.\\d+\\.(\\d+)', @@ -1961,8 +1801,7 @@ def testNoSplittingOnSingleArgument(self): re.search(r'\\d+\\.\\d+\\.\\d+\\.(\\d+)', ccccccc).group(c.d)) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ xxxxxxxxxxxxxx = ( re.search(r'(\\d+\\.\\d+\\.\\d+\\.)\\d+', aaaaaaa.bbbbbbbbbbbb).group(1) + re.search(r'\\d+\\.\\d+\\.\\d+\\.(\\d+)', ccccccc).group(1)) @@ -1974,15 +1813,13 @@ def testNoSplittingOnSingleArgument(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingArraysSensibly(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ while True: while True: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list['bbbbbbbbbbbbbbbbbbbbbbbbb'].split(',') aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list('bbbbbbbbbbbbbbbbbbbbbbbbb').split(',') """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ while True: while True: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list[ @@ -1994,15 +1831,13 @@ def testSplittingArraysSensibly(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testComprehensionForAndIf(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class f: def __repr__(self): tokens_repr = ','.join(['{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens]) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class f: def __repr__(self): @@ -2013,8 +1848,7 @@ def __repr__(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testFunctionCallArguments(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def f(): if True: pytree_utils.InsertNodesBefore(_CreateCommentsFromPrefix( @@ -2024,8 +1858,7 @@ def f(): comment_prefix, comment_lineno, comment_column, standalone=True)) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def f(): if True: pytree_utils.InsertNodesBefore( @@ -2040,21 +1873,18 @@ def f(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBinaryOperators(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ a = b ** 37 c = (20 ** -3) / (_GRID_ROWS ** (code_length - 10)) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ a = b**37 c = (20**-3) / (_GRID_ROWS**(code_length - 10)) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def f(): if True: if (self.stack[-1].split_before_closing_bracket and @@ -2067,8 +1897,7 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testContiguousList(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ [retval1, retval2] = a_very_long_function(argument_1, argument2, argument_3, argument_4) """) # noqa @@ -2076,8 +1905,7 @@ def testContiguousList(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testArgsAndKwargsFormatting(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ a(a=aaaaaaaaaaaaaaaaaaaaa, b=aaaaaaaaaaaaaaaaaaaaaaaa, c=aaaaaaaaaaaaaaaaaa, @@ -2087,8 +1915,7 @@ def testArgsAndKwargsFormatting(self): llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def foo(): return [ Bar(xxx='some string', @@ -2100,8 +1927,7 @@ def foo(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentColumnLimitOverflow(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def f(): if True: TaskManager.get_tags = MagicMock( @@ -2114,8 +1940,7 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testMultilineLambdas(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class SomeClass(object): do_something = True @@ -2126,8 +1951,7 @@ def succeeded(self, dddddddddddddd): d.addCallback(lambda _: self.aaaaaa.bbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccccccc(dddddddddddddd)) return d """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class SomeClass(object): do_something = True @@ -2145,14 +1969,13 @@ def succeeded(self, dddddddddddddd): style.CreateStyleFromConfig( '{based_on_style: yapf, allow_multiline_lambdas: true}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testMultilineDictionaryKeys(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ MAP_WITH_LONG_KEYS = { ('lorem ipsum', 'dolor sit amet'): 1, @@ -2162,8 +1985,7 @@ def testMultilineDictionaryKeys(self): 3 } """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ MAP_WITH_LONG_KEYS = { ('lorem ipsum', 'dolor sit amet'): 1, @@ -2177,18 +1999,16 @@ def testMultilineDictionaryKeys(self): try: style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: yapf, ' - 'allow_multiline_dictionary_keys: true}')) + style.CreateStyleFromConfig('{based_on_style: yapf, ' + 'allow_multiline_dictionary_keys: true}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testStableDictionaryFormatting(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class A(object): def method(self): @@ -2205,16 +2025,15 @@ def method(self): try: style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: pep8, indent_width: 2, ' - 'continuation_indent_width: 4, ' - 'indent_dictionary_value: True}')) + style.CreateStyleFromConfig('{based_on_style: pep8, indent_width: 2, ' + 'continuation_indent_width: 4, ' + 'indent_dictionary_value: True}')) - llines = yapf_test_helper.ParseAndUnwrap(code) + llines = yapf_test_helper.ParseAndUnwrap(code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, reformatted_code) - llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, reformatted_code) finally: @@ -2223,14 +2042,12 @@ def method(self): def testStableInlinedDictionaryFormatting(self): try: style.SetGlobalStyle(style.CreatePEP8Style()) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def _(): url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( value, urllib.urlencode({'action': 'update', 'parameter': value})) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def _(): url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( value, urllib.urlencode({ @@ -2239,25 +2056,23 @@ def _(): })) """) - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) - llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testDontSplitKeywordValueArguments(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def mark_game_scored(gid): _connect.execute(_games.update().where(_games.c.gid == gid).values( scored=True)) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def mark_game_scored(gid): _connect.execute( _games.update().where(_games.c.gid == gid).values(scored=True)) @@ -2266,8 +2081,7 @@ def mark_game_scored(gid): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDontAddBlankLineAfterMultilineString(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ query = '''SELECT id FROM table WHERE day in {}''' @@ -2277,8 +2091,7 @@ def testDontAddBlankLineAfterMultilineString(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFormattingListComprehensions(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def a(): if True: if True: @@ -2292,8 +2105,7 @@ def a(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSplittingWhenBinPacking(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ a_very_long_function_name( long_argument_name_1=1, long_argument_name_2=2, @@ -2315,25 +2127,23 @@ def testNoSplittingWhenBinPacking(self): 'dedent_closing_brackets: True, ' 'split_before_named_assigns: False}')) - llines = yapf_test_helper.ParseAndUnwrap(code) + llines = yapf_test_helper.ParseAndUnwrap(code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, reformatted_code) - llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, reformatted_code) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testNotSplittingAfterSubscript(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if not aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.b(c == d[ 'eeeeee']).ffffff(): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if not aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.b( c == d['eeeeee']).ffffff(): pass @@ -2342,8 +2152,7 @@ def testNotSplittingAfterSubscript(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingOneArgumentList(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def _(): if True: if True: @@ -2352,8 +2161,7 @@ def _(): if True: boxes[id_] = np.concatenate((points.min(axis=0), qoints.max(axis=0))) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def _(): if True: if True: @@ -2367,8 +2175,7 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingBeforeFirstElementListArgument(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class _(): @classmethod def _pack_results_for_constraint_or(cls, combination, constraints): @@ -2381,8 +2188,7 @@ def _pack_results_for_constraint_or(cls, combination, constraints): ), constraints, InvestigationResult.OR ) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class _(): @classmethod @@ -2398,8 +2204,7 @@ def _pack_results_for_constraint_or(cls, combination, constraints): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingArgumentsTerminatedByComma(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3) function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3,) @@ -2410,8 +2215,7 @@ def testSplittingArgumentsTerminatedByComma(self): r =f0 (1, 2,3,) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3) function_name( @@ -2446,19 +2250,18 @@ def testSplittingArgumentsTerminatedByComma(self): '{based_on_style: yapf, ' 'split_arguments_when_comma_terminated: True}')) - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) - llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testImportAsList(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ from toto import titi, tata, tutu # noqa from toto import titi, tata, tutu from toto import (titi, tata, tutu) @@ -2467,8 +2270,7 @@ def testImportAsList(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDictionaryValuesOnOwnLines(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ a = { 'aaaaaaaaaaaaaaaaaaaaaaaa': Check('ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ', '=', True), @@ -2492,8 +2294,7 @@ def testDictionaryValuesOnOwnLines(self): Check('QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ', '=', False), } """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ a = { 'aaaaaaaaaaaaaaaaaaaaaaaa': Check('ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ', '=', True), @@ -2521,31 +2322,27 @@ def testDictionaryValuesOnOwnLines(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDictionaryOnOwnLine(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ doc = test_utils.CreateTestDocumentViaController( content={ 'a': 'b' }, branch_key=branch.key, collection_key=collection.key) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ doc = test_utils.CreateTestDocumentViaController( content={'a': 'b'}, branch_key=branch.key, collection_key=collection.key) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ doc = test_utils.CreateTestDocumentViaController( content={ 'a': 'b' }, branch_key=branch.key, collection_key=collection.key, collection_key2=collection.key2) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ doc = test_utils.CreateTestDocumentViaController( content={'a': 'b'}, branch_key=branch.key, @@ -2556,8 +2353,7 @@ def testDictionaryOnOwnLine(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNestedListsInDictionary(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ _A = { 'cccccccccc': ('^^1',), 'rrrrrrrrrrrrrrrrrrrrrrrrr': ('^7913', # AAAAAAAAAAAAAA. @@ -2586,8 +2382,7 @@ def testNestedListsInDictionary(self): ), } """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ _A = { 'cccccccccc': ('^^1',), 'rrrrrrrrrrrrrrrrrrrrrrrrr': ( @@ -2625,8 +2420,7 @@ def testNestedListsInDictionary(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNestedDictionary(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class _(): def _(): breadcrumbs = [{'name': 'Admin', @@ -2636,8 +2430,7 @@ def _(): 'url': url_for(".home")}, {'title': title}] """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class _(): def _(): breadcrumbs = [ @@ -2655,8 +2448,7 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDictionaryElementsOnOneLine(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class _(): @mock.patch.dict( @@ -2676,12 +2468,10 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNotInParams(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ list("a long line to break the line. a long line to break the brk a long lin", not True) """) # noqa - expected_code = textwrap.dedent( - """\ + expected_code = textwrap.dedent("""\ list("a long line to break the line. a long line to break the brk a long lin", not True) """) # noqa @@ -2689,16 +2479,14 @@ def testNotInParams(self): self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testNamedAssignNotAtEndOfLine(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def _(): if True: with py3compat.open_with_encoding(filename, mode='w', encoding=encoding) as fd: pass """) - expected_code = textwrap.dedent( - """\ + expected_code = textwrap.dedent("""\ def _(): if True: with py3compat.open_with_encoding( @@ -2709,8 +2497,7 @@ def _(): self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testBlankLineBeforeClassDocstring(self): - unformatted_code = textwrap.dedent( - '''\ + unformatted_code = textwrap.dedent('''\ class A: """Does something. @@ -2721,8 +2508,7 @@ class A: def __init__(self): pass ''') - expected_code = textwrap.dedent( - '''\ + expected_code = textwrap.dedent('''\ class A: """Does something. @@ -2735,8 +2521,7 @@ def __init__(self): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - '''\ + unformatted_code = textwrap.dedent('''\ class A: """Does something. @@ -2747,8 +2532,7 @@ class A: def __init__(self): pass ''') - expected_formatted_code = textwrap.dedent( - '''\ + expected_formatted_code = textwrap.dedent('''\ class A: """Does something. @@ -2767,14 +2551,13 @@ def __init__(self): 'blank_line_before_class_docstring: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testBlankLineBeforeModuleDocstring(self): - unformatted_code = textwrap.dedent( - '''\ + unformatted_code = textwrap.dedent('''\ #!/usr/bin/env python # -*- coding: utf-8 name> -*- @@ -2784,8 +2567,7 @@ def testBlankLineBeforeModuleDocstring(self): def foobar(): pass ''') - expected_code = textwrap.dedent( - '''\ + expected_code = textwrap.dedent('''\ #!/usr/bin/env python # -*- coding: utf-8 name> -*- """Some module docstring.""" @@ -2797,8 +2579,7 @@ def foobar(): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - '''\ + unformatted_code = textwrap.dedent('''\ #!/usr/bin/env python # -*- coding: utf-8 name> -*- """Some module docstring.""" @@ -2807,8 +2588,7 @@ def foobar(): def foobar(): pass ''') - expected_formatted_code = textwrap.dedent( - '''\ + expected_formatted_code = textwrap.dedent('''\ #!/usr/bin/env python # -*- coding: utf-8 name> -*- @@ -2826,20 +2606,18 @@ def foobar(): 'blank_line_before_module_docstring: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testTupleCohesion(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def f(): this_is_a_very_long_function_name(an_extremely_long_variable_name, ( 'a string that may be too long %s' % 'M15')) """) - expected_code = textwrap.dedent( - """\ + expected_code = textwrap.dedent("""\ def f(): this_is_a_very_long_function_name( an_extremely_long_variable_name, @@ -2849,15 +2627,14 @@ def f(): self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testSubscriptExpression(self): - code = textwrap.dedent("""\ + code = textwrap.dedent("""\ foo = d[not a] """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testListWithFunctionCalls(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo(): return [ Bar( @@ -2869,8 +2646,7 @@ def foo(): zzz='a third long string') ] """) - expected_code = textwrap.dedent( - """\ + expected_code = textwrap.dedent("""\ def foo(): return [ Bar(xxx='some string', @@ -2885,13 +2661,11 @@ def foo(): self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testEllipses(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ X=... Y = X if ... else X """) - expected_code = textwrap.dedent( - """\ + expected_code = textwrap.dedent("""\ X = ... Y = X if ... else X """) @@ -2905,7 +2679,7 @@ def testPseudoParens(self): {'nested_key': 1, }, } """ - expected_code = """\ + expected_code = """\ my_dict = { 'key': # Some comment about the key { @@ -2913,18 +2687,16 @@ def testPseudoParens(self): }, } """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testSplittingBeforeFirstArgumentOnFunctionCall(self): """Tests split_before_first_argument on a function call.""" - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ a_very_long_function_name("long string with formatting {0:s}".format( "mystring")) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ a_very_long_function_name( "long string with formatting {0:s}".format("mystring")) """) @@ -2935,21 +2707,19 @@ def testSplittingBeforeFirstArgumentOnFunctionCall(self): '{based_on_style: yapf, split_before_first_argument: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testSplittingBeforeFirstArgumentOnFunctionDefinition(self): """Tests split_before_first_argument on a function definition.""" - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def _GetNumberOfSecondsFromElements(year, month, day, hours, minutes, seconds, microseconds): return """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def _GetNumberOfSecondsFromElements( year, month, day, hours, minutes, seconds, microseconds): return @@ -2961,23 +2731,21 @@ def _GetNumberOfSecondsFromElements( '{based_on_style: yapf, split_before_first_argument: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testSplittingBeforeFirstArgumentOnCompoundStatement(self): """Tests split_before_first_argument on a compound statement.""" - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if (long_argument_name_1 == 1 or long_argument_name_2 == 2 or long_argument_name_3 == 3 or long_argument_name_4 == 4): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if (long_argument_name_1 == 1 or long_argument_name_2 == 2 or long_argument_name_3 == 3 or long_argument_name_4 == 4): pass @@ -2989,15 +2757,14 @@ def testSplittingBeforeFirstArgumentOnCompoundStatement(self): '{based_on_style: yapf, split_before_first_argument: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testCoalesceBracketsOnDict(self): """Tests coalesce_brackets on a dictionary.""" - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ date_time_values = ( { u'year': year, @@ -3009,8 +2776,7 @@ def testCoalesceBracketsOnDict(self): } ) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ date_time_values = ({ u'year': year, u'month': month, @@ -3027,14 +2793,13 @@ def testCoalesceBracketsOnDict(self): '{based_on_style: yapf, coalesce_brackets: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testSplitAfterComment(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ if __name__ == "__main__": with another_resource: account = { @@ -3059,8 +2824,7 @@ def testAsyncAsNonKeyword(self): style.SetGlobalStyle(style.CreatePEP8Style()) # In Python 2, async may be used as a non-keyword identifier. - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ from util import async @@ -3082,9 +2846,8 @@ def testDisableEndingCommaHeuristic(self): try: style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: yapf,' - ' disable_ending_comma_heuristic: True}')) + style.CreateStyleFromConfig('{based_on_style: yapf,' + ' disable_ending_comma_heuristic: True}')) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -3092,8 +2855,7 @@ def testDisableEndingCommaHeuristic(self): style.SetGlobalStyle(style.CreateYapfStyle()) def testDedentClosingBracketsWithTypeAnnotationExceedingLineLength(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: pass @@ -3101,8 +2863,7 @@ def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: pass """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def function( first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None ) -> None: @@ -3117,19 +2878,17 @@ def function( try: style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: yapf,' - ' dedent_closing_brackets: True}')) + style.CreateStyleFromConfig('{based_on_style: yapf,' + ' dedent_closing_brackets: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testIndentClosingBracketsWithTypeAnnotationExceedingLineLength(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: pass @@ -3137,8 +2896,7 @@ def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: pass """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def function( first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None ) -> None: @@ -3153,19 +2911,17 @@ def function( try: style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: yapf,' - ' indent_closing_brackets: True}')) + style.CreateStyleFromConfig('{based_on_style: yapf,' + ' indent_closing_brackets: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testIndentClosingBracketsInFunctionCall(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None, third_and_final_argument=True): pass @@ -3173,8 +2929,7 @@ def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None, third_a def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_and_last_argument=None): pass """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def function( first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None, @@ -3191,19 +2946,17 @@ def function( try: style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: yapf,' - ' indent_closing_brackets: True}')) + style.CreateStyleFromConfig('{based_on_style: yapf,' + ' indent_closing_brackets: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testIndentClosingBracketsInTuple(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def function(): some_var = ('a long element', 'another long element', 'short element', 'really really long element') return True @@ -3212,8 +2965,7 @@ def function(): some_var = ('a couple', 'small', 'elemens') return False """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def function(): some_var = ( 'a long element', 'another long element', 'short element', @@ -3229,19 +2981,17 @@ def function(): try: style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: yapf,' - ' indent_closing_brackets: True}')) + style.CreateStyleFromConfig('{based_on_style: yapf,' + ' indent_closing_brackets: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testIndentClosingBracketsInList(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def function(): some_var = ['a long element', 'another long element', 'short element', 'really really long element'] return True @@ -3250,8 +3000,7 @@ def function(): some_var = ['a couple', 'small', 'elemens'] return False """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def function(): some_var = [ 'a long element', 'another long element', 'short element', @@ -3267,19 +3016,17 @@ def function(): try: style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: yapf,' - ' indent_closing_brackets: True}')) + style.CreateStyleFromConfig('{based_on_style: yapf,' + ' indent_closing_brackets: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testIndentClosingBracketsInDict(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def function(): some_var = {1: ('a long element', 'and another really really long element that is really really amazingly long'), 2: 'another long element', 3: 'short element', 4: 'really really long element'} return True @@ -3288,8 +3035,7 @@ def function(): some_var = {1: 'a couple', 2: 'small', 3: 'elemens'} return False """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def function(): some_var = { 1: @@ -3311,19 +3057,17 @@ def function(): try: style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: yapf,' - ' indent_closing_brackets: True}')) + style.CreateStyleFromConfig('{based_on_style: yapf,' + ' indent_closing_brackets: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testMultipleDictionariesInList(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class A: def b(): d = { @@ -3349,8 +3093,7 @@ def b(): ] } """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class A: def b(): @@ -3382,10 +3125,9 @@ def testForceMultilineDict_True(self): style.CreateStyleFromConfig('{force_multiline_dict: true}')) unformatted_code = textwrap.dedent( "responseDict = {'childDict': {'spam': 'eggs'}}\n") - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - actual = reformatter.Reformat(llines) - expected = textwrap.dedent( - """\ + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + actual = reformatter.Reformat(llines) + expected = textwrap.dedent("""\ responseDict = { 'childDict': { 'spam': 'eggs' @@ -3400,26 +3142,23 @@ def testForceMultilineDict_False(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig('{force_multiline_dict: false}')) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ responseDict = {'childDict': {'spam': 'eggs'}} """) expected_formatted_code = unformatted_code - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @unittest.skipUnless(py3compat.PY38, 'Requires Python 3.8') def testWalrus(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if (x := len([1]*1000)>100): print(f'{x} is pretty big' ) """) - expected = textwrap.dedent( - """\ + expected = textwrap.dedent("""\ if (x := len([1] * 1000) > 100): print(f'{x} is pretty big') """) @@ -3431,23 +3170,21 @@ def testAlignAssignBlankLineInbetween(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig('{align_assignment: true}')) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ val_first = 1 val_second += 2 val_third = 3 """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ val_first = 1 val_second += 2 val_third = 3 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -3457,23 +3194,21 @@ def testAlignAssignCommentLineInbetween(self): style.CreateStyleFromConfig( '{align_assignment: true,' 'new_alignment_after_commentline = true}')) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ val_first = 1 val_second += 2 # comment val_third = 3 """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ val_first = 1 val_second += 2 # comment val_third = 3 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -3481,8 +3216,7 @@ def testAlignAssignDefLineInbetween(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig('{align_assignment: true}')) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ val_first = 1 val_second += 2 def fun(): @@ -3490,8 +3224,7 @@ def fun(): abc = '' val_third = 3 """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ val_first = 1 val_second += 2 @@ -3504,8 +3237,8 @@ def fun(): val_third = 3 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -3513,8 +3246,7 @@ def testAlignAssignObjectWithNewLineInbetween(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig('{align_assignment: true}')) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ val_first = 1 val_second += 2 object = { @@ -3524,8 +3256,7 @@ def testAlignAssignObjectWithNewLineInbetween(self): } val_third = 3 """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ val_first = 1 val_second += 2 object = { @@ -3536,8 +3267,8 @@ def testAlignAssignObjectWithNewLineInbetween(self): val_third = 3 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) @@ -3545,13 +3276,13 @@ def testAlignAssignWithOnlyOneAssignmentLine(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig('{align_assignment: true}')) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ val_first = 1 """) expected_formatted_code = unformatted_code - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index d8beb04cb..a4089ad03 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -29,7 +29,7 @@ def setUpClass(cls): style.SetGlobalStyle(style.CreateYapfStyle()) def testB137580392(self): - code = """\ + code = """\ def _create_testing_simulator_and_sink( ) -> Tuple[_batch_simulator:_batch_simulator.BatchSimulator, _batch_simulator.SimulationSink]: @@ -39,7 +39,7 @@ def _create_testing_simulator_and_sink( self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB73279849(self): - unformatted_code = """\ + unformatted_code = """\ class A: def _(a): return 'hello' [ a ] @@ -49,11 +49,11 @@ class A: def _(a): return 'hello'[a] """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB122455211(self): - unformatted_code = """\ + unformatted_code = """\ _zzzzzzzzzzzzzzzzzzzz = Union[sssssssssssssssssssss.pppppppppppppppp, sssssssssssssssssssss.pppppppppppppppppppppppppppp] """ @@ -62,11 +62,11 @@ def testB122455211(self): sssssssssssssssssssss.pppppppppppppppp, sssssssssssssssssssss.pppppppppppppppppppppppppppp] """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB119300344(self): - code = """\ + code = """\ def _GenerateStatsEntries( process_id: Text, timestamp: Optional[rdfvalue.RDFDatetime] = None @@ -77,7 +77,7 @@ def _GenerateStatsEntries( self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB132886019(self): - code = """\ + code = """\ X = { 'some_dict_key': frozenset([ @@ -90,7 +90,7 @@ def testB132886019(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB26521719(self): - code = """\ + code = """\ class _(): def _(self): @@ -101,7 +101,7 @@ def _(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB122541552(self): - code = """\ + code = """\ # pylint: disable=g-explicit-bool-comparison,singleton-comparison _QUERY = account.Account.query(account.Account.enabled == True) # pylint: enable=g-explicit-bool-comparison,singleton-comparison @@ -114,7 +114,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB124415889(self): - code = """\ + code = """\ class _(): def run_queue_scanners(): @@ -137,7 +137,7 @@ def modules_to_install(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB73166511(self): - code = """\ + code = """\ def _(): if min_std is not None: groundtruth_age_variances = tf.maximum(groundtruth_age_variances, @@ -147,7 +147,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB118624921(self): - code = """\ + code = """\ def _(): function_call( alert_name='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', @@ -175,7 +175,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB120047670(self): - unformatted_code = """\ + unformatted_code = """\ X = { 'NO_PING_COMPONENTS': [ 79775, # Releases / FOO API @@ -195,7 +195,7 @@ def testB120047670(self): 'PING_BLOCKED_BUGS': False, } """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB120245013(self): @@ -213,11 +213,11 @@ def testNoAlertForShortPeriod(self, rutabaga): self._fillInOtherFields(streamz_path, {streamz_field_of_interest: True} )] = series.Counter('1s', '+ 500x10000') """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB117841880(self): - code = """\ + code = """\ def xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( aaaaaaaaaaaaaaaaaaa: AnyStr, bbbbbbbbbbbb: Optional[Sequence[AnyStr]] = None, @@ -244,11 +244,11 @@ def testB111764402(self): for external_id in external_ids })) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB116825060(self): - code = """\ + code = """\ result_df = pd.DataFrame({LEARNED_CTR_COLUMN: learned_ctr}, index=df_metrics.index) """ @@ -256,7 +256,7 @@ def testB116825060(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB112711217(self): - code = """\ + code = """\ def _(): stats['moderated'] = ~stats.moderation_reason.isin( approved_moderation_reasons) @@ -265,7 +265,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB112867548(self): - unformatted_code = """\ + unformatted_code = """\ def _(): return flask.make_response( 'Records: {}, Problems: {}, More: {}'.format( @@ -283,7 +283,7 @@ def _(): httplib.ACCEPTED if process_result.has_more else httplib.OK, {'content-type': _TEXT_CONTEXT_TYPE}) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB112651423(self): @@ -302,11 +302,11 @@ def potato(feeditems, browse_use_case=None): 'FEEDS_LOAD_PLAYLIST_VIDEOS_FOR_ALL_ITEMS'] and item.video: continue """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB80484938(self): - code = """\ + code = """\ for sssssss, aaaaaaaaaa in [ ('ssssssssssssssssssss', 'sssssssssssssssssssssssss'), ('nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn', @@ -349,7 +349,7 @@ def testB80484938(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB120771563(self): - code = """\ + code = """\ class A: def b(): @@ -376,7 +376,7 @@ def b(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB79462249(self): - code = """\ + code = """\ foo.bar(baz, [ quux(thud=42), norf, @@ -410,7 +410,7 @@ def _(): eeeeeeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffffffffffffffffffffff .ggggggggggggggggggggggggggggggggg.hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh()) """ # noqa - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB77923341(self): @@ -424,7 +424,7 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB77329955(self): - code = """\ + code = """\ class _(): @parameterized.named_parameters( @@ -442,7 +442,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB65197969(self): - unformatted_code = """\ + unformatted_code = """\ class _(): def _(): @@ -457,11 +457,11 @@ def _(): seconds=max(float(time_scale), small_interval) * 1.41**min(num_attempts, 9)) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB65546221(self): - unformatted_code = """\ + unformatted_code = """\ SUPPORTED_PLATFORMS = ( "centos-6", "centos-7", @@ -484,7 +484,7 @@ def testB65546221(self): "debian-9-stretch", ) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30500455(self): @@ -501,11 +501,11 @@ def testB30500455(self): [(name, 'function#' + name) for name in INITIAL_FUNCTIONS] + [(name, 'const#' + name) for name in INITIAL_CONSTS]) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB38343525(self): - code = """\ + code = """\ # This does foo. @arg.String('some_path_to_a_file', required=True) # This does bar. @@ -534,7 +534,7 @@ def testB37099651(self): # pylint: enable=g-long-lambda ) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB33228502(self): @@ -572,11 +572,11 @@ def _(): | m.Join('successes', 'total') | m.Point(m.VAL['successes'] / m.VAL['total'])))) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30394228(self): - code = """\ + code = """\ class _(): def _(self): @@ -589,7 +589,7 @@ def _(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB65246454(self): - unformatted_code = """\ + unformatted_code = """\ class _(): def _(self): @@ -605,11 +605,11 @@ def _(self): self.assertEqual({i.id for i in successful_instances}, {i.id for i in self._statuses.successful_instances}) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB67935450(self): - unformatted_code = """\ + unformatted_code = """\ def _(): return ( (Gauge( @@ -646,11 +646,11 @@ def _(): m.Cond(m.VAL['start'] != 0, m.VAL['start'], m.TimestampMicros() / 1000000L))) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB66011084(self): - unformatted_code = """\ + unformatted_code = """\ X = { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": # Comment 1. ([] if True else [ # Comment 2. @@ -678,7 +678,7 @@ def testB66011084(self): ]), } """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB67455376(self): @@ -689,11 +689,11 @@ def testB67455376(self): sponge_ids.extend(invocation.id() for invocation in self._client.GetInvocationsByLabels(labels)) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB35210351(self): - unformatted_code = """\ + unformatted_code = """\ def _(): config.AnotherRuleThing( 'the_title_to_the_thing_here', @@ -719,11 +719,11 @@ def _(): GetTheAlertToIt('the_title_to_the_thing_here'), GetNotificationTemplate('your_email_here'))) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB34774905(self): - unformatted_code = """\ + unformatted_code = """\ x=[VarExprType(ir_name=IrName( value='x', expr_type=UnresolvedAttrExprType( atom=UnknownExprType(), attr_name=IrName( value='x', expr_type=UnknownExprType(), usage='UNKNOWN', fqn=None, @@ -748,11 +748,11 @@ def testB34774905(self): astn=None)) ] """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB65176185(self): - code = """\ + code = """\ xx = zip(*[(a, b) for (a, b, c) in yy]) """ llines = yapf_test_helper.ParseAndUnwrap(code) @@ -776,11 +776,11 @@ def _(): | o.Window(m.Align('5m')) | p.GroupBy(['borg_user', 'borg_job', 'borg_cell'], q.Mean())) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB32167774(self): - unformatted_code = """\ + unformatted_code = """\ X = ( 'is_official', 'is_cover', @@ -803,7 +803,7 @@ def testB32167774(self): 'is_compilation', ) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB66912275(self): @@ -827,11 +827,11 @@ def _(): 'fingerprint': base64.urlsafe_b64encode('invalid_fingerprint') }).execute() """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB67312284(self): - code = """\ + code = """\ def _(): self.assertEqual( [u'to be published 2', u'to be published 1', u'to be published 0'], @@ -850,12 +850,11 @@ def testB65241516(self): TrainTraceDir(unit_key, "*", "*"), embedding_model.CHECKPOINT_FILENAME + "-*")) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB37460004(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ assert all(s not in (_SENTINEL, None) for s in nested_schemas ), 'Nested schemas should never contain None/_SENTINEL' """) @@ -863,7 +862,7 @@ def testB37460004(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB36806207(self): - code = """\ + code = """\ def _(): linearity_data = [[row] for row in [ "%.1f mm" % (np.mean(linearity_values["pos_error"]) * 1000.0), @@ -882,8 +881,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB36215507(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class X(): def _(): @@ -897,8 +895,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB35212469(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def _(): X = { 'retain': { @@ -907,8 +904,7 @@ def _(): } } """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def _(): X = { 'retain': { @@ -921,14 +917,12 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB31063453(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def _(): while ((not mpede_proc) or ((time_time() - last_modified) < FLAGS_boot_idle_timeout)): pass """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def _(): while ((not mpede_proc) or ((time_time() - last_modified) < FLAGS_boot_idle_timeout)): @@ -938,8 +932,7 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB35021894(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def _(): labelacl = Env(qa={ 'read': 'name/some-type-of-very-long-name-for-reading-perms', @@ -950,8 +943,7 @@ def _(): 'modify': 'name/some-other-type-of-very-long-name-for-modifying' }) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def _(): labelacl = Env( qa={ @@ -967,12 +959,10 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB34682902(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ logging.info("Mean angular velocity norm: %.3f", np.linalg.norm(np.mean(ang_vel_arr, axis=0))) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ logging.info("Mean angular velocity norm: %.3f", np.linalg.norm(np.mean(ang_vel_arr, axis=0))) """) @@ -980,15 +970,13 @@ def testB34682902(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB33842726(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class _(): def _(): hints.append(('hg tag -f -l -r %s %s # %s' % (short(ctx.node( )), candidatetag, firstline))[:78]) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class _(): def _(): hints.append(('hg tag -f -l -r %s %s # %s' % @@ -998,8 +986,7 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB32931780(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ environments = { 'prod': { # this is a comment before the first entry. @@ -1030,8 +1017,7 @@ def testB32931780(self): } } """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ environments = { 'prod': { # this is a comment before the first entry. @@ -1062,8 +1048,7 @@ def testB32931780(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB33047408(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def _(): for sort in (sorts or []): request['sorts'].append({ @@ -1077,8 +1062,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB32714745(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class _(): def _BlankDefinition(): @@ -1108,16 +1092,14 @@ def _BlankDefinition(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB32737279(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ here_is_a_dict = { 'key': # Comment. 'value' } """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ here_is_a_dict = { 'key': # Comment. 'value' @@ -1127,8 +1109,7 @@ def testB32737279(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB32570937(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def _(): if (job_message.ball not in ('*', ball) or job_message.call not in ('*', call) or @@ -1139,8 +1120,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB31937033(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class _(): def __init__(self, metric, fields_cb=None): @@ -1150,7 +1130,7 @@ def __init__(self, metric, fields_cb=None): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB31911533(self): - code = """\ + code = """\ class _(): @parameterized.NamedParameters( @@ -1166,8 +1146,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB31847238(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class _(): def aaaaa(self, bbbbb, cccccccccccccc=None): # TODO(who): pylint: disable=unused-argument @@ -1176,8 +1155,7 @@ def aaaaa(self, bbbbb, cccccccccccccc=None): # TODO(who): pylint: disable=unuse def xxxxx(self, yyyyy, zzzzzzzzzzzzzz=None): # A normal comment that runs over the column limit. return 1 """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class _(): def aaaaa(self, bbbbb, cccccccccccccc=None): # TODO(who): pylint: disable=unused-argument @@ -1193,13 +1171,11 @@ def xxxxx( self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30760569(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ {'1234567890123456789012345678901234567890123456789012345678901234567890': '1234567890123456789012345678901234567890'} """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ { '1234567890123456789012345678901234567890123456789012345678901234567890': '1234567890123456789012345678901234567890' @@ -1209,15 +1185,13 @@ def testB30760569(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB26034238(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class Thing: def Function(self): thing.Scrape('/aaaaaaaaa/bbbbbbbbbb/ccccc/dddd/eeeeeeeeeeeeee/ffffffffffffff').AndReturn(42) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class Thing: def Function(self): @@ -1229,8 +1203,7 @@ def Function(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30536435(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def main(unused_argv): if True: if True: @@ -1239,8 +1212,7 @@ def main(unused_argv): ccccccccc.within, imports.ddddddddddddddddddd(name_item.ffffffffffffffff))) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def main(unused_argv): if True: if True: @@ -1252,14 +1224,12 @@ def main(unused_argv): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30442148(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def lulz(): return (some_long_module_name.SomeLongClassName. some_long_attribute_name.some_long_method_name()) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def lulz(): return (some_long_module_name.SomeLongClassName.some_long_attribute_name .some_long_method_name()) @@ -1268,8 +1238,7 @@ def lulz(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB26868213(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def _(): xxxxxxxxxxxxxxxxxxx = { 'ssssss': {'ddddd': 'qqqqq', @@ -1284,8 +1253,7 @@ def _(): } } """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def _(): xxxxxxxxxxxxxxxxxxx = { 'ssssss': { @@ -1306,8 +1274,7 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30173198(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class _(): def _(): @@ -1318,8 +1285,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB29908765(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class _(): def __repr__(self): @@ -1330,8 +1296,7 @@ def __repr__(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB30087362(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def _(): for s in sorted(env['foo']): bar() @@ -1344,8 +1309,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB30087363(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ if False: bar() # This is a comment @@ -1357,14 +1321,12 @@ def testB30087363(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB29093579(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def _(): _xxxxxxxxxxxxxxx(aaaaaaaa, bbbbbbbbbbbbbb.cccccccccc[ dddddddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffff]) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def _(): _xxxxxxxxxxxxxxx( aaaaaaaa, @@ -1375,8 +1337,7 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB26382315(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ @hello_world # This is a first comment @@ -1388,8 +1349,7 @@ def foo(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB27616132(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if True: query.fetch_page.assert_has_calls([ mock.call(100, @@ -1400,8 +1360,7 @@ def testB27616132(self): start_cursor=cursor_2), ]) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if True: query.fetch_page.assert_has_calls([ mock.call(100, start_cursor=None), @@ -1413,8 +1372,7 @@ def testB27616132(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB27590179(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if True: if True: self.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = ( @@ -1424,8 +1382,7 @@ def testB27590179(self): self.bbb.cccccccccc(ddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee) }) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if True: if True: self.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = ({ @@ -1439,13 +1396,11 @@ def testB27590179(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB27266946(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def _(): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = (self.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccccccccccc) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def _(): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = ( self.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb @@ -1455,8 +1410,7 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB25505359(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ _EXAMPLE = { 'aaaaaaaaaaaaaa': [{ 'bbbb': 'cccccccccccccccccccccc', @@ -1471,8 +1425,7 @@ def testB25505359(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB25324261(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ aaaaaaaaa = set(bbbb.cccc for ddd in eeeeee.fffffffffff.gggggggggggggggg for cccc in ddd.specification) @@ -1481,8 +1434,7 @@ def testB25324261(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB25136704(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class f: def test(self): @@ -1494,8 +1446,7 @@ def test(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB25165602(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def f(): ids = {u: i for u, i in zip(self.aaaaa, xrange(42, 42 + len(self.aaaaaa)))} """) # noqa @@ -1503,8 +1454,7 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB25157123(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def ListArgs(): FairlyLongMethodName([relatively_long_identifier_for_a_list], another_argument_with_a_long_identifier) @@ -1513,8 +1463,7 @@ def ListArgs(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB25136820(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo(): return collections.OrderedDict({ # Preceding comment. @@ -1522,8 +1471,7 @@ def foo(): '$bbbbbbbbbbbbbbbbbbbbbbbb', }) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo(): return collections.OrderedDict({ # Preceding comment. @@ -1535,15 +1483,13 @@ def foo(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB25131481(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ APPARENT_ACTIONS = ('command_type', { 'materialize': lambda x: some_type_of_function('materialize ' + x.command_def), '#': lambda x: x # do nothing }) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ APPARENT_ACTIONS = ( 'command_type', { @@ -1557,8 +1503,7 @@ def testB25131481(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB23445244(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo(): if True: return xxxxxxxxxxxxxxxx( @@ -1569,8 +1514,7 @@ def foo(): FLAGS.aaaaaaaaaaaaaa + FLAGS.bbbbbbbbbbbbbbbbbbb, }) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo(): if True: return xxxxxxxxxxxxxxxx( @@ -1586,8 +1530,7 @@ def foo(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB20559654(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class A(object): def foo(self): @@ -1595,8 +1538,7 @@ def foo(self): ['AA BBBB CCC DDD EEEEEEEE X YY ZZZZ FFF EEE AAAAAAAA'], aaaaaaaaaaa=True, bbbbbbbb=None) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class A(object): def foo(self): @@ -1609,8 +1551,7 @@ def foo(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB23943842(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class F(): def f(): self.assertDictEqual( @@ -1624,8 +1565,7 @@ def f(): 'lines': 'l8'} }) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class F(): def f(): @@ -1649,14 +1589,12 @@ def f(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB20551180(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo(): if True: return (struct.pack('aaaa', bbbbbbbbbb, ccccccccccccccc, dddddddd) + eeeeeee) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo(): if True: return (struct.pack('aaaa', bbbbbbbbbb, ccccccccccccccc, dddddddd) + @@ -1666,14 +1604,12 @@ def foo(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB23944849(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class A(object): def xxxxxxxxx(self, aaaaaaa, bbbbbbb=ccccccccccc, dddddd=300, eeeeeeeeeeeeee=None, fffffffffffffff=0): pass """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class A(object): def xxxxxxxxx(self, @@ -1688,14 +1624,12 @@ def xxxxxxxxx(self, self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB23935890(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class F(): def functioni(self, aaaaaaa, bbbbbbb, cccccc, dddddddddddddd, eeeeeeeeeeeeeee): pass """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class F(): def functioni(self, aaaaaaa, bbbbbbb, cccccc, dddddddddddddd, @@ -1706,8 +1640,7 @@ def functioni(self, aaaaaaa, bbbbbbb, cccccc, dddddddddddddd, self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB28414371(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def _(): return ((m.fffff( m.rrr('mmmmmmmmmmmmmmmm', 'ssssssssssssssssssssssssss'), ffffffffffffffff) @@ -1732,8 +1665,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20127686(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def f(): if True: return ((m.fffff( @@ -1751,13 +1683,11 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20016122(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ from a_very_long_or_indented_module_name_yada_yada import (long_argument_1, long_argument_2) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ from a_very_long_or_indented_module_name_yada_yada import ( long_argument_1, long_argument_2) """) @@ -1768,13 +1698,12 @@ def testB20016122(self): '{based_on_style: pep8, split_penalty_import_names: 350}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class foo(): def __eq__(self, other): @@ -1794,9 +1723,8 @@ def __eq__(self, other): try: style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: yapf, ' - 'split_before_logical_operator: True}')) + style.CreateStyleFromConfig('{based_on_style: yapf, ' + 'split_before_logical_operator: True}')) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1804,14 +1732,12 @@ def __eq__(self, other): style.SetGlobalStyle(style.CreateYapfStyle()) def testB22527411(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def f(): if True: aaaaaa.bbbbbbbbbbbbbbbbbbbb[-1].cccccccccccccc.ddd().eeeeeeee(ffffffffffffff) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def f(): if True: aaaaaa.bbbbbbbbbbbbbbbbbbbb[-1].cccccccccccccc.ddd().eeeeeeee( @@ -1821,8 +1747,7 @@ def f(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB20849933(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def main(unused_argv): if True: aaaaaaaa = { @@ -1830,8 +1755,7 @@ def main(unused_argv): (eeeeee.FFFFFFFFFFFFFFFFFF), } """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def main(unused_argv): if True: aaaaaaaa = { @@ -1843,8 +1767,7 @@ def main(unused_argv): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB20813997(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def myfunc_1(): myarray = numpy.zeros((2, 2, 2)) print(myarray[:, 1, :]) @@ -1853,8 +1776,7 @@ def myfunc_1(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20605036(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ foo = { 'aaaa': { # A comment for no particular reason. @@ -1868,8 +1790,7 @@ def testB20605036(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20562732(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ foo = [ # Comment about first list item 'First item', @@ -1881,8 +1802,7 @@ def testB20562732(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20128830(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ a = { 'xxxxxxxxxxxxxxxxxxxx': { 'aaaa': @@ -1902,8 +1822,7 @@ def testB20128830(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20073838(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class DummyModel(object): def do_nothing(self, class_1_count): @@ -1920,8 +1839,7 @@ def do_nothing(self, class_1_count): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19626808(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ if True: aaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbb( 'ccccccccccc', ddddddddd='eeeee').fffffffff([ggggggggggggggggggggg]) @@ -1930,8 +1848,7 @@ def testB19626808(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19547210(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ while True: if True: if True: @@ -1945,8 +1862,7 @@ def testB19547210(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19377034(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def f(): if (aaaaaaaaaaaaaaa.start >= aaaaaaaaaaaaaaa.end or bbbbbbbbbbbbbbb.start >= bbbbbbbbbbbbbbb.end): @@ -1956,8 +1872,7 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19372573(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def f(): if a: return 42 while True: @@ -1975,8 +1890,7 @@ def f(): style.SetGlobalStyle(style.CreateYapfStyle()) def testB19353268(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ a = {1, 2, 3}[x] b = {'foo': 42, 'bar': 37}['foo'] """) @@ -1984,8 +1898,7 @@ def testB19353268(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19287512(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class Foo(object): def bar(self): @@ -1995,8 +1908,7 @@ def bar(self): .Mmmmmmmmmmmmmmmmmm(-1, 'permission error'))): self.assertRaises(nnnnnnnnnnnnnnnn.ooooo, ppppp.qqqqqqqqqqqqqqqqq) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class Foo(object): def bar(self): @@ -2011,8 +1923,7 @@ def bar(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB19194420(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ method.Set( 'long argument goes here that causes the line to break', lambda arg2=0.5: arg2) @@ -2021,7 +1932,7 @@ def testB19194420(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19073499(self): - code = """\ + code = """\ instance = ( aaaaaaa.bbbbbbb().ccccccccccccccccc().ddddddddddd({ 'aa': 'context!' @@ -2033,8 +1944,7 @@ def testB19073499(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB18257115(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ if True: if True: self._Test(aaaa, bbbbbbb.cccccccccc, dddddddd, eeeeeeeeeee, @@ -2044,8 +1954,7 @@ def testB18257115(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB18256666(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class Foo(object): def Bar(self): @@ -2063,8 +1972,7 @@ def Bar(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB18256826(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ if True: pass # A multiline comment. @@ -2083,8 +1991,7 @@ def testB18256826(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB18255697(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ AAAAAAAAAAAAAAA = { 'XXXXXXXXXXXXXX': 4242, # Inline comment # Next comment @@ -2095,14 +2002,12 @@ def testB18255697(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB17534869(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if True: self.assertLess(abs(time.time()-aaaa.bbbbbbbbbbb( datetime.datetime.now())), 1) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if True: self.assertLess( abs(time.time() - aaaa.bbbbbbbbbbb(datetime.datetime.now())), 1) @@ -2111,16 +2016,14 @@ def testB17534869(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB17489866(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def f(): if True: if True: return aaaa.bbbbbbbbb(ccccccc=dddddddddddddd({('eeee', \ 'ffffffff'): str(j)})) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def f(): if True: if True: @@ -2131,8 +2034,7 @@ def f(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB17133019(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class aaaaaaaaaaaaaa(object): def bbbbbbbbbb(self): @@ -2143,8 +2045,7 @@ def bbbbbbbbbb(self): ), "rb") as gggggggggggggggggggg: print(gggggggggggggggggggg) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class aaaaaaaaaaaaaa(object): def bbbbbbbbbb(self): @@ -2158,8 +2059,7 @@ def bbbbbbbbbb(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB17011869(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ '''blah......''' class SomeClass(object): @@ -2170,8 +2070,7 @@ class SomeClass(object): 'DDDDDDDD': 0.4811 } """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ '''blah......''' @@ -2187,16 +2086,14 @@ class SomeClass(object): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB16783631(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if True: with aaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccc(ddddddddddddd, eeeeeeeee=self.fffffffffffff )as gggg: pass """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if True: with aaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccc( ddddddddddddd, eeeeeeeee=self.fffffffffffff) as gggg: @@ -2206,14 +2103,12 @@ def testB16783631(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB16572361(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo(self): def bar(my_dict_name): self.my_dict_name['foo-bar-baz-biz-boo-baa-baa'].IncrementBy.assert_called_once_with('foo_bar_baz_boo') """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo(self): def bar(my_dict_name): @@ -2225,15 +2120,13 @@ def bar(my_dict_name): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB15884241(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if 1: if 1: for row in AAAA: self.create(aaaaaaaa="/aaa/bbbb/cccc/dddddd/eeeeeeeeeeeeeeeeeeeeeeeeee/%s" % row [0].replace(".foo", ".bar"), aaaaa=bbb[1], ccccc=bbb[2], dddd=bbb[3], eeeeeeeeeee=[s.strip() for s in bbb[4].split(",")], ffffffff=[s.strip() for s in bbb[5].split(",")], gggggg=bbb[6]) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if 1: if 1: for row in AAAA: @@ -2251,8 +2144,7 @@ def testB15884241(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB15697268(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def main(unused_argv): ARBITRARY_CONSTANT_A = 10 an_array_with_an_exceedingly_long_name = range(ARBITRARY_CONSTANT_A + 1) @@ -2261,8 +2153,7 @@ def main(unused_argv): a_long_name_slicing = an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A] bad_slice = ("I am a crazy, no good, string what's too long, etc." + " no really ")[:ARBITRARY_CONSTANT_A] """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def main(unused_argv): ARBITRARY_CONSTANT_A = 10 an_array_with_an_exceedingly_long_name = range(ARBITRARY_CONSTANT_A + 1) @@ -2292,16 +2183,14 @@ def testB15597568(self): (", and the process timed out." if did_time_out else ".")) % errorcode) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB15542157(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ aaaaaaaaaaaa = bbbb.ccccccccccccccc(dddddd.eeeeeeeeeeeeee, ffffffffffffffffff, gggggg.hhhhhhhhhhhhhhhhh) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaaaa = bbbb.ccccccccccccccc(dddddd.eeeeeeeeeeeeee, ffffffffffffffffff, gggggg.hhhhhhhhhhhhhhhhh) """) # noqa @@ -2309,8 +2198,7 @@ def testB15542157(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB15438132(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if aaaaaaa.bbbbbbbbbb: cccccc.dddddddddd(eeeeeeeeeee=fffffffffffff.gggggggggggggggggg) if hhhhhh.iiiii.jjjjjjjjjjjjj: @@ -2326,8 +2214,7 @@ def testB15438132(self): lllll.mm), nnnnnnnnnn=ooooooo.pppppppppp) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if aaaaaaa.bbbbbbbbbb: cccccc.dddddddddd(eeeeeeeeeee=fffffffffffff.gggggggggggggggggg) if hhhhhh.iiiii.jjjjjjjjjjjjj: @@ -2346,7 +2233,7 @@ def testB15438132(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB14468247(self): - unformatted_code = """\ + unformatted_code = """\ call(a=1, b=2, ) @@ -2357,17 +2244,15 @@ def testB14468247(self): b=2, ) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB14406499(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo1(parameter_1, parameter_2, parameter_3, parameter_4, \ parameter_5, parameter_6): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo1(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6): pass @@ -2376,21 +2261,18 @@ def foo1(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB13900309(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ self.aaaaaaaaaaa( # A comment in the middle of it all. 948.0/3600, self.bbb.ccccccccccccccccccccc(dddddddddddddddd.eeee, True)) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ self.aaaaaaaaaaa( # A comment in the middle of it all. 948.0 / 3600, self.bbb.ccccccccccccccccccccc(dddddddddddddddd.eeee, True)) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ aaaaaaaaaa.bbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccccc( DC_1, (CL - 50, CL), AAAAAAAA, BBBBBBBBBBBBBBBB, 98.0, CCCCCCC).ddddddddd( # Look! A comment is here. @@ -2399,49 +2281,41 @@ def testB13900309(self): llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc().dddddddddddddddddddddddddd(1, 2, 3, 4) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc( ).dddddddddddddddddddddddddd(1, 2, 3, 4) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc(x).dddddddddddddddddddddddddd(1, 2, 3, 4) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc( x).dddddddddddddddddddddddddd(1, 2, 3, 4) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx).dddddddddddddddddddddddddd(1, 2, 3, 4) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa( xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx).dddddddddddddddddddddddddd(1, 2, 3, 4) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa().bbbbbbbbbbbbbbbbbbbbbbbb().ccccccccccccccccccc().\ dddddddddddddddddd().eeeeeeeeeeeeeeeeeeeee().fffffffffffffffff().gggggggggggggggggg() """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa().bbbbbbbbbbbbbbbbbbbbbbbb().ccccccccccccccccccc( ).dddddddddddddddddd().eeeeeeeeeeeeeeeeeeeee().fffffffffffffffff( ).gggggggggggggggggg() @@ -2450,8 +2324,7 @@ def testB13900309(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB67935687(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ Fetch( Raw('monarch.BorgTask', '/union/row_operator_action_delay'), {'borg_user': self.borg_user}) @@ -2459,15 +2332,13 @@ def testB67935687(self): llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ shelf_renderer.expand_text = text.translate_to_unicode( expand_text % { 'creator': creator }) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ shelf_renderer.expand_text = text.translate_to_unicode(expand_text % {'creator': creator}) """) # noqa diff --git a/yapftests/reformatter_facebook_test.py b/yapftests/reformatter_facebook_test.py index 14b07d06b..780b42440 100644 --- a/yapftests/reformatter_facebook_test.py +++ b/yapftests/reformatter_facebook_test.py @@ -29,14 +29,12 @@ def setUpClass(cls): style.SetGlobalStyle(style.CreateFacebookStyle()) def testNoNeedForLineBreaks(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def overly_long_function_name( just_one_arg, **kwargs): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def overly_long_function_name(just_one_arg, **kwargs): pass """) @@ -44,15 +42,13 @@ def overly_long_function_name(just_one_arg, **kwargs): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDedentClosingBracket(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def overly_long_function_name( first_argument_on_the_same_line, second_argument_makes_the_line_too_long): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def overly_long_function_name( first_argument_on_the_same_line, second_argument_makes_the_line_too_long ): @@ -62,14 +58,12 @@ def overly_long_function_name( self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBreakAfterOpeningBracketIfContentsTooBig(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def overly_long_function_name(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def overly_long_function_name( a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, \ v, w, x, y, z @@ -80,8 +74,7 @@ def overly_long_function_name( self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDedentClosingBracketWithComments(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def overly_long_function_name( # comment about the first argument first_argument_with_a_very_long_name_or_so, @@ -89,8 +82,7 @@ def overly_long_function_name( second_argument_makes_the_line_too_long): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def overly_long_function_name( # comment about the first argument first_argument_with_a_very_long_name_or_so, @@ -103,8 +95,7 @@ def overly_long_function_name( self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDedentImportAsNames(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ from module import ( internal_function as function, SOME_CONSTANT_NUMBER1, @@ -116,8 +107,7 @@ def testDedentImportAsNames(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDedentTestListGexp(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ try: pass except ( @@ -132,8 +122,7 @@ def testDedentTestListGexp(self): ) as exception: pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ try: pass except ( @@ -157,15 +146,13 @@ def testDedentTestListGexp(self): def testBrokenIdempotency(self): # TODO(ambv): The following behaviour should be fixed. - pass0_code = textwrap.dedent( - """\ + pass0_code = textwrap.dedent("""\ try: pass except (IOError, OSError, LookupError, RuntimeError, OverflowError) as exception: pass """) # noqa - pass1_code = textwrap.dedent( - """\ + pass1_code = textwrap.dedent("""\ try: pass except ( @@ -176,8 +163,7 @@ def testBrokenIdempotency(self): llines = yapf_test_helper.ParseAndUnwrap(pass0_code) self.assertCodeEqual(pass1_code, reformatter.Reformat(llines)) - pass2_code = textwrap.dedent( - """\ + pass2_code = textwrap.dedent("""\ try: pass except ( @@ -189,8 +175,7 @@ def testBrokenIdempotency(self): self.assertCodeEqual(pass2_code, reformatter.Reformat(llines)) def testIfExprHangingIndent(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if True: if True: if True: @@ -199,8 +184,7 @@ def testIfExprHangingIndent(self): self.foobars.counters['db.marshmellow_skins'] != 1): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if True: if True: if True: @@ -214,13 +198,11 @@ def testIfExprHangingIndent(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSimpleDedenting(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if True: self.assertEqual(result.reason_not_added, "current preflight is still running") """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if True: self.assertEqual( result.reason_not_added, "current preflight is still running" @@ -230,8 +212,7 @@ def testSimpleDedenting(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDedentingWithSubscripts(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class Foo: class Bar: @classmethod @@ -240,8 +221,7 @@ def baz(cls, clues_list, effect, constraints, constraint_manager): return cls.single_constraint_not(clues_lists, effect, constraints[0], constraint_manager) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class Foo: class Bar: @classmethod @@ -255,8 +235,7 @@ def baz(cls, clues_list, effect, constraints, constraint_manager): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDedentingCallsWithInnerLists(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class _(): def _(): cls.effect_clues = { @@ -267,8 +246,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDedentingListComprehension(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class Foo(): def _pack_results_for_constraint_or(): self.param_groups = dict( @@ -306,8 +284,7 @@ def _pack_results_for_constraint_or(): ('localhost', os.path.join(path, 'node_2.log'), super_parser) ] """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class Foo(): def _pack_results_for_constraint_or(): self.param_groups = dict( @@ -347,8 +324,7 @@ def _pack_results_for_constraint_or(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMustSplitDedenting(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class _(): def _(): effect_line = FrontInput( @@ -360,8 +336,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDedentIfConditional(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class _(): def _(): if True: @@ -375,8 +350,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDedentSet(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class _(): def _(): assert set(self.constraint_links.get_links()) == set( @@ -392,8 +366,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDedentingInnerScope(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class Foo(): @classmethod def _pack_results_for_constraint_or(cls, combination, constraints): @@ -402,17 +375,16 @@ def _pack_results_for_constraint_or(cls, combination, constraints): constraints, InvestigationResult.OR ) """) # noqa - llines = yapf_test_helper.ParseAndUnwrap(code) + llines = yapf_test_helper.ParseAndUnwrap(code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, reformatted_code) - llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, reformatted_code) def testCommentWithNewlinesInPrefix(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo(): if 0: return False @@ -425,8 +397,7 @@ def foo(): print(foo()) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo(): if 0: return False @@ -453,7 +424,7 @@ def testIfStmtClosingBracket(self): ): return False """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 19c294d18..67ddadc23 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -30,13 +30,11 @@ def setUpClass(cls): # pylint: disable=g-missing-super-call style.SetGlobalStyle(style.CreatePEP8Style()) def testIndent4(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if a+b: pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if a + b: pass """) @@ -44,8 +42,7 @@ def testIndent4(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSingleLineIfStatements(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ if True: a = 42 elif False: b = 42 else: c = 42 @@ -54,14 +51,12 @@ def testSingleLineIfStatements(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testBlankBetweenClassAndDef(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class Foo: def joe(): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class Foo: def joe(): @@ -71,8 +66,7 @@ def joe(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBlankBetweenDefsInClass(self): - unformatted_code = textwrap.dedent( - '''\ + unformatted_code = textwrap.dedent('''\ class TestClass: def __init__(self): self.running = False @@ -81,8 +75,7 @@ def run(self): def is_running(self): return self.running ''') - expected_formatted_code = textwrap.dedent( - '''\ + expected_formatted_code = textwrap.dedent('''\ class TestClass: def __init__(self): @@ -98,13 +91,11 @@ def is_running(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSingleWhiteBeforeTrailingComment(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if a+b: # comment pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if a + b: # comment pass """) @@ -112,22 +103,19 @@ def testSingleWhiteBeforeTrailingComment(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSpaceBetweenEndingCommandAndClosingBracket(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ a = ( 1, ) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ a = (1, ) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testContinuedNonOutdentedLine(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class eld(d): if str(geom.geom_type).upper( ) != self.geom_type and not self.geom_type == 'GEOMETRY': @@ -137,8 +125,7 @@ class eld(d): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testWrappingPercentExpressions(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def f(): if True: zzzzz = '%s-%s' % (xxxxxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxx.yyy + 1) @@ -146,8 +133,7 @@ def f(): zzzzz = '%s-%s' % (xxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxxxxxx + 1) zzzzz = '%s-%s'.ww(xxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxxxxxx + 1) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def f(): if True: zzzzz = '%s-%s' % (xxxxxxxxxxxxxxxxxxxxxxxxxx + 1, @@ -163,14 +149,12 @@ def f(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testAlignClosingBracketWithVisualIndentation(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ TEST_LIST = ('foo', 'bar', # first comment 'baz' # second comment ) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ TEST_LIST = ( 'foo', 'bar', # first comment @@ -180,8 +164,7 @@ def testAlignClosingBracketWithVisualIndentation(self): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def f(): def g(): @@ -190,8 +173,7 @@ def g(): ): pass """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def f(): def g(): @@ -204,13 +186,11 @@ def g(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testIndentSizeChanging(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if True: runtime_mins = (program_end_time - program_start_time).total_seconds() / 60.0 """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if True: runtime_mins = (program_end_time - program_start_time).total_seconds() / 60.0 @@ -219,8 +199,7 @@ def testIndentSizeChanging(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testHangingIndentCollision(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if (aaaaaaaaaaaaaa + bbbbbbbbbbbbbbbb == ccccccccccccccccc and xxxxxxxxxxxxx or yyyyyyyyyyyyyyyyy): pass elif (xxxxxxxxxxxxxxx(aaaaaaaaaaa, bbbbbbbbbbbbbb, cccccccccccc, dddddddddd=None)): @@ -234,8 +213,7 @@ def h(): for connection in itertools.chain(branch.contact, branch.address, morestuff.andmore.andmore.andmore.andmore.andmore.andmore.andmore): dosomething(connection) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if (aaaaaaaaaaaaaa + bbbbbbbbbbbbbbbb == ccccccccccccccccc and xxxxxxxxxxxxx or yyyyyyyyyyyyyyyyy): pass @@ -264,8 +242,7 @@ def testSplittingBeforeLogicalOperator(self): style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: pep8, split_before_logical_operator: True}')) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo(): return bool(update.message.new_chat_member or update.message.left_chat_member or update.message.new_chat_title or update.message.new_chat_photo or @@ -274,8 +251,7 @@ def foo(): or update.message.migrate_to_chat_id or update.message.migrate_from_chat_id or update.message.pinned_message) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo(): return bool( update.message.new_chat_member or update.message.left_chat_member @@ -289,20 +265,18 @@ def foo(): or update.message.pinned_message) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) def testContiguousListEndingWithComment(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if True: if True: keys.append(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) # may be unassigned. """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if True: if True: keys.append( @@ -316,13 +290,11 @@ def testSplittingBeforeFirstArgument(self): style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: pep8, split_before_first_argument: True}')) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ a_very_long_function_name(long_argument_name_1=1, long_argument_name_2=2, long_argument_name_3=3, long_argument_name_4=4) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ a_very_long_function_name( long_argument_name_1=1, long_argument_name_2=2, @@ -330,19 +302,17 @@ def testSplittingBeforeFirstArgument(self): long_argument_name_4=4) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) def testSplittingExpressionsInsideSubscripts(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo(): df = df[(df['campaign_status'] == 'LIVE') & (df['action_status'] == 'LIVE')] """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo(): df = df[(df['campaign_status'] == 'LIVE') & (df['action_status'] == 'LIVE')] @@ -351,15 +321,13 @@ def foo(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplitListsAndDictSetMakersIfCommaTerminated(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ DJANGO_TEMPLATES_OPTIONS = {"context_processors": []} DJANGO_TEMPLATES_OPTIONS = {"context_processors": [],} x = ["context_processors"] x = ["context_processors",] """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ DJANGO_TEMPLATES_OPTIONS = {"context_processors": []} DJANGO_TEMPLATES_OPTIONS = { "context_processors": [], @@ -373,15 +341,13 @@ def testSplitListsAndDictSetMakersIfCommaTerminated(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplitAroundNamedAssigns(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class a(): def a(): return a( aaaaaaaaaa=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class a(): def a(): @@ -393,15 +359,13 @@ def a(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testUnaryOperator(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if not -3 < x < 3: pass if -3 < x < 3: pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if not -3 < x < 3: pass if -3 < x < 3: @@ -413,24 +377,21 @@ def testUnaryOperator(self): def testNoSplitBeforeDictValue(self): try: style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{based_on_style: pep8, ' - 'allow_split_before_dict_value: false, ' - 'coalesce_brackets: true, ' - 'dedent_closing_brackets: true, ' - 'each_dict_entry_on_separate_line: true, ' - 'split_before_logical_operator: true}')) - - unformatted_code = textwrap.dedent( - """\ + style.CreateStyleFromConfig('{based_on_style: pep8, ' + 'allow_split_before_dict_value: false, ' + 'coalesce_brackets: true, ' + 'dedent_closing_brackets: true, ' + 'each_dict_entry_on_separate_line: true, ' + 'split_before_logical_operator: true}')) + + unformatted_code = textwrap.dedent("""\ some_dict = { 'title': _("I am example data"), 'description': _("Lorem ipsum dolor met sit amet elit, si vis pacem para bellum " "elites nihi very long string."), } """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ some_dict = { 'title': _("I am example data"), 'description': _( @@ -440,15 +401,13 @@ def testNoSplitBeforeDictValue(self): } """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ X = {'a': 1, 'b': 2, 'key': this_is_a_function_call_that_goes_over_the_column_limit_im_pretty_sure()} """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ X = { 'a': 1, 'b': 2, @@ -456,18 +415,16 @@ def testNoSplitBeforeDictValue(self): } """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ attrs = { 'category': category, 'role': forms.ModelChoiceField(label=_("Role"), required=False, queryset=category_roles, initial=selected_role, empty_label=_("No access"),), } """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ attrs = { 'category': category, 'role': forms.ModelChoiceField( @@ -480,19 +437,17 @@ def testNoSplitBeforeDictValue(self): } """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ css_class = forms.CharField( label=_("CSS class"), required=False, help_text=_("Optional CSS class used to customize this category appearance from templates."), ) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ css_class = forms.CharField( label=_("CSS class"), required=False, @@ -502,8 +457,8 @@ def testNoSplitBeforeDictValue(self): ) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) @@ -518,7 +473,7 @@ def _(): cdffile['Latitude'][:] >= select_lat - radius) & ( cdffile['Latitude'][:] <= select_lat + radius)) """ - expected_code = """\ + expected_code = """\ def _(): include_values = np.where( (cdffile['Quality_Flag'][:] >= 5) & (cdffile['Day_Night_Flag'][:] == 1) @@ -527,7 +482,7 @@ def _(): & (cdffile['Latitude'][:] >= select_lat - radius) & (cdffile['Latitude'][:] <= select_lat + radius)) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertEqual(expected_code, reformatter.Reformat(llines)) def testNoBlankLinesOnlyForFirstNestedObject(self): @@ -545,7 +500,7 @@ def bar(self): bar docs """ ''' - expected_code = '''\ + expected_code = '''\ class Demo: """ Demo docs @@ -561,7 +516,7 @@ def bar(self): bar docs """ ''' - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertEqual(expected_code, reformatter.Reformat(llines)) def testSplitBeforeArithmeticOperators(self): @@ -579,9 +534,9 @@ def _(): raise ValueError('This is a long message that ends with an argument: ' + str(42)) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) @@ -591,12 +546,12 @@ def testListSplitting(self): (1,1), (1,1), (1,1), (1,1), (1,1), (1,1), (1,1), (1,10), (1,11), (1, 10), (1,11), (10,11)]) """ - expected_code = """\ + expected_code = """\ foo([(1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 10), (1, 11), (1, 10), (1, 11), (10, 11)]) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testNoBlankLineBeforeNestedFuncOrClass(self): @@ -606,7 +561,7 @@ def testNoBlankLineBeforeNestedFuncOrClass(self): '{based_on_style: pep8, ' 'blank_line_before_nested_class_or_def: false}')) - unformatted_code = '''\ + unformatted_code = '''\ def normal_function(): """Return the nested function.""" @@ -634,15 +589,14 @@ class nested_class(): return nested_function ''' - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) def testParamListIndentationCollision1(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class _(): def __init__(self, title: Optional[str], diffs: Collection[BinaryDiff] = (), charset: Union[Type[AsciiCharset], Type[LineCharset]] = AsciiCharset, preprocess: Callable[[str], str] = identity, @@ -651,8 +605,7 @@ def __init__(self, title: Optional[str], diffs: Collection[BinaryDiff] = (), cha self._cs = charset self._preprocess = preprocess """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class _(): def __init__( @@ -671,8 +624,7 @@ def __init__( self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testParamListIndentationCollision2(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def simple_pass_function_with_an_extremely_long_name_and_some_arguments( argument0, argument1): pass @@ -681,8 +633,7 @@ def simple_pass_function_with_an_extremely_long_name_and_some_arguments( self.assertCodeEqual(code, reformatter.Reformat(llines)) def testParamListIndentationCollision3(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def func1( arg1, arg2, @@ -700,13 +651,11 @@ def func2( self.assertCodeEqual(code, reformatter.Reformat(llines)) def testTwoWordComparisonOperators(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl is not ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj) _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl not in {ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj}) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl is not ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj) _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl @@ -718,8 +667,7 @@ def testTwoWordComparisonOperators(self): @unittest.skipUnless(not py3compat.PY3, 'Requires Python 2.7') def testAsyncAsNonKeyword(self): # In Python 2, async may be used as a non-keyword identifier. - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ from util import async @@ -735,14 +683,12 @@ def bar(self): self.assertCodeEqual(code, reformatter.Reformat(llines, verify=False)) def testStableInlinedDictionaryFormatting(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def _(): url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( value, urllib.urlencode({'action': 'update', 'parameter': value})) """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def _(): url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( value, urllib.urlencode({ @@ -751,19 +697,18 @@ def _(): })) """) - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) - llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(reformatted_code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testSpaceBetweenColonAndElipses(self): style.SetGlobalStyle(style.CreatePEP8Style()) - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class MyClass(ABC): place: ... @@ -774,11 +719,10 @@ class MyClass(ABC): @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testSpaceBetweenDictColonAndElipses(self): style.SetGlobalStyle(style.CreatePEP8Style()) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ {0:"...", 1:...} """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ {0: "...", 1: ...} """) @@ -788,8 +732,7 @@ def testSpaceBetweenDictColonAndElipses(self): class TestsForSpacesInsideBrackets(yapf_test_helper.YAPFTest): """Test the SPACE_INSIDE_BRACKETS style option.""" - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ foo() foo(1) foo(1,2) @@ -822,8 +765,7 @@ def testEnabled(self): style.SetGlobalStyle( style.CreateStyleFromConfig('{space_inside_brackets: True}')) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ foo() foo( 1 ) foo( 1, 2 ) @@ -861,8 +803,7 @@ def testEnabled(self): def testDefault(self): style.SetGlobalStyle(style.CreatePEP8Style()) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ foo() foo(1) foo(1, 2) @@ -901,8 +842,7 @@ def testDefault(self): def testAwait(self): style.SetGlobalStyle( style.CreateStyleFromConfig('{space_inside_brackets: True}')) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ import asyncio import time @@ -915,8 +855,7 @@ async def main(): if (await get_html()): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ import asyncio import time @@ -937,8 +876,7 @@ async def main(): class TestsForSpacesAroundSubscriptColon(yapf_test_helper.YAPFTest): """Test the SPACES_AROUND_SUBSCRIPT_COLON style option.""" - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ a = list1[ : ] b = list2[ slice_start: ] c = list3[ slice_start:slice_end ] @@ -954,8 +892,7 @@ class TestsForSpacesAroundSubscriptColon(yapf_test_helper.YAPFTest): def testEnabled(self): style.SetGlobalStyle( style.CreateStyleFromConfig('{spaces_around_subscript_colon: True}')) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ a = list1[:] b = list2[slice_start :] c = list3[slice_start : slice_end] @@ -972,13 +909,11 @@ def testEnabled(self): def testWithSpaceInsideBrackets(self): style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{' - 'spaces_around_subscript_colon: true, ' - 'space_inside_brackets: true,' - '}')) - expected_formatted_code = textwrap.dedent( - """\ + style.CreateStyleFromConfig('{' + 'spaces_around_subscript_colon: true, ' + 'space_inside_brackets: true,' + '}')) + expected_formatted_code = textwrap.dedent("""\ a = list1[ : ] b = list2[ slice_start : ] c = list3[ slice_start : slice_end ] @@ -995,8 +930,7 @@ def testWithSpaceInsideBrackets(self): def testDefault(self): style.SetGlobalStyle(style.CreatePEP8Style()) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ a = list1[:] b = list2[slice_start:] c = list3[slice_start:slice_end] diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index 88dd9d7bd..81e565326 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -33,13 +33,11 @@ def setUpClass(cls): # pylint: disable=g-missing-super-call style.SetGlobalStyle(style.CreatePEP8Style()) def testTypedNames(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def x(aaaaaaaaaaaaaaa:int,bbbbbbbbbbbbbbbb:str,ccccccccccccccc:dict,eeeeeeeeeeeeee:set={1, 2, 3})->bool: pass """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def x(aaaaaaaaaaaaaaa: int, bbbbbbbbbbbbbbbb: str, ccccccccccccccc: dict, @@ -50,13 +48,11 @@ def x(aaaaaaaaaaaaaaa: int, self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testTypedNameWithLongNamedArg(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def func(arg=long_function_call_that_pushes_the_line_over_eighty_characters()) -> ReturnType: pass """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def func(arg=long_function_call_that_pushes_the_line_over_eighty_characters() ) -> ReturnType: pass @@ -65,13 +61,11 @@ def func(arg=long_function_call_that_pushes_the_line_over_eighty_characters() self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testKeywordOnlyArgSpecifier(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo(a, *, kw): return a+kw """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo(a, *, kw): return a + kw """) @@ -80,15 +74,13 @@ def foo(a, *, kw): @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testPEP448ParameterExpansion(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ { ** x } { **{} } { **{ **x }, **x } {'a': 1, **kw , 'b':3, **kw2 } """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ {**x} {**{}} {**{**x}, **x} @@ -98,13 +90,11 @@ def testPEP448ParameterExpansion(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testAnnotations(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo(a: list, b: "bar") -> dict: return a+b """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo(a: list, b: "bar") -> dict: return a + b """) @@ -112,16 +102,15 @@ def foo(a: list, b: "bar") -> dict: self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testExecAsNonKeyword(self): - unformatted_code = 'methods.exec( sys.modules[name])\n' + unformatted_code = 'methods.exec( sys.modules[name])\n' expected_formatted_code = 'methods.exec(sys.modules[name])\n' - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testAsyncFunctions(self): if sys.version_info[1] < 5: return - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ import asyncio import time @@ -141,7 +130,7 @@ async def main(): self.assertCodeEqual(code, reformatter.Reformat(llines, verify=False)) def testNoSpacesAroundPowerOperator(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ a**b """) expected_formatted_code = textwrap.dedent("""\ @@ -154,13 +143,13 @@ def testNoSpacesAroundPowerOperator(self): '{based_on_style: pep8, SPACES_AROUND_POWER_OPERATOR: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) def testSpacesAroundDefaultOrNamedAssign(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ f(a=5) """) expected_formatted_code = textwrap.dedent("""\ @@ -174,14 +163,13 @@ def testSpacesAroundDefaultOrNamedAssign(self): 'SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) def testTypeHint(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo(x: int=42): pass @@ -189,8 +177,7 @@ def foo(x: int=42): def foo2(x: 'int' =42): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo(x: int = 42): pass @@ -202,18 +189,17 @@ def foo2(x: 'int' = 42): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMatrixMultiplication(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ a=b@c """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ a = b @ c """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoneKeyword(self): - code = """\ + code = """\ None.__ne__() """ llines = yapf_test_helper.ParseAndUnwrap(code) @@ -222,8 +208,7 @@ def testNoneKeyword(self): def testAsyncWithPrecedingComment(self): if sys.version_info[1] < 5: return - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ import asyncio # Comment @@ -233,8 +218,7 @@ async def bar(): async def foo(): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ import asyncio @@ -252,8 +236,7 @@ async def foo(): def testAsyncFunctionsNested(self): if sys.version_info[1] < 5: return - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ async def outer(): async def inner(): @@ -265,15 +248,13 @@ async def inner(): def testKeepTypesIntact(self): if sys.version_info[1] < 5: return - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def _ReduceAbstractContainers( self, *args: Optional[automation_converter.PyiCollectionAbc]) -> List[ automation_converter.PyiCollectionAbc]: pass """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def _ReduceAbstractContainers( self, *args: Optional[automation_converter.PyiCollectionAbc] ) -> List[automation_converter.PyiCollectionAbc]: @@ -285,15 +266,13 @@ def _ReduceAbstractContainers( def testContinuationIndentWithAsync(self): if sys.version_info[1] < 5: return - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ async def start_websocket(): async with session.ws_connect( r"ws://a_really_long_long_long_long_long_long_url") as ws: pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ async def start_websocket(): async with session.ws_connect( r"ws://a_really_long_long_long_long_long_long_url") as ws: @@ -367,15 +346,15 @@ def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): 'split_before_first_argument: true}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) def testDictUnpacking(self): if sys.version_info[1] < 5: return - unformatted_code = """\ + unformatted_code = """\ class Foo: def foo(self): foofoofoofoofoofoofoofoo('foofoofoofoofoo', { @@ -394,7 +373,7 @@ def foo(self): **foofoofoo }) """ - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMultilineFormatString(self): @@ -422,7 +401,7 @@ def dirichlet(x12345678901234567890123456789012345678901234567890=...) -> None: self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionTypedReturnNextLine(self): - code = """\ + code = """\ def _GenerateStatsEntries( process_id: Text, timestamp: Optional[ffffffff.FFFFFFFFFFF] = None @@ -433,7 +412,7 @@ def _GenerateStatsEntries( self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionTypedReturnSameLine(self): - code = """\ + code = """\ def rrrrrrrrrrrrrrrrrrrrrr( ccccccccccccccccccccccc: Tuple[Text, Text]) -> List[Tuple[Text, Text]]: pass @@ -444,8 +423,7 @@ def rrrrrrrrrrrrrrrrrrrrrr( def testAsyncForElseNotIndentedInsideBody(self): if sys.version_info[1] < 5: return - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ async def fn(): async for message in websocket: for i in range(10): @@ -461,8 +439,7 @@ async def fn(): def testForElseInAsyncNotMixedWithAsyncFor(self): if sys.version_info[1] < 5: return - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ async def fn(): for i in range(10): pass @@ -473,14 +450,12 @@ async def fn(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testParameterListIndentationConflicts(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def raw_message( # pylint: disable=too-many-arguments self, text, user_id=1000, chat_type='private', forward_date=None, forward_from=None): pass """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def raw_message( # pylint: disable=too-many-arguments self, text, diff --git a/yapftests/reformatter_style_config_test.py b/yapftests/reformatter_style_config_test.py index 6746ba0ed..c5726cb30 100644 --- a/yapftests/reformatter_style_config_test.py +++ b/yapftests/reformatter_style_config_test.py @@ -30,30 +30,26 @@ def setUp(self): def testSetGlobalStyle(self): try: style.SetGlobalStyle(style.CreateYapfStyle()) - unformatted_code = textwrap.dedent( - u"""\ + unformatted_code = textwrap.dedent(u"""\ for i in range(5): print('bar') """) - expected_formatted_code = textwrap.dedent( - u"""\ + expected_formatted_code = textwrap.dedent(u"""\ for i in range(5): print('bar') """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) style.DEFAULT_STYLE = self.current_style - unformatted_code = textwrap.dedent( - u"""\ + unformatted_code = textwrap.dedent(u"""\ for i in range(5): print('bar') """) - expected_formatted_code = textwrap.dedent( - u"""\ + expected_formatted_code = textwrap.dedent(u"""\ for i in range(5): print('bar') """) @@ -62,35 +58,32 @@ def testSetGlobalStyle(self): def testOperatorNoSpaceStyle(self): try: - sympy_style = style.CreatePEP8Style() + sympy_style = style.CreatePEP8Style() sympy_style['NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS'] = \ style._StringSetConverter('*,/') style.SetGlobalStyle(sympy_style) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ a = 1+2 * 3 - 4 / 5 b = '0' * 1 """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ a = 1 + 2*3 - 4/5 b = '0'*1 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) style.DEFAULT_STYLE = self.current_style def testOperatorPrecedenceStyle(self): try: - pep8_with_precedence = style.CreatePEP8Style() + pep8_with_precedence = style.CreatePEP8Style() pep8_with_precedence['ARITHMETIC_PRECEDENCE_INDICATION'] = True style.SetGlobalStyle(pep8_with_precedence) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ 1+2 (1 + 2) * (3 - (4 / 5)) a = 1 * 2 + 3 / 4 @@ -105,8 +98,7 @@ def testOperatorPrecedenceStyle(self): j = (1 * 2 - 3) + 4 k = (1 * 2 * 3) + (4 * 5 * 6 * 7 * 8) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ 1 + 2 (1+2) * (3 - (4/5)) a = 1*2 + 3/4 @@ -123,20 +115,19 @@ def testOperatorPrecedenceStyle(self): """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) style.DEFAULT_STYLE = self.current_style def testNoSplitBeforeFirstArgumentStyle1(self): try: - pep8_no_split_before_first = style.CreatePEP8Style() + pep8_no_split_before_first = style.CreatePEP8Style() pep8_no_split_before_first['SPLIT_BEFORE_FIRST_ARGUMENT'] = False - pep8_no_split_before_first['SPLIT_BEFORE_NAMED_ASSIGNS'] = False + pep8_no_split_before_first['SPLIT_BEFORE_NAMED_ASSIGNS'] = False style.SetGlobalStyle(pep8_no_split_before_first) - formatted_code = textwrap.dedent( - """\ + formatted_code = textwrap.dedent("""\ # Example from in-code MustSplit comments foo = outer_function_call(fitting_inner_function_call(inner_arg1, inner_arg2), outer_arg1, outer_arg2) @@ -173,12 +164,11 @@ def testNoSplitBeforeFirstArgumentStyle1(self): def testNoSplitBeforeFirstArgumentStyle2(self): try: - pep8_no_split_before_first = style.CreatePEP8Style() + pep8_no_split_before_first = style.CreatePEP8Style() pep8_no_split_before_first['SPLIT_BEFORE_FIRST_ARGUMENT'] = False - pep8_no_split_before_first['SPLIT_BEFORE_NAMED_ASSIGNS'] = True + pep8_no_split_before_first['SPLIT_BEFORE_NAMED_ASSIGNS'] = True style.SetGlobalStyle(pep8_no_split_before_first) - formatted_code = textwrap.dedent( - """\ + formatted_code = textwrap.dedent("""\ # Examples Issue#556 i_take_a_lot_of_params(arg1, param1=very_long_expression1(), diff --git a/yapftests/reformatter_verify_test.py b/yapftests/reformatter_verify_test.py index 2abbd19ff..33ba3a614 100644 --- a/yapftests/reformatter_verify_test.py +++ b/yapftests/reformatter_verify_test.py @@ -32,8 +32,7 @@ def setUpClass(cls): style.SetGlobalStyle(style.CreatePEP8Style()) def testVerifyException(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class ABC(metaclass=type): pass """) @@ -43,23 +42,20 @@ class ABC(metaclass=type): reformatter.Reformat(llines) # verify should be False by default. def testNoVerify(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class ABC(metaclass=type): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class ABC(metaclass=type): pass """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines, verify=False)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines, verify=False)) def testVerifyFutureImport(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ from __future__ import print_function def call_my_function(the_function): @@ -72,8 +68,7 @@ def call_my_function(the_function): with self.assertRaises(verifier.InternalError): reformatter.Reformat(llines, verify=True) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ from __future__ import print_function @@ -85,12 +80,11 @@ def call_my_function(the_function): call_my_function(print) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual( - expected_formatted_code, reformatter.Reformat(llines, verify=False)) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines, verify=False)) def testContinuationLineShouldBeDistinguished(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ class Foo(object): def bar(self): diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index 24226cbac..f7474a398 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -26,10 +26,10 @@ from yapftests import yapf_test_helper -UNBREAKABLE = split_penalty.UNBREAKABLE +UNBREAKABLE = split_penalty.UNBREAKABLE VERY_STRONGLY_CONNECTED = split_penalty.VERY_STRONGLY_CONNECTED -DOTTED_NAME = split_penalty.DOTTED_NAME -STRONGLY_CONNECTED = split_penalty.STRONGLY_CONNECTED +DOTTED_NAME = split_penalty.DOTTED_NAME +STRONGLY_CONNECTED = split_penalty.STRONGLY_CONNECTED class SplitPenaltyTest(yapf_test_helper.YAPFTest): @@ -68,12 +68,9 @@ def FlattenRec(tree): if pytree_utils.NodeName(tree) in pytree_utils.NONSEMANTIC_TOKENS: return [] if isinstance(tree, pytree.Leaf): - return [ - ( - tree.value, - pytree_utils.GetNodeAnnotation( - tree, pytree_utils.Annotation.SPLIT_PENALTY)) - ] + return [(tree.value, + pytree_utils.GetNodeAnnotation( + tree, pytree_utils.Annotation.SPLIT_PENALTY))] nodes = [] for node in tree.children: nodes += FlattenRec(node) @@ -88,194 +85,181 @@ def foo(x): pass """) tree = self._ParseAndComputePenalties(code) - self._CheckPenalties( - tree, [ - ('def', None), - ('foo', UNBREAKABLE), - ('(', UNBREAKABLE), - ('x', None), - (')', STRONGLY_CONNECTED), - (':', UNBREAKABLE), - ('pass', None), - ]) + self._CheckPenalties(tree, [ + ('def', None), + ('foo', UNBREAKABLE), + ('(', UNBREAKABLE), + ('x', None), + (')', STRONGLY_CONNECTED), + (':', UNBREAKABLE), + ('pass', None), + ]) # Test function definition with trailing comment. - code = textwrap.dedent( - r""" + code = textwrap.dedent(r""" def foo(x): # trailing comment pass """) tree = self._ParseAndComputePenalties(code) - self._CheckPenalties( - tree, [ - ('def', None), - ('foo', UNBREAKABLE), - ('(', UNBREAKABLE), - ('x', None), - (')', STRONGLY_CONNECTED), - (':', UNBREAKABLE), - ('pass', None), - ]) + self._CheckPenalties(tree, [ + ('def', None), + ('foo', UNBREAKABLE), + ('(', UNBREAKABLE), + ('x', None), + (')', STRONGLY_CONNECTED), + (':', UNBREAKABLE), + ('pass', None), + ]) # Test class definitions. - code = textwrap.dedent( - r""" + code = textwrap.dedent(r""" class A: pass class B(A): pass """) tree = self._ParseAndComputePenalties(code) - self._CheckPenalties( - tree, [ - ('class', None), - ('A', UNBREAKABLE), - (':', UNBREAKABLE), - ('pass', None), - ('class', None), - ('B', UNBREAKABLE), - ('(', UNBREAKABLE), - ('A', None), - (')', None), - (':', UNBREAKABLE), - ('pass', None), - ]) + self._CheckPenalties(tree, [ + ('class', None), + ('A', UNBREAKABLE), + (':', UNBREAKABLE), + ('pass', None), + ('class', None), + ('B', UNBREAKABLE), + ('(', UNBREAKABLE), + ('A', None), + (')', None), + (':', UNBREAKABLE), + ('pass', None), + ]) # Test lambda definitions. code = textwrap.dedent(r""" lambda a, b: None """) tree = self._ParseAndComputePenalties(code) - self._CheckPenalties( - tree, [ - ('lambda', None), - ('a', VERY_STRONGLY_CONNECTED), - (',', VERY_STRONGLY_CONNECTED), - ('b', VERY_STRONGLY_CONNECTED), - (':', VERY_STRONGLY_CONNECTED), - ('None', VERY_STRONGLY_CONNECTED), - ]) + self._CheckPenalties(tree, [ + ('lambda', None), + ('a', VERY_STRONGLY_CONNECTED), + (',', VERY_STRONGLY_CONNECTED), + ('b', VERY_STRONGLY_CONNECTED), + (':', VERY_STRONGLY_CONNECTED), + ('None', VERY_STRONGLY_CONNECTED), + ]) # Test dotted names. code = textwrap.dedent(r""" import a.b.c """) tree = self._ParseAndComputePenalties(code) - self._CheckPenalties( - tree, [ - ('import', None), - ('a', None), - ('.', UNBREAKABLE), - ('b', UNBREAKABLE), - ('.', UNBREAKABLE), - ('c', UNBREAKABLE), - ]) + self._CheckPenalties(tree, [ + ('import', None), + ('a', None), + ('.', UNBREAKABLE), + ('b', UNBREAKABLE), + ('.', UNBREAKABLE), + ('c', UNBREAKABLE), + ]) def testStronglyConnected(self): # Test dictionary keys. - code = textwrap.dedent( - r""" + code = textwrap.dedent(r""" a = { 'x': 42, y(lambda a: 23): 37, } """) tree = self._ParseAndComputePenalties(code) - self._CheckPenalties( - tree, [ - ('a', None), - ('=', None), - ('{', None), - ("'x'", None), - (':', STRONGLY_CONNECTED), - ('42', None), - (',', None), - ('y', None), - ('(', UNBREAKABLE), - ('lambda', STRONGLY_CONNECTED), - ('a', VERY_STRONGLY_CONNECTED), - (':', VERY_STRONGLY_CONNECTED), - ('23', VERY_STRONGLY_CONNECTED), - (')', VERY_STRONGLY_CONNECTED), - (':', STRONGLY_CONNECTED), - ('37', None), - (',', None), - ('}', None), - ]) + self._CheckPenalties(tree, [ + ('a', None), + ('=', None), + ('{', None), + ("'x'", None), + (':', STRONGLY_CONNECTED), + ('42', None), + (',', None), + ('y', None), + ('(', UNBREAKABLE), + ('lambda', STRONGLY_CONNECTED), + ('a', VERY_STRONGLY_CONNECTED), + (':', VERY_STRONGLY_CONNECTED), + ('23', VERY_STRONGLY_CONNECTED), + (')', VERY_STRONGLY_CONNECTED), + (':', STRONGLY_CONNECTED), + ('37', None), + (',', None), + ('}', None), + ]) # Test list comprehension. code = textwrap.dedent(r""" [a for a in foo if a.x == 37] """) tree = self._ParseAndComputePenalties(code) - self._CheckPenalties( - tree, [ - ('[', None), - ('a', None), - ('for', 0), - ('a', STRONGLY_CONNECTED), - ('in', STRONGLY_CONNECTED), - ('foo', STRONGLY_CONNECTED), - ('if', 0), - ('a', STRONGLY_CONNECTED), - ('.', VERY_STRONGLY_CONNECTED), - ('x', DOTTED_NAME), - ('==', STRONGLY_CONNECTED), - ('37', STRONGLY_CONNECTED), - (']', None), - ]) + self._CheckPenalties(tree, [ + ('[', None), + ('a', None), + ('for', 0), + ('a', STRONGLY_CONNECTED), + ('in', STRONGLY_CONNECTED), + ('foo', STRONGLY_CONNECTED), + ('if', 0), + ('a', STRONGLY_CONNECTED), + ('.', VERY_STRONGLY_CONNECTED), + ('x', DOTTED_NAME), + ('==', STRONGLY_CONNECTED), + ('37', STRONGLY_CONNECTED), + (']', None), + ]) def testFuncCalls(self): code = 'foo(1, 2, 3)\n' tree = self._ParseAndComputePenalties(code) - self._CheckPenalties( - tree, [ - ('foo', None), - ('(', UNBREAKABLE), - ('1', None), - (',', UNBREAKABLE), - ('2', None), - (',', UNBREAKABLE), - ('3', None), - (')', VERY_STRONGLY_CONNECTED), - ]) + self._CheckPenalties(tree, [ + ('foo', None), + ('(', UNBREAKABLE), + ('1', None), + (',', UNBREAKABLE), + ('2', None), + (',', UNBREAKABLE), + ('3', None), + (')', VERY_STRONGLY_CONNECTED), + ]) # Now a method call, which has more than one trailer code = 'foo.bar.baz(1, 2, 3)\n' tree = self._ParseAndComputePenalties(code) - self._CheckPenalties( - tree, [ - ('foo', None), - ('.', VERY_STRONGLY_CONNECTED), - ('bar', DOTTED_NAME), - ('.', VERY_STRONGLY_CONNECTED), - ('baz', DOTTED_NAME), - ('(', STRONGLY_CONNECTED), - ('1', None), - (',', UNBREAKABLE), - ('2', None), - (',', UNBREAKABLE), - ('3', None), - (')', VERY_STRONGLY_CONNECTED), - ]) + self._CheckPenalties(tree, [ + ('foo', None), + ('.', VERY_STRONGLY_CONNECTED), + ('bar', DOTTED_NAME), + ('.', VERY_STRONGLY_CONNECTED), + ('baz', DOTTED_NAME), + ('(', STRONGLY_CONNECTED), + ('1', None), + (',', UNBREAKABLE), + ('2', None), + (',', UNBREAKABLE), + ('3', None), + (')', VERY_STRONGLY_CONNECTED), + ]) # Test single generator argument. code = 'max(i for i in xrange(10))\n' tree = self._ParseAndComputePenalties(code) - self._CheckPenalties( - tree, [ - ('max', None), - ('(', UNBREAKABLE), - ('i', 0), - ('for', 0), - ('i', STRONGLY_CONNECTED), - ('in', STRONGLY_CONNECTED), - ('xrange', STRONGLY_CONNECTED), - ('(', UNBREAKABLE), - ('10', STRONGLY_CONNECTED), - (')', VERY_STRONGLY_CONNECTED), - (')', VERY_STRONGLY_CONNECTED), - ]) + self._CheckPenalties(tree, [ + ('max', None), + ('(', UNBREAKABLE), + ('i', 0), + ('for', 0), + ('i', STRONGLY_CONNECTED), + ('in', STRONGLY_CONNECTED), + ('xrange', STRONGLY_CONNECTED), + ('(', UNBREAKABLE), + ('10', STRONGLY_CONNECTED), + (')', VERY_STRONGLY_CONNECTED), + (')', VERY_STRONGLY_CONNECTED), + ]) if __name__ == '__main__': diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 4aceba3d0..8a37f9535 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -50,8 +50,8 @@ def testContinuationAlignStyleStringConverter(self): 'VALIGN-RIGHT') with self.assertRaises(ValueError) as ctx: style._ContinuationAlignStyleStringConverter('blahblah') - self.assertIn( - "unknown continuation align style: 'blahblah'", str(ctx.exception)) + self.assertIn("unknown continuation align style: 'blahblah'", + str(ctx.exception)) def testStringListConverter(self): self.assertEqual(style._StringListConverter('foo, bar'), ['foo', 'bar']) @@ -136,8 +136,7 @@ def tearDownClass(cls): # pylint: disable=g-missing-super-call shutil.rmtree(cls.test_tmpdir) def testDefaultBasedOnStyle(self): - cfg = textwrap.dedent( - u'''\ + cfg = textwrap.dedent(u'''\ [style] continuation_indent_width = 20 ''') @@ -147,8 +146,7 @@ def testDefaultBasedOnStyle(self): self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) def testDefaultBasedOnPEP8Style(self): - cfg = textwrap.dedent( - u'''\ + cfg = textwrap.dedent(u'''\ [style] based_on_style = pep8 continuation_indent_width = 40 @@ -159,8 +157,7 @@ def testDefaultBasedOnPEP8Style(self): self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 40) def testDefaultBasedOnGoogleStyle(self): - cfg = textwrap.dedent( - u'''\ + cfg = textwrap.dedent(u'''\ [style] based_on_style = google continuation_indent_width = 20 @@ -171,8 +168,7 @@ def testDefaultBasedOnGoogleStyle(self): self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) def testDefaultBasedOnFacebookStyle(self): - cfg = textwrap.dedent( - u'''\ + cfg = textwrap.dedent(u'''\ [style] based_on_style = facebook continuation_indent_width = 20 @@ -183,8 +179,7 @@ def testDefaultBasedOnFacebookStyle(self): self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) def testBoolOptionValue(self): - cfg = textwrap.dedent( - u'''\ + cfg = textwrap.dedent(u'''\ [style] based_on_style = pep8 SPLIT_BEFORE_NAMED_ASSIGNS=False @@ -197,8 +192,7 @@ def testBoolOptionValue(self): self.assertEqual(cfg['SPLIT_BEFORE_LOGICAL_OPERATOR'], True) def testStringListOptionValue(self): - cfg = textwrap.dedent( - u'''\ + cfg = textwrap.dedent(u'''\ [style] based_on_style = pep8 I18N_FUNCTION_CALL = N_, V_, T_ @@ -224,8 +218,7 @@ def testErrorNoStyleSection(self): style.CreateStyleFromConfig(filepath) def testErrorUnknownStyleOption(self): - cfg = textwrap.dedent( - u'''\ + cfg = textwrap.dedent(u'''\ [style] indent_width=2 hummus=2 @@ -242,7 +235,7 @@ def testPyprojectTomlNoYapfSection(self): return filepath = os.path.join(self.test_tmpdir, 'pyproject.toml') - _ = open(filepath, 'w') + _ = open(filepath, 'w') with self.assertRaisesRegex(style.StyleConfigError, 'Unable to find section'): style.CreateStyleFromConfig(filepath) @@ -253,8 +246,7 @@ def testPyprojectTomlParseYapfSection(self): except ImportError: return - cfg = textwrap.dedent( - u'''\ + cfg = textwrap.dedent(u'''\ [tool.yapf] based_on_style = "pep8" continuation_indent_width = 40 @@ -284,12 +276,12 @@ def testDefaultBasedOnStyle(self): self.assertEqual(cfg['INDENT_WIDTH'], 2) def testDefaultBasedOnStyleBadDict(self): - self.assertRaisesRegex( - style.StyleConfigError, 'Unknown style option', - style.CreateStyleFromConfig, {'based_on_styl': 'pep8'}) - self.assertRaisesRegex( - style.StyleConfigError, 'not a valid', style.CreateStyleFromConfig, - {'INDENT_WIDTH': 'FOUR'}) + self.assertRaisesRegex(style.StyleConfigError, 'Unknown style option', + style.CreateStyleFromConfig, + {'based_on_styl': 'pep8'}) + self.assertRaisesRegex(style.StyleConfigError, 'not a valid', + style.CreateStyleFromConfig, + {'INDENT_WIDTH': 'FOUR'}) class StyleFromCommandLine(yapf_test_helper.YAPFTest): @@ -323,15 +315,12 @@ def testDefaultBasedOnDetaultTypeString(self): self.assertIsInstance(cfg, dict) def testDefaultBasedOnStyleBadString(self): - self.assertRaisesRegex( - style.StyleConfigError, 'Unknown style option', - style.CreateStyleFromConfig, '{based_on_styl: pep8}') - self.assertRaisesRegex( - style.StyleConfigError, 'not a valid', style.CreateStyleFromConfig, - '{INDENT_WIDTH: FOUR}') - self.assertRaisesRegex( - style.StyleConfigError, 'Invalid style dict', - style.CreateStyleFromConfig, '{based_on_style: pep8') + self.assertRaisesRegex(style.StyleConfigError, 'Unknown style option', + style.CreateStyleFromConfig, '{based_on_styl: pep8}') + self.assertRaisesRegex(style.StyleConfigError, 'not a valid', + style.CreateStyleFromConfig, '{INDENT_WIDTH: FOUR}') + self.assertRaisesRegex(style.StyleConfigError, 'Invalid style dict', + style.CreateStyleFromConfig, '{based_on_style: pep8') class StyleHelp(yapf_test_helper.YAPFTest): diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index 222153db4..8616169c9 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -35,11 +35,9 @@ def _CheckFormatTokenSubtypes(self, llines, list_of_expected): """ actual = [] for lline in llines: - filtered_values = [ - (ft.value, ft.subtypes) - for ft in lline.tokens - if ft.name not in pytree_utils.NONSEMANTIC_TOKENS - ] + filtered_values = [(ft.value, ft.subtypes) + for ft in lline.tokens + if ft.name not in pytree_utils.NONSEMANTIC_TOKENS] if filtered_values: actual.append(filtered_values) @@ -47,263 +45,242 @@ def _CheckFormatTokenSubtypes(self, llines, list_of_expected): def testFuncDefDefaultAssign(self): self.maxDiff = None # pylint: disable=invalid-name - code = textwrap.dedent( - r""" + code = textwrap.dedent(r""" def foo(a=37, *b, **c): return -x[:42] """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes( - llines, [ - [ - ('def', {subtypes.NONE}), - ('foo', {subtypes.FUNC_DEF}), - ('(', {subtypes.NONE}), - ( - 'a', { - subtypes.NONE, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - subtypes.PARAMETER_START, - }), - ( - '=', { - subtypes.DEFAULT_OR_NAMED_ASSIGN, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - }), - ( - '37', { - subtypes.NONE, - subtypes.PARAMETER_STOP, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - }), - (',', {subtypes.NONE}), - ( - '*', { - subtypes.PARAMETER_START, - subtypes.VARARGS_STAR, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - }), - ( - 'b', { - subtypes.NONE, - subtypes.PARAMETER_STOP, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - }), - (',', {subtypes.NONE}), - ( - '**', { - subtypes.PARAMETER_START, - subtypes.KWARGS_STAR_STAR, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - }), - ( - 'c', { - subtypes.NONE, - subtypes.PARAMETER_STOP, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - }), - (')', {subtypes.NONE}), - (':', {subtypes.NONE}), - ], - [ - ('return', {subtypes.NONE}), - ('-', {subtypes.UNARY_OPERATOR}), - ('x', {subtypes.NONE}), - ('[', {subtypes.SUBSCRIPT_BRACKET}), - (':', {subtypes.SUBSCRIPT_COLON}), - ('42', {subtypes.NONE}), - (']', {subtypes.SUBSCRIPT_BRACKET}), - ], - ]) + self._CheckFormatTokenSubtypes(llines, [ + [ + ('def', {subtypes.NONE}), + ('foo', {subtypes.FUNC_DEF}), + ('(', {subtypes.NONE}), + ('a', { + subtypes.NONE, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + subtypes.PARAMETER_START, + }), + ('=', { + subtypes.DEFAULT_OR_NAMED_ASSIGN, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + ('37', { + subtypes.NONE, + subtypes.PARAMETER_STOP, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + (',', {subtypes.NONE}), + ('*', { + subtypes.PARAMETER_START, + subtypes.VARARGS_STAR, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + ('b', { + subtypes.NONE, + subtypes.PARAMETER_STOP, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + (',', {subtypes.NONE}), + ('**', { + subtypes.PARAMETER_START, + subtypes.KWARGS_STAR_STAR, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + ('c', { + subtypes.NONE, + subtypes.PARAMETER_STOP, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + (')', {subtypes.NONE}), + (':', {subtypes.NONE}), + ], + [ + ('return', {subtypes.NONE}), + ('-', {subtypes.UNARY_OPERATOR}), + ('x', {subtypes.NONE}), + ('[', {subtypes.SUBSCRIPT_BRACKET}), + (':', {subtypes.SUBSCRIPT_COLON}), + ('42', {subtypes.NONE}), + (']', {subtypes.SUBSCRIPT_BRACKET}), + ], + ]) def testFuncCallWithDefaultAssign(self): - code = textwrap.dedent(r""" + code = textwrap.dedent(r""" foo(x, a='hello world') """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes( - llines, [ - [ - ('foo', {subtypes.NONE}), - ('(', {subtypes.NONE}), - ( - 'x', { - subtypes.NONE, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - }), - (',', {subtypes.NONE}), - ( - 'a', { - subtypes.NONE, - subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, - }), - ('=', {subtypes.DEFAULT_OR_NAMED_ASSIGN}), - ("'hello world'", {subtypes.NONE}), - (')', {subtypes.NONE}), - ], - ]) + self._CheckFormatTokenSubtypes(llines, [ + [ + ('foo', {subtypes.NONE}), + ('(', {subtypes.NONE}), + ('x', { + subtypes.NONE, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + (',', {subtypes.NONE}), + ('a', { + subtypes.NONE, + subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST, + }), + ('=', {subtypes.DEFAULT_OR_NAMED_ASSIGN}), + ("'hello world'", {subtypes.NONE}), + (')', {subtypes.NONE}), + ], + ]) def testSetComprehension(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ def foo(strs): return {s.lower() for s in strs} """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes( - llines, [ - [ - ('def', {subtypes.NONE}), - ('foo', {subtypes.FUNC_DEF}), - ('(', {subtypes.NONE}), - ( - 'strs', { - subtypes.NONE, - subtypes.PARAMETER_START, - subtypes.PARAMETER_STOP, - }), - (')', {subtypes.NONE}), - (':', {subtypes.NONE}), - ], - [ - ('return', {subtypes.NONE}), - ('{', {subtypes.NONE}), - ('s', {subtypes.COMP_EXPR}), - ('.', {subtypes.COMP_EXPR}), - ('lower', {subtypes.COMP_EXPR}), - ('(', {subtypes.COMP_EXPR}), - (')', {subtypes.COMP_EXPR}), - ('for', { - subtypes.DICT_SET_GENERATOR, - subtypes.COMP_FOR, - }), - ('s', {subtypes.COMP_FOR}), - ('in', {subtypes.COMP_FOR}), - ('strs', {subtypes.COMP_FOR}), - ('}', {subtypes.NONE}), - ], - ]) + self._CheckFormatTokenSubtypes(llines, [ + [ + ('def', {subtypes.NONE}), + ('foo', {subtypes.FUNC_DEF}), + ('(', {subtypes.NONE}), + ('strs', { + subtypes.NONE, + subtypes.PARAMETER_START, + subtypes.PARAMETER_STOP, + }), + (')', {subtypes.NONE}), + (':', {subtypes.NONE}), + ], + [ + ('return', {subtypes.NONE}), + ('{', {subtypes.NONE}), + ('s', {subtypes.COMP_EXPR}), + ('.', {subtypes.COMP_EXPR}), + ('lower', {subtypes.COMP_EXPR}), + ('(', {subtypes.COMP_EXPR}), + (')', {subtypes.COMP_EXPR}), + ('for', { + subtypes.DICT_SET_GENERATOR, + subtypes.COMP_FOR, + }), + ('s', {subtypes.COMP_FOR}), + ('in', {subtypes.COMP_FOR}), + ('strs', {subtypes.COMP_FOR}), + ('}', {subtypes.NONE}), + ], + ]) def testUnaryNotOperator(self): - code = textwrap.dedent("""\ + code = textwrap.dedent("""\ not a """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes( - llines, [[('not', {subtypes.UNARY_OPERATOR}), ('a', {subtypes.NONE})]]) + self._CheckFormatTokenSubtypes(llines, [[('not', {subtypes.UNARY_OPERATOR}), + ('a', {subtypes.NONE})]]) def testBitwiseOperators(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ x = ((a | (b ^ 3) & c) << 3) >> 1 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes( - llines, [ - [ - ('x', {subtypes.NONE}), - ('=', {subtypes.ASSIGN_OPERATOR}), - ('(', {subtypes.NONE}), - ('(', {subtypes.NONE}), - ('a', {subtypes.NONE}), - ('|', {subtypes.BINARY_OPERATOR}), - ('(', {subtypes.NONE}), - ('b', {subtypes.NONE}), - ('^', {subtypes.BINARY_OPERATOR}), - ('3', {subtypes.NONE}), - (')', {subtypes.NONE}), - ('&', {subtypes.BINARY_OPERATOR}), - ('c', {subtypes.NONE}), - (')', {subtypes.NONE}), - ('<<', {subtypes.BINARY_OPERATOR}), - ('3', {subtypes.NONE}), - (')', {subtypes.NONE}), - ('>>', {subtypes.BINARY_OPERATOR}), - ('1', {subtypes.NONE}), - ], - ]) + self._CheckFormatTokenSubtypes(llines, [ + [ + ('x', {subtypes.NONE}), + ('=', {subtypes.ASSIGN_OPERATOR}), + ('(', {subtypes.NONE}), + ('(', {subtypes.NONE}), + ('a', {subtypes.NONE}), + ('|', {subtypes.BINARY_OPERATOR}), + ('(', {subtypes.NONE}), + ('b', {subtypes.NONE}), + ('^', {subtypes.BINARY_OPERATOR}), + ('3', {subtypes.NONE}), + (')', {subtypes.NONE}), + ('&', {subtypes.BINARY_OPERATOR}), + ('c', {subtypes.NONE}), + (')', {subtypes.NONE}), + ('<<', {subtypes.BINARY_OPERATOR}), + ('3', {subtypes.NONE}), + (')', {subtypes.NONE}), + ('>>', {subtypes.BINARY_OPERATOR}), + ('1', {subtypes.NONE}), + ], + ]) def testArithmeticOperators(self): - code = textwrap.dedent( - """\ + code = textwrap.dedent("""\ x = ((a + (b - 3) * (1 % c) @ d) / 3) // 1 """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes( - llines, [ - [ - ('x', {subtypes.NONE}), - ('=', {subtypes.ASSIGN_OPERATOR}), - ('(', {subtypes.NONE}), - ('(', {subtypes.NONE}), - ('a', {subtypes.NONE}), - ('+', {subtypes.BINARY_OPERATOR}), - ('(', {subtypes.NONE}), - ('b', {subtypes.NONE}), - ('-', { - subtypes.BINARY_OPERATOR, - subtypes.SIMPLE_EXPRESSION, - }), - ('3', {subtypes.NONE}), - (')', {subtypes.NONE}), - ('*', {subtypes.BINARY_OPERATOR}), - ('(', {subtypes.NONE}), - ('1', {subtypes.NONE}), - ('%', { - subtypes.BINARY_OPERATOR, - subtypes.SIMPLE_EXPRESSION, - }), - ('c', {subtypes.NONE}), - (')', {subtypes.NONE}), - ('@', {subtypes.BINARY_OPERATOR}), - ('d', {subtypes.NONE}), - (')', {subtypes.NONE}), - ('/', {subtypes.BINARY_OPERATOR}), - ('3', {subtypes.NONE}), - (')', {subtypes.NONE}), - ('//', {subtypes.BINARY_OPERATOR}), - ('1', {subtypes.NONE}), - ], - ]) + self._CheckFormatTokenSubtypes(llines, [ + [ + ('x', {subtypes.NONE}), + ('=', {subtypes.ASSIGN_OPERATOR}), + ('(', {subtypes.NONE}), + ('(', {subtypes.NONE}), + ('a', {subtypes.NONE}), + ('+', {subtypes.BINARY_OPERATOR}), + ('(', {subtypes.NONE}), + ('b', {subtypes.NONE}), + ('-', { + subtypes.BINARY_OPERATOR, + subtypes.SIMPLE_EXPRESSION, + }), + ('3', {subtypes.NONE}), + (')', {subtypes.NONE}), + ('*', {subtypes.BINARY_OPERATOR}), + ('(', {subtypes.NONE}), + ('1', {subtypes.NONE}), + ('%', { + subtypes.BINARY_OPERATOR, + subtypes.SIMPLE_EXPRESSION, + }), + ('c', {subtypes.NONE}), + (')', {subtypes.NONE}), + ('@', {subtypes.BINARY_OPERATOR}), + ('d', {subtypes.NONE}), + (')', {subtypes.NONE}), + ('/', {subtypes.BINARY_OPERATOR}), + ('3', {subtypes.NONE}), + (')', {subtypes.NONE}), + ('//', {subtypes.BINARY_OPERATOR}), + ('1', {subtypes.NONE}), + ], + ]) def testSubscriptColon(self): - code = textwrap.dedent("""\ + code = textwrap.dedent("""\ x[0:42:1] """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes( - llines, [ - [ - ('x', {subtypes.NONE}), - ('[', {subtypes.SUBSCRIPT_BRACKET}), - ('0', {subtypes.NONE}), - (':', {subtypes.SUBSCRIPT_COLON}), - ('42', {subtypes.NONE}), - (':', {subtypes.SUBSCRIPT_COLON}), - ('1', {subtypes.NONE}), - (']', {subtypes.SUBSCRIPT_BRACKET}), - ], - ]) + self._CheckFormatTokenSubtypes(llines, [ + [ + ('x', {subtypes.NONE}), + ('[', {subtypes.SUBSCRIPT_BRACKET}), + ('0', {subtypes.NONE}), + (':', {subtypes.SUBSCRIPT_COLON}), + ('42', {subtypes.NONE}), + (':', {subtypes.SUBSCRIPT_COLON}), + ('1', {subtypes.NONE}), + (']', {subtypes.SUBSCRIPT_BRACKET}), + ], + ]) def testFunctionCallWithStarExpression(self): - code = textwrap.dedent("""\ + code = textwrap.dedent("""\ [a, *b] """) llines = yapf_test_helper.ParseAndUnwrap(code) - self._CheckFormatTokenSubtypes( - llines, [ - [ - ('[', {subtypes.NONE}), - ('a', {subtypes.NONE}), - (',', {subtypes.NONE}), - ('*', { - subtypes.UNARY_OPERATOR, - subtypes.VARARGS_STAR, - }), - ('b', {subtypes.NONE}), - (']', {subtypes.NONE}), - ], - ]) + self._CheckFormatTokenSubtypes(llines, [ + [ + ('[', {subtypes.NONE}), + ('a', {subtypes.NONE}), + (',', {subtypes.NONE}), + ('*', { + subtypes.UNARY_OPERATOR, + subtypes.VARARGS_STAR, + }), + ('b', {subtypes.NONE}), + (']', {subtypes.NONE}), + ], + ]) if __name__ == '__main__': diff --git a/yapftests/utils.py b/yapftests/utils.py index d10a0982c..268b8c43a 100644 --- a/yapftests/utils.py +++ b/yapftests/utils.py @@ -42,16 +42,15 @@ def stdout_redirector(stream): # pylint: disable=invalid-name # Note: `buffering` is set to -1 despite documentation of NamedTemporaryFile # says None. This is probably a problem with the python documentation. @contextlib.contextmanager -def NamedTempFile( - mode='w+b', - buffering=-1, - encoding=None, - errors=None, - newline=None, - suffix=None, - prefix=None, - dirname=None, - text=False): +def NamedTempFile(mode='w+b', + buffering=-1, + encoding=None, + errors=None, + newline=None, + suffix=None, + prefix=None, + dirname=None, + text=False): """Context manager creating a new temporary file in text mode.""" if sys.version_info < (3, 5): # covers also python 2 if suffix is None: @@ -73,11 +72,18 @@ def NamedTempFile( @contextlib.contextmanager -def TempFileContents( - dirname, contents, encoding='utf-8', newline='', suffix=None): +def TempFileContents(dirname, + contents, + encoding='utf-8', + newline='', + suffix=None): # Note: NamedTempFile properly handles unicode encoding when using mode='w' - with NamedTempFile(dirname=dirname, mode='w', encoding=encoding, - newline=newline, suffix=suffix) as (f, fname): + with NamedTempFile( + dirname=dirname, + mode='w', + encoding=encoding, + newline=newline, + suffix=suffix) as (f, fname): f.write(contents) f.flush() yield fname diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 865a67e3b..2330f4e18 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -54,11 +54,10 @@ def testSimple(self): self._Check(unformatted_code, unformatted_code) def testNoEndingNewline(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ if True: pass""") - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if True: pass """) @@ -66,7 +65,7 @@ def testNoEndingNewline(self): @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testPrintAfterPeriod(self): - unformatted_code = textwrap.dedent("""a.print\n""") + unformatted_code = textwrap.dedent("""a.print\n""") expected_formatted_code = textwrap.dedent("""a.print\n""") self._Check(unformatted_code, expected_formatted_code) @@ -81,7 +80,7 @@ def tearDown(self): # pylint: disable=g-missing-super-call def assertCodeEqual(self, expected_code, code): if code != expected_code: - msg = 'Code format mismatch:\n' + msg = 'Code format mismatch:\n' msg += 'Expected:\n >' msg += '\n > '.join(expected_code.splitlines()) msg += '\nActual:\n >' @@ -90,18 +89,15 @@ def assertCodeEqual(self, expected_code, code): self.fail(msg) def testFormatFile(self): - unformatted_code = textwrap.dedent( - u"""\ + unformatted_code = textwrap.dedent(u"""\ if True: pass """) - expected_formatted_code_pep8 = textwrap.dedent( - u"""\ + expected_formatted_code_pep8 = textwrap.dedent(u"""\ if True: pass """) - expected_formatted_code_yapf = textwrap.dedent( - u"""\ + expected_formatted_code_yapf = textwrap.dedent(u"""\ if True: pass """) @@ -113,8 +109,7 @@ def testFormatFile(self): self.assertCodeEqual(expected_formatted_code_yapf, formatted_code) def testDisableLinesPattern(self): - unformatted_code = textwrap.dedent( - u"""\ + unformatted_code = textwrap.dedent(u"""\ if a: b # yapf: disable @@ -122,8 +117,7 @@ def testDisableLinesPattern(self): if h: i """) - expected_formatted_code = textwrap.dedent( - u"""\ + expected_formatted_code = textwrap.dedent(u"""\ if a: b # yapf: disable @@ -136,8 +130,7 @@ def testDisableLinesPattern(self): self.assertCodeEqual(expected_formatted_code, formatted_code) def testDisableAndReenableLinesPattern(self): - unformatted_code = textwrap.dedent( - u"""\ + unformatted_code = textwrap.dedent(u"""\ if a: b # yapf: disable @@ -146,8 +139,7 @@ def testDisableAndReenableLinesPattern(self): if h: i """) - expected_formatted_code = textwrap.dedent( - u"""\ + expected_formatted_code = textwrap.dedent(u"""\ if a: b # yapf: disable @@ -161,8 +153,7 @@ def testDisableAndReenableLinesPattern(self): self.assertCodeEqual(expected_formatted_code, formatted_code) def testDisablePartOfMultilineComment(self): - unformatted_code = textwrap.dedent( - u"""\ + unformatted_code = textwrap.dedent(u"""\ if a: b # This is a multiline comment that disables YAPF. @@ -174,8 +165,7 @@ def testDisablePartOfMultilineComment(self): if h: i """) - expected_formatted_code = textwrap.dedent( - u"""\ + expected_formatted_code = textwrap.dedent(u"""\ if a: b # This is a multiline comment that disables YAPF. @@ -190,8 +180,7 @@ def testDisablePartOfMultilineComment(self): formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(expected_formatted_code, formatted_code) - code = textwrap.dedent( - u"""\ + code = textwrap.dedent(u"""\ def foo_function(): # some comment # yapf: disable @@ -208,8 +197,7 @@ def foo_function(): self.assertCodeEqual(code, formatted_code) def testEnabledDisabledSameComment(self): - code = textwrap.dedent( - u"""\ + code = textwrap.dedent(u"""\ # yapf: disable a(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, ccccccccccccccccccccccccccccccc, ddddddddddddddddddddddd, eeeeeeeeeeeeeeeeeeeeeeeeeee) # yapf: enable @@ -222,24 +210,21 @@ def testEnabledDisabledSameComment(self): self.assertCodeEqual(code, formatted_code) def testFormatFileLinesSelection(self): - unformatted_code = textwrap.dedent( - u"""\ + unformatted_code = textwrap.dedent(u"""\ if a: b if f: g if h: i """) - expected_formatted_code_lines1and2 = textwrap.dedent( - u"""\ + expected_formatted_code_lines1and2 = textwrap.dedent(u"""\ if a: b if f: g if h: i """) - expected_formatted_code_lines3 = textwrap.dedent( - u"""\ + expected_formatted_code_lines3 = textwrap.dedent(u"""\ if a: b if f: g @@ -255,8 +240,7 @@ def testFormatFileLinesSelection(self): self.assertCodeEqual(expected_formatted_code_lines3, formatted_code) def testFormatFileDiff(self): - unformatted_code = textwrap.dedent( - u"""\ + unformatted_code = textwrap.dedent(u"""\ if True: pass """) @@ -266,7 +250,7 @@ def testFormatFileDiff(self): def testFormatFileInPlace(self): unformatted_code = u'True==False\n' - formatted_code = u'True == False\n' + formatted_code = u'True == False\n' with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: result, _, _ = yapf_api.FormatFile(filepath, in_place=True) self.assertEqual(result, None) @@ -284,19 +268,17 @@ def testFormatFileInPlace(self): print_diff=True) def testNoFile(self): - stream = py3compat.StringIO() + stream = py3compat.StringIO() handler = logging.StreamHandler(stream) - logger = logging.getLogger('mylogger') + logger = logging.getLogger('mylogger') logger.addHandler(handler) self.assertRaises( IOError, yapf_api.FormatFile, 'not_a_file.py', logger=logger.error) - self.assertEqual( - stream.getvalue(), - "[Errno 2] No such file or directory: 'not_a_file.py'\n") + self.assertEqual(stream.getvalue(), + "[Errno 2] No such file or directory: 'not_a_file.py'\n") def testCommentsUnformatted(self): - code = textwrap.dedent( - u"""\ + code = textwrap.dedent(u"""\ foo = [# A list of things # bork 'one', @@ -308,8 +290,7 @@ def testCommentsUnformatted(self): self.assertCodeEqual(code, formatted_code) def testDisabledHorizontalFormattingOnNewLine(self): - code = textwrap.dedent( - u"""\ + code = textwrap.dedent(u"""\ # yapf: disable a = [ 1] @@ -320,14 +301,12 @@ def testDisabledHorizontalFormattingOnNewLine(self): self.assertCodeEqual(code, formatted_code) def testSplittingSemicolonStatements(self): - unformatted_code = textwrap.dedent( - u"""\ + unformatted_code = textwrap.dedent(u"""\ def f(): x = y + 42 ; z = n * 42 if True: a += 1 ; b += 1; c += 1 """) - expected_formatted_code = textwrap.dedent( - u"""\ + expected_formatted_code = textwrap.dedent(u"""\ def f(): x = y + 42 z = n * 42 @@ -341,14 +320,12 @@ def f(): self.assertCodeEqual(expected_formatted_code, formatted_code) def testSemicolonStatementsDisabled(self): - unformatted_code = textwrap.dedent( - u"""\ + unformatted_code = textwrap.dedent(u"""\ def f(): x = y + 42 ; z = n * 42 # yapf: disable if True: a += 1 ; b += 1; c += 1 """) - expected_formatted_code = textwrap.dedent( - u"""\ + expected_formatted_code = textwrap.dedent(u"""\ def f(): x = y + 42 ; z = n * 42 # yapf: disable if True: @@ -361,8 +338,7 @@ def f(): self.assertCodeEqual(expected_formatted_code, formatted_code) def testDisabledSemiColonSeparatedStatements(self): - code = textwrap.dedent( - u"""\ + code = textwrap.dedent(u"""\ # yapf: disable if True: a ; b """) @@ -371,8 +347,7 @@ def testDisabledSemiColonSeparatedStatements(self): self.assertCodeEqual(code, formatted_code) def testDisabledMultilineStringInDictionary(self): - code = textwrap.dedent( - u"""\ + code = textwrap.dedent(u"""\ # yapf: disable A = [ @@ -391,8 +366,7 @@ def testDisabledMultilineStringInDictionary(self): self.assertCodeEqual(code, formatted_code) def testDisabledWithPrecedingText(self): - code = textwrap.dedent( - u"""\ + code = textwrap.dedent(u"""\ # TODO(fix formatting): yapf: disable A = [ @@ -428,8 +402,11 @@ def setUpClass(cls): # pylint: disable=g-missing-super-call def tearDownClass(cls): # pylint: disable=g-missing-super-call shutil.rmtree(cls.test_tmpdir) - def assertYapfReformats( - self, unformatted, expected, extra_options=None, env=None): + def assertYapfReformats(self, + unformatted, + expected, + extra_options=None, + env=None): """Check that yapf reformats the given code as expected. Invokes yapf in a subprocess, piping the unformatted code into its stdin. @@ -442,7 +419,7 @@ def assertYapfReformats( env: dict of environment variables. """ cmdline = YAPF_BINARY + (extra_options or []) - p = subprocess.Popen( + p = subprocess.Popen( cmdline, stdout=subprocess.PIPE, stdin=subprocess.PIPE, @@ -455,30 +432,27 @@ def assertYapfReformats( @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testUnicodeEncodingPipedToFile(self): - unformatted_code = textwrap.dedent( - u"""\ + unformatted_code = textwrap.dedent(u"""\ def foo(): print('⇒') """) - with utils.NamedTempFile(dirname=self.test_tmpdir, - suffix='.py') as (out, _): - with utils.TempFileContents(self.test_tmpdir, unformatted_code, - suffix='.py') as filepath: + with utils.NamedTempFile( + dirname=self.test_tmpdir, suffix='.py') as (out, _): + with utils.TempFileContents( + self.test_tmpdir, unformatted_code, suffix='.py') as filepath: subprocess.check_call(YAPF_BINARY + ['--diff', filepath], stdout=out) def testInPlaceReformatting(self): - unformatted_code = textwrap.dedent( - u"""\ + unformatted_code = textwrap.dedent(u"""\ def foo(): x = 37 """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo(): x = 37 """) - with utils.TempFileContents(self.test_tmpdir, unformatted_code, - suffix='.py') as filepath: + with utils.TempFileContents( + self.test_tmpdir, unformatted_code, suffix='.py') as filepath: p = subprocess.Popen(YAPF_BINARY + ['--in-place', filepath]) p.wait() with io.open(filepath, mode='r', newline='') as fd: @@ -486,10 +460,10 @@ def foo(): self.assertEqual(reformatted_code, expected_formatted_code) def testInPlaceReformattingBlank(self): - unformatted_code = u'\n\n' + unformatted_code = u'\n\n' expected_formatted_code = u'\n' - with utils.TempFileContents(self.test_tmpdir, unformatted_code, - suffix='.py') as filepath: + with utils.TempFileContents( + self.test_tmpdir, unformatted_code, suffix='.py') as filepath: p = subprocess.Popen(YAPF_BINARY + ['--in-place', filepath]) p.wait() with io.open(filepath, mode='r', encoding='utf-8', newline='') as fd: @@ -497,10 +471,10 @@ def testInPlaceReformattingBlank(self): self.assertEqual(reformatted_code, expected_formatted_code) def testInPlaceReformattingEmpty(self): - unformatted_code = u'' + unformatted_code = u'' expected_formatted_code = u'' - with utils.TempFileContents(self.test_tmpdir, unformatted_code, - suffix='.py') as filepath: + with utils.TempFileContents( + self.test_tmpdir, unformatted_code, suffix='.py') as filepath: p = subprocess.Popen(YAPF_BINARY + ['--in-place', filepath]) p.wait() with io.open(filepath, mode='r', encoding='utf-8', newline='') as fd: @@ -508,37 +482,31 @@ def testInPlaceReformattingEmpty(self): self.assertEqual(reformatted_code, expected_formatted_code) def testReadFromStdin(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo(): x = 37 """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo(): x = 37 """) self.assertYapfReformats(unformatted_code, expected_formatted_code) def testReadFromStdinWithEscapedStrings(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ s = "foo\\nbar" """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ s = "foo\\nbar" """) self.assertYapfReformats(unformatted_code, expected_formatted_code) def testSetYapfStyle(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo(): # trail x = 37 """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo(): # trail x = 37 """) @@ -548,18 +516,15 @@ def foo(): # trail extra_options=['--style=yapf']) def testSetCustomStyleBasedOnYapf(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo(): # trail x = 37 """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo(): # trail x = 37 """) - style_file = textwrap.dedent( - u'''\ + style_file = textwrap.dedent(u'''\ [style] based_on_style = yapf spaces_before_comment = 4 @@ -571,18 +536,15 @@ def foo(): # trail extra_options=['--style={0}'.format(stylepath)]) def testSetCustomStyleSpacesBeforeComment(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ a_very_long_statement_that_extends_way_beyond # Comment short # This is a shorter statement """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ a_very_long_statement_that_extends_way_beyond # Comment short # This is a shorter statement """) # noqa - style_file = textwrap.dedent( - u'''\ + style_file = textwrap.dedent(u'''\ [style] spaces_before_comment = 15, 20 ''') @@ -593,28 +555,26 @@ def testSetCustomStyleSpacesBeforeComment(self): extra_options=['--style={0}'.format(stylepath)]) def testReadSingleLineCodeFromStdin(self): - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ if True: pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if True: pass """) self.assertYapfReformats(unformatted_code, expected_formatted_code) def testEncodingVerification(self): - unformatted_code = textwrap.dedent( - u"""\ + unformatted_code = textwrap.dedent(u"""\ '''The module docstring.''' # -*- coding: utf-8 -*- def f(): x = 37 """) - with utils.NamedTempFile(suffix='.py', - dirname=self.test_tmpdir) as (out, _): - with utils.TempFileContents(self.test_tmpdir, unformatted_code, - suffix='.py') as filepath: + with utils.NamedTempFile( + suffix='.py', dirname=self.test_tmpdir) as (out, _): + with utils.TempFileContents( + self.test_tmpdir, unformatted_code, suffix='.py') as filepath: try: subprocess.check_call(YAPF_BINARY + ['--diff', filepath], stdout=out) except subprocess.CalledProcessError as e: @@ -622,8 +582,7 @@ def f(): self.assertEqual(e.returncode, 1) # pylint: disable=g-assert-in-except # noqa def testReformattingSpecificLines(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass @@ -633,8 +592,7 @@ def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -654,16 +612,14 @@ def g(): extra_options=['--lines', '1-2']) def testOmitFormattingLinesBeforeDisabledFunctionComment(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ import sys # Comment def some_func(x): x = ["badly" , "formatted","line" ] """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ import sys # Comment @@ -676,8 +632,7 @@ def some_func(x): extra_options=['--lines', '5-5']) def testReformattingSkippingLines(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass @@ -688,8 +643,7 @@ def g(): pass # yapf: enable """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -705,8 +659,7 @@ def g(): self.assertYapfReformats(unformatted_code, expected_formatted_code) def testReformattingSkippingToEndOfFile(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass @@ -723,8 +676,7 @@ def e(): 'bbbbbbb'): pass """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -746,8 +698,7 @@ def e(): self.assertYapfReformats(unformatted_code, expected_formatted_code) def testReformattingSkippingSingleLine(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass @@ -756,8 +707,7 @@ def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): # yapf: disable pass """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -771,15 +721,13 @@ def g(): self.assertYapfReformats(unformatted_code, expected_formatted_code) def testDisableWholeDataStructure(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ A = set([ 'hello', 'world', ]) # yapf: disable """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ A = set([ 'hello', 'world', @@ -788,16 +736,14 @@ def testDisableWholeDataStructure(self): self.assertYapfReformats(unformatted_code, expected_formatted_code) def testDisableButAdjustIndentations(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class SplitPenaltyTest(unittest.TestCase): def testUnbreakable(self): self._CheckPenalties(tree, [ ]) # yapf: disable """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class SplitPenaltyTest(unittest.TestCase): def testUnbreakable(self): @@ -807,8 +753,7 @@ def testUnbreakable(self): self.assertYapfReformats(unformatted_code, expected_formatted_code) def testRetainingHorizontalWhitespace(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass @@ -817,8 +762,7 @@ def g(): if (xxxxxxxxxxxx.yyyyyyyy (zzzzzzzzzzzzz [0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): # yapf: disable pass """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -832,8 +776,7 @@ def g(): self.assertYapfReformats(unformatted_code, expected_formatted_code) def testRetainingVerticalWhitespace(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass @@ -845,8 +788,7 @@ def g(): pass """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): @@ -864,8 +806,7 @@ def g(): expected_formatted_code, extra_options=['--lines', '1-2']) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if a: b @@ -882,8 +823,7 @@ def g(): # trailing whitespace """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if a: b @@ -903,8 +843,7 @@ def g(): expected_formatted_code, extra_options=['--lines', '3-3', '--lines', '13-13']) - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ ''' docstring @@ -917,7 +856,7 @@ def g(): unformatted_code, unformatted_code, extra_options=['--lines', '2-2']) def testVerticalSpacingWithCommentWithContinuationMarkers(self): - unformatted_code = """\ + unformatted_code = """\ # \\ # \\ # \\ @@ -939,15 +878,13 @@ def testVerticalSpacingWithCommentWithContinuationMarkers(self): extra_options=['--lines', '1-1']) def testRetainingSemicolonsWhenSpecifyingLines(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ a = line_to_format def f(): x = y + 42; z = n * 42 if True: a += 1 ; b += 1 ; c += 1 """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ a = line_to_format def f(): x = y + 42; z = n * 42 @@ -959,8 +896,7 @@ def f(): extra_options=['--lines', '1-1']) def testDisabledMultilineStrings(self): - unformatted_code = textwrap.dedent( - '''\ + unformatted_code = textwrap.dedent('''\ foo=42 def f(): email_text += """This is a really long docstring that goes over the column limit and is multi-line.

@@ -970,8 +906,7 @@ def f(): """ ''') # noqa - expected_formatted_code = textwrap.dedent( - '''\ + expected_formatted_code = textwrap.dedent('''\ foo = 42 def f(): email_text += """This is a really long docstring that goes over the column limit and is multi-line.

@@ -987,8 +922,7 @@ def f(): extra_options=['--lines', '1-1']) def testDisableWhenSpecifyingLines(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ # yapf: disable A = set([ 'hello', @@ -1000,8 +934,7 @@ def testDisableWhenSpecifyingLines(self): 'world', ]) # yapf: disable """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ # yapf: disable A = set([ 'hello', @@ -1019,8 +952,7 @@ def testDisableWhenSpecifyingLines(self): extra_options=['--lines', '1-10']) def testDisableFormattingInDataLiteral(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def horrible(): oh_god() why_would_you() @@ -1039,8 +971,7 @@ def still_horrible(): 'that' ] """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def horrible(): oh_god() why_would_you() @@ -1061,8 +992,7 @@ def still_horrible(): extra_options=['--lines', '14-15']) def testRetainVerticalFormattingBetweenDisabledAndEnabledLines(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class A(object): def aaaaaaaaaaaaa(self): c = bbbbbbbbb.ccccccccc('challenge', 0, 1, 10) @@ -1073,8 +1003,7 @@ def aaaaaaaaaaaaa(self): gggggggggggg.hhhhhhhhh(c, c.ffffffffffff)) iiiii = jjjjjjjjjjjjjj.iiiii """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class A(object): def aaaaaaaaaaaaa(self): c = bbbbbbbbb.ccccccccc('challenge', 0, 1, 10) @@ -1089,8 +1018,7 @@ def aaaaaaaaaaaaa(self): extra_options=['--lines', '4-7']) def testRetainVerticalFormattingBetweenDisabledLines(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class A(object): def aaaaaaaaaaaaa(self): pass @@ -1099,8 +1027,7 @@ def aaaaaaaaaaaaa(self): def bbbbbbbbbbbbb(self): # 5 pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class A(object): def aaaaaaaaaaaaa(self): pass @@ -1115,8 +1042,7 @@ def bbbbbbbbbbbbb(self): # 5 extra_options=['--lines', '4-4']) def testFormatLinesSpecifiedInMiddleOfExpression(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ class A(object): def aaaaaaaaaaaaa(self): c = bbbbbbbbb.ccccccccc('challenge', 0, 1, 10) @@ -1127,8 +1053,7 @@ def aaaaaaaaaaaaa(self): gggggggggggg.hhhhhhhhh(c, c.ffffffffffff)) iiiii = jjjjjjjjjjjjjj.iiiii """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ class A(object): def aaaaaaaaaaaaa(self): c = bbbbbbbbb.ccccccccc('challenge', 0, 1, 10) @@ -1143,8 +1068,7 @@ def aaaaaaaaaaaaa(self): extra_options=['--lines', '5-6']) def testCommentFollowingMultilineString(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo(): '''First line. Second line. @@ -1152,8 +1076,7 @@ def foo(): x = '''hello world''' # second comment return 42 # another comment """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo(): '''First line. Second line. @@ -1168,14 +1091,12 @@ def foo(): def testDedentClosingBracket(self): # no line-break on the first argument, not dedenting closing brackets - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def overly_long_function_name(first_argument_on_the_same_line, second_argument_makes_the_line_too_long): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def overly_long_function_name(first_argument_on_the_same_line, second_argument_makes_the_line_too_long): pass @@ -1193,8 +1114,7 @@ def overly_long_function_name(first_argument_on_the_same_line, # extra_options=['--style=facebook']) # line-break before the first argument, dedenting closing brackets if set - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def overly_long_function_name( first_argument_on_the_same_line, second_argument_makes_the_line_too_long): @@ -1206,8 +1126,7 @@ def overly_long_function_name( # second_argument_makes_the_line_too_long): # pass # """) - expected_formatted_fb_code = textwrap.dedent( - """\ + expected_formatted_fb_code = textwrap.dedent("""\ def overly_long_function_name( first_argument_on_the_same_line, second_argument_makes_the_line_too_long ): @@ -1225,16 +1144,14 @@ def overly_long_function_name( # extra_options=['--style=pep8']) def testCoalesceBrackets(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ some_long_function_name_foo( { 'first_argument_of_the_thing': id, 'second_argument_of_the_thing': "some thing" } )""") - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ some_long_function_name_foo({ 'first_argument_of_the_thing': id, 'second_argument_of_the_thing': "some thing" @@ -1242,8 +1159,7 @@ def testCoalesceBrackets(self): """) with utils.NamedTempFile(dirname=self.test_tmpdir, mode='w') as (f, name): f.write( - textwrap.dedent( - u'''\ + textwrap.dedent(u'''\ [style] column_limit=82 coalesce_brackets = True @@ -1255,14 +1171,12 @@ def testCoalesceBrackets(self): extra_options=['--style={0}'.format(name)]) def testPseudoParenSpaces(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo(): def bar(): return {msg_id: author for author, msg_id in reader} """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo(): def bar(): return {msg_id: author for author, msg_id in reader} @@ -1273,8 +1187,7 @@ def bar(): extra_options=['--lines', '1-1', '--style', 'yapf']) def testMultilineCommentFormattingDisabled(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ # This is a comment FOO = { aaaaaaaa.ZZZ: [ @@ -1288,8 +1201,7 @@ def testMultilineCommentFormattingDisabled(self): '#': lambda x: x # do nothing } """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ # This is a comment FOO = { aaaaaaaa.ZZZ: [ @@ -1309,16 +1221,14 @@ def testMultilineCommentFormattingDisabled(self): extra_options=['--lines', '1-1', '--style', 'yapf']) def testTrailingCommentsWithDisabledFormatting(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ import os SCOPES = [ 'hello world' # This is a comment. ] """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ import os SCOPES = [ @@ -1331,7 +1241,7 @@ def testTrailingCommentsWithDisabledFormatting(self): extra_options=['--lines', '1-1', '--style', 'yapf']) def testUseTabs(self): - unformatted_code = """\ + unformatted_code = """\ def foo_function(): if True: pass @@ -1341,7 +1251,7 @@ def foo_function(): if True: pass """ # noqa: W191,E101 - style_contents = u"""\ + style_contents = u"""\ [style] based_on_style = yapf USE_TABS = true @@ -1354,7 +1264,7 @@ def foo_function(): extra_options=['--style={0}'.format(stylepath)]) def testUseTabsWith(self): - unformatted_code = """\ + unformatted_code = """\ def f(): return ['hello', 'world',] """ @@ -1365,7 +1275,7 @@ def f(): 'world', ] """ # noqa: W191,E101 - style_contents = u"""\ + style_contents = u"""\ [style] based_on_style = yapf USE_TABS = true @@ -1378,7 +1288,7 @@ def f(): extra_options=['--style={0}'.format(stylepath)]) def testUseTabsContinuationAlignStyleFixed(self): - unformatted_code = """\ + unformatted_code = """\ def foo_function(arg1, arg2, arg3): return ['hello', 'world',] """ @@ -1390,7 +1300,7 @@ def foo_function( 'world', ] """ # noqa: W191,E101 - style_contents = u"""\ + style_contents = u"""\ [style] based_on_style = yapf USE_TABS = true @@ -1406,7 +1316,7 @@ def foo_function( extra_options=['--style={0}'.format(stylepath)]) def testUseTabsContinuationAlignStyleVAlignRight(self): - unformatted_code = """\ + unformatted_code = """\ def foo_function(arg1, arg2, arg3): return ['hello', 'world',] """ @@ -1418,7 +1328,7 @@ def foo_function(arg1, arg2, 'world', ] """ # noqa: W191,E101 - style_contents = u"""\ + style_contents = u"""\ [style] based_on_style = yapf USE_TABS = true @@ -1434,7 +1344,7 @@ def foo_function(arg1, arg2, extra_options=['--style={0}'.format(stylepath)]) def testUseSpacesContinuationAlignStyleFixed(self): - unformatted_code = """\ + unformatted_code = """\ def foo_function(arg1, arg2, arg3): return ['hello', 'world',] """ @@ -1446,7 +1356,7 @@ def foo_function( 'world', ] """ - style_contents = u"""\ + style_contents = u"""\ [style] based_on_style = yapf COLUMN_LIMIT=32 @@ -1461,7 +1371,7 @@ def foo_function( extra_options=['--style={0}'.format(stylepath)]) def testUseSpacesContinuationAlignStyleVAlignRight(self): - unformatted_code = """\ + unformatted_code = """\ def foo_function(arg1, arg2, arg3): return ['hello', 'world',] """ @@ -1473,7 +1383,7 @@ def foo_function(arg1, arg2, 'world', ] """ - style_contents = u"""\ + style_contents = u"""\ [style] based_on_style = yapf COLUMN_LIMIT=32 @@ -1488,13 +1398,11 @@ def foo_function(arg1, arg2, extra_options=['--style={0}'.format(stylepath)]) def testStyleOutputRoundTrip(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def foo_function(): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def foo_function(): pass """) @@ -1514,8 +1422,7 @@ def foo_function(): extra_options=['--style={0}'.format(stylepath)]) def testSpacingBeforeComments(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ A = 42 @@ -1525,8 +1432,7 @@ def x(): def _(): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ A = 42 @@ -1542,8 +1448,7 @@ def _(): extra_options=['--lines', '1-2']) def testSpacingBeforeCommentsInDicts(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ A=42 X = { @@ -1558,8 +1463,7 @@ def testSpacingBeforeCommentsInDicts(self): 'BROKEN' } """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ A = 42 X = { @@ -1580,8 +1484,7 @@ def testSpacingBeforeCommentsInDicts(self): extra_options=['--style', 'yapf', '--lines', '1-1']) def testDisableWithLinesOption(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ # yapf_lines_bug.py # yapf: disable def outer_func(): @@ -1590,8 +1493,7 @@ def inner_func(): return # yapf: enable """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ # yapf_lines_bug.py # yapf: disable def outer_func(): @@ -1607,7 +1509,7 @@ def inner_func(): @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testNoSpacesAroundBinaryOperators(self): - unformatted_code = """\ + unformatted_code = """\ a = 4-b/c@d**37 """ expected_formatted_code = """\ @@ -1624,7 +1526,7 @@ def testNoSpacesAroundBinaryOperators(self): @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') def testCP936Encoding(self): - unformatted_code = 'print("äž­æ–‡")\n' + unformatted_code = 'print("äž­æ–‡")\n' expected_formatted_code = 'print("äž­æ–‡")\n' self.assertYapfReformats( unformatted_code, @@ -1632,7 +1534,7 @@ def testCP936Encoding(self): env={'PYTHONIOENCODING': 'cp936'}) def testDisableWithLineRanges(self): - unformatted_code = """\ + unformatted_code = """\ # yapf: disable a = [ 1, @@ -1672,8 +1574,8 @@ class DiffIndentTest(unittest.TestCase): @staticmethod def _OwnStyle(): - my_style = style.CreatePEP8Style() - my_style['INDENT_WIDTH'] = 3 + my_style = style.CreatePEP8Style() + my_style['INDENT_WIDTH'] = 3 my_style['CONTINUATION_INDENT_WIDTH'] = 3 return my_style @@ -1683,13 +1585,11 @@ def _Check(self, unformatted_code, expected_formatted_code): self.assertEqual(expected_formatted_code, formatted_code) def testSimple(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ for i in range(5): print('bar') """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ for i in range(5): print('bar') """) @@ -1700,7 +1600,7 @@ class HorizontallyAlignedTrailingCommentsTest(yapf_test_helper.YAPFTest): @staticmethod def _OwnStyle(): - my_style = style.CreatePEP8Style() + my_style = style.CreatePEP8Style() my_style['SPACES_BEFORE_COMMENT'] = [ 15, 25, @@ -1714,8 +1614,7 @@ def _Check(self, unformatted_code, expected_formatted_code): self.assertCodeEqual(expected_formatted_code, formatted_code) def testSimple(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ foo = '1' # Aligned at first list value foo = '2__<15>' # Aligned at second list value @@ -1724,8 +1623,7 @@ def testSimple(self): foo = '4______________________<35>' # Aligned beyond list values """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ foo = '1' # Aligned at first list value foo = '2__<15>' # Aligned at second list value @@ -1737,8 +1635,7 @@ def testSimple(self): self._Check(unformatted_code, expected_formatted_code) def testBlock(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ func(1) # Line 1 func(2) # Line 2 # Line 3 @@ -1746,8 +1643,7 @@ def testBlock(self): # Line 5 # Line 6 """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ func(1) # Line 1 func(2) # Line 2 # Line 3 @@ -1758,8 +1654,7 @@ def testBlock(self): self._Check(unformatted_code, expected_formatted_code) def testBlockWithLongLine(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ func(1) # Line 1 func___________________(2) # Line 2 # Line 3 @@ -1767,8 +1662,7 @@ def testBlockWithLongLine(self): # Line 5 # Line 6 """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ func(1) # Line 1 func___________________(2) # Line 2 # Line 3 @@ -1779,8 +1673,7 @@ def testBlockWithLongLine(self): self._Check(unformatted_code, expected_formatted_code) def testBlockFuncSuffix(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ func(1) # Line 1 func(2) # Line 2 # Line 3 @@ -1791,8 +1684,7 @@ def testBlockFuncSuffix(self): def Func(): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ func(1) # Line 1 func(2) # Line 2 # Line 3 @@ -1807,8 +1699,7 @@ def Func(): self._Check(unformatted_code, expected_formatted_code) def testBlockCommentSuffix(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ func(1) # Line 1 func(2) # Line 2 # Line 3 @@ -1818,8 +1709,7 @@ def testBlockCommentSuffix(self): # Aligned with prev comment block """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ func(1) # Line 1 func(2) # Line 2 # Line 3 @@ -1832,8 +1722,7 @@ def testBlockCommentSuffix(self): self._Check(unformatted_code, expected_formatted_code) def testBlockIndentedFuncSuffix(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if True: func(1) # Line 1 func(2) # Line 2 @@ -1847,8 +1736,7 @@ def testBlockIndentedFuncSuffix(self): def Func(): pass """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if True: func(1) # Line 1 func(2) # Line 2 @@ -1867,8 +1755,7 @@ def Func(): self._Check(unformatted_code, expected_formatted_code) def testBlockIndentedCommentSuffix(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if True: func(1) # Line 1 func(2) # Line 2 @@ -1879,8 +1766,7 @@ def testBlockIndentedCommentSuffix(self): # Not aligned """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if True: func(1) # Line 1 func(2) # Line 2 @@ -1894,8 +1780,7 @@ def testBlockIndentedCommentSuffix(self): self._Check(unformatted_code, expected_formatted_code) def testBlockMultiIndented(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ if True: if True: if True: @@ -1908,8 +1793,7 @@ def testBlockMultiIndented(self): # Not aligned """) # noqa - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ if True: if True: if True: @@ -1925,8 +1809,7 @@ def testBlockMultiIndented(self): self._Check(unformatted_code, expected_formatted_code) def testArgs(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ def MyFunc( arg1, # Desc 1 arg2, # Desc 2 @@ -1937,8 +1820,7 @@ def MyFunc( ): pass """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ def MyFunc( arg1, # Desc 1 arg2, # Desc 2 @@ -1952,8 +1834,7 @@ def MyFunc( self._Check(unformatted_code, expected_formatted_code) def testDisableBlock(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ a() # comment 1 b() # comment 2 @@ -1965,8 +1846,7 @@ def testDisableBlock(self): e() # comment 5 f() # comment 6 """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ a() # comment 1 b() # comment 2 @@ -1981,15 +1861,13 @@ def testDisableBlock(self): self._Check(unformatted_code, expected_formatted_code) def testDisabledLine(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ short # comment 1 do_not_touch1 # yapf: disable do_not_touch2 # yapf: disable a_longer_statement # comment 2 """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ short # comment 1 do_not_touch1 # yapf: disable do_not_touch2 # yapf: disable @@ -2002,9 +1880,9 @@ class _SpacesAroundDictListTupleTestImpl(unittest.TestCase): @staticmethod def _OwnStyle(): - my_style = style.CreatePEP8Style() - my_style['DISABLE_ENDING_COMMA_HEURISTIC'] = True - my_style['SPLIT_ALL_COMMA_SEPARATED_VALUES'] = False + my_style = style.CreatePEP8Style() + my_style['DISABLE_ENDING_COMMA_HEURISTIC'] = True + my_style['SPLIT_ALL_COMMA_SEPARATED_VALUES'] = False my_style['SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED'] = False return my_style @@ -2021,14 +1899,13 @@ class SpacesAroundDictTest(_SpacesAroundDictListTupleTestImpl): @classmethod def _OwnStyle(cls): - style = super(SpacesAroundDictTest, cls)._OwnStyle() + style = super(SpacesAroundDictTest, cls)._OwnStyle() style['SPACES_AROUND_DICT_DELIMITERS'] = True return style def testStandard(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ {1 : 2} {k:v for k, v in other.items()} {k for k in [1, 2, 3]} @@ -2045,8 +1922,7 @@ def testStandard(self): [1, 2] (3, 4) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ { 1: 2 } { k: v for k, v in other.items() } { k for k in [1, 2, 3] } @@ -2071,14 +1947,13 @@ class SpacesAroundListTest(_SpacesAroundDictListTupleTestImpl): @classmethod def _OwnStyle(cls): - style = super(SpacesAroundListTest, cls)._OwnStyle() + style = super(SpacesAroundListTest, cls)._OwnStyle() style['SPACES_AROUND_LIST_DELIMITERS'] = True return style def testStandard(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ [a,b,c] [4,5,] [6, [7, 8], 9] @@ -2099,8 +1974,7 @@ def testStandard(self): {a: b} (1, 2) """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ [ a, b, c ] [ 4, 5, ] [ 6, [ 7, 8 ], 9 ] @@ -2129,14 +2003,13 @@ class SpacesAroundTupleTest(_SpacesAroundDictListTupleTestImpl): @classmethod def _OwnStyle(cls): - style = super(SpacesAroundTupleTest, cls)._OwnStyle() + style = super(SpacesAroundTupleTest, cls)._OwnStyle() style['SPACES_AROUND_TUPLE_DELIMITERS'] = True return style def testStandard(self): - unformatted_code = textwrap.dedent( - """\ + unformatted_code = textwrap.dedent("""\ (0, 1) (2, 3) (4, 5, 6,) @@ -2159,8 +2032,7 @@ def testStandard(self): {a: b} [3, 4] """) - expected_formatted_code = textwrap.dedent( - """\ + expected_formatted_code = textwrap.dedent("""\ ( 0, 1 ) ( 2, 3 ) ( 4, 5, 6, ) diff --git a/yapftests/yapf_test_helper.py b/yapftests/yapf_test_helper.py index b95212a8b..cb56ec865 100644 --- a/yapftests/yapf_test_helper.py +++ b/yapftests/yapf_test_helper.py @@ -39,7 +39,7 @@ def __init__(self, *args): def assertCodeEqual(self, expected_code, code): if code != expected_code: - msg = ['Code format mismatch:', 'Expected:'] + msg = ['Code format mismatch:', 'Expected:'] linelen = style.Get('COLUMN_LIMIT') for line in expected_code.splitlines(): if len(line) > linelen: From f756c12ff065333ac4be9d7a490c7e0f3cd180ce Mon Sep 17 00:00:00 2001 From: Xiao Wang Date: Tue, 3 Jan 2023 11:01:27 +0100 Subject: [PATCH 575/719] change the format back to yapf-based 2 --- yapftests/reformatter_basic_test.py | 2 +- yapftests/reformatter_buganizer_test.py | 28 ++++++++++++------------- yapftests/reformatter_facebook_test.py | 2 +- yapftests/reformatter_pep8_test.py | 2 +- yapftests/reformatter_python3_test.py | 2 +- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index f7bb4c5f5..798dbab9a 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -849,7 +849,7 @@ def testNoQueueSeletionInMiddleOfLine(self): # If the queue isn't properly constructed, then a token in the middle of the # line may be selected as the one with least penalty. The tokens after that # one are then splatted at the end of the line with no formatting. - unformatted_code = """\ + unformatted_code = """\ find_symbol(node.type) + "< " + " ".join(find_pattern(n) for n in node.child) + " >" """ # noqa expected_formatted_code = """\ diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index a4089ad03..54a62b588 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -160,7 +160,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB35417079(self): - code = """\ + code = """\ class _(): def _(): @@ -199,7 +199,7 @@ def testB120047670(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB120245013(self): - unformatted_code = """\ + unformatted_code = """\ class Foo(object): def testNoAlertForShortPeriod(self, rutabaga): self.targets[:][streamz_path,self._fillInOtherFields(streamz_path, {streamz_field_of_interest:True})] = series.Counter('1s', '+ 500x10000') @@ -234,7 +234,7 @@ def xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB111764402(self): - unformatted_code = """\ + unformatted_code = """\ x = self.stubs.stub(video_classification_map, 'read_video_classifications', (lambda external_ids, **unused_kwargs: {external_id: self._get_serving_classification('video') for external_id in external_ids})) """ # noqa expected_formatted_code = """\ @@ -287,7 +287,7 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB112651423(self): - unformatted_code = """\ + unformatted_code = """\ def potato(feeditems, browse_use_case=None): for item in turnip: if kumquat: @@ -398,7 +398,7 @@ def testB79462249(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB113210278(self): - unformatted_code = """\ + unformatted_code = """\ def _(): aaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccc(\ eeeeeeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffffffffffffffffffffff.\ @@ -414,7 +414,7 @@ def _(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB77923341(self): - code = """\ + code = """\ def f(): if (aaaaaaaaaaaaaa.bbbbbbbbbbbb.ccccc <= 0 and # pytype: disable=attribute-error ddddddddddd.eeeeeeeee == constants.FFFFFFFFFFFFFF): @@ -488,7 +488,7 @@ def testB65546221(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30500455(self): - unformatted_code = """\ + unformatted_code = """\ INITIAL_SYMTAB = dict([(name, 'exception#' + name) for name in INITIAL_EXCEPTIONS ] * [(name, 'type#' + name) for name in INITIAL_TYPES] + [ (name, 'function#' + name) for name in INITIAL_FUNCTIONS @@ -517,7 +517,7 @@ def f(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB37099651(self): - unformatted_code = """\ + unformatted_code = """\ _MEMCACHE = lazy.MakeLazy( # pylint: disable=g-long-lambda lambda: function.call.mem.clients(FLAGS.some_flag_thingy, default_namespace=_LAZY_MEM_NAMESPACE, allow_pickle=True) @@ -538,7 +538,7 @@ def testB37099651(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB33228502(self): - unformatted_code = """\ + unformatted_code = """\ def _(): success_rate_stream_table = module.Precompute( query_function=module.DefineQueryFunction( @@ -682,7 +682,7 @@ def testB66011084(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB67455376(self): - unformatted_code = """\ + unformatted_code = """\ sponge_ids.extend(invocation.id() for invocation in self._client.GetInvocationsByLabels(labels)) """ # noqa expected_formatted_code = """\ @@ -759,7 +759,7 @@ def testB65176185(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB35210166(self): - unformatted_code = """\ + unformatted_code = """\ def _(): query = ( m.Fetch(n.Raw('monarch.BorgTask', '/proc/container/memory/usage'), { 'borg_user': borguser, 'borg_job': jobname }) @@ -807,7 +807,7 @@ def testB32167774(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB66912275(self): - unformatted_code = """\ + unformatted_code = """\ def _(): with self.assertRaisesRegexp(errors.HttpError, 'Invalid'): patch_op = api_client.forwardingRules().patch( @@ -841,7 +841,7 @@ def _(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB65241516(self): - unformatted_code = """\ + unformatted_code = """\ checkpoint_files = gfile.Glob(os.path.join(TrainTraceDir(unit_key, "*", "*"), embedding_model.CHECKPOINT_FILENAME + "-*")) """ # noqa expected_formatted_code = """\ @@ -2169,7 +2169,7 @@ def main(unused_argv): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB15597568(self): - unformatted_code = """\ + unformatted_code = """\ if True: if True: if True: diff --git a/yapftests/reformatter_facebook_test.py b/yapftests/reformatter_facebook_test.py index 780b42440..c61f32bf5 100644 --- a/yapftests/reformatter_facebook_test.py +++ b/yapftests/reformatter_facebook_test.py @@ -413,7 +413,7 @@ def foo(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testIfStmtClosingBracket(self): - unformatted_code = """\ + unformatted_code = """\ if (isinstance(value , (StopIteration , StopAsyncIteration )) and exc.__cause__ is value_asdfasdfasdfasdfsafsafsafdasfasdfs): return False """ # noqa diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 67ddadc23..acc218d24 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -525,7 +525,7 @@ def testSplitBeforeArithmeticOperators(self): style.CreateStyleFromConfig( '{based_on_style: pep8, split_before_arithmetic_operator: true}')) - unformatted_code = """\ + unformatted_code = """\ def _(): raise ValueError('This is a long message that ends with an argument: ' + str(42)) """ # noqa diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index 81e565326..b5d68e86f 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -285,7 +285,7 @@ def testSplittingArguments(self): if sys.version_info[1] < 5: return - unformatted_code = """\ + unformatted_code = """\ async def open_file(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None): pass From 10c5b0c237c3f6faaf2c526f401bff04ef87d98e Mon Sep 17 00:00:00 2001 From: Alexey Pelykh Date: Wed, 4 Jan 2023 06:26:36 +0100 Subject: [PATCH 576/719] Generated dicts also have keys and values for rules to apply (#1044) --- CHANGELOG | 1 + yapf/pytree/subtype_assigner.py | 19 ++- yapf/yapflib/format_decision_state.py | 2 + yapftests/reformatter_basic_test.py | 22 ++- yapftests/subtype_assigner_test.py | 233 ++++++++++++++++++++++++++ 5 files changed, 270 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8b29032f4..f3ba6e9b3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,7 @@ ### Changes - Moved 'pytree' parsing tools into its own subdirectory. - Add support for Python 3.10. +- Format generated dicts with respect to same rules as regular dicts ### Fixed - Split line before all comparison operators. diff --git a/yapf/pytree/subtype_assigner.py b/yapf/pytree/subtype_assigner.py index dd3ea3d1e..c93d69df2 100644 --- a/yapf/pytree/subtype_assigner.py +++ b/yapf/pytree/subtype_assigner.py @@ -66,20 +66,26 @@ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name for child in node.children: self.Visit(child) - comp_for = False dict_maker = False + def markAsDictSetGenerator(node): + _AppendFirstLeafTokenSubtype(node, subtypes.DICT_SET_GENERATOR) + for child in node.children: + if pytree_utils.NodeName(child) == 'comp_for': + markAsDictSetGenerator(child) + for child in node.children: if pytree_utils.NodeName(child) == 'comp_for': - comp_for = True - _AppendFirstLeafTokenSubtype(child, subtypes.DICT_SET_GENERATOR) + markAsDictSetGenerator(child) elif child.type in (grammar_token.COLON, grammar_token.DOUBLESTAR): dict_maker = True - if not comp_for and dict_maker: + if dict_maker: last_was_colon = False unpacking = False for child in node.children: + if pytree_utils.NodeName(child) == 'comp_for': + break if child.type == grammar_token.DOUBLESTAR: _AppendFirstLeafTokenSubtype(child, subtypes.KWARGS_STAR_STAR) if last_was_colon: @@ -335,7 +341,10 @@ def Visit_comp_for(self, node): # pylint: disable=invalid-name attr = pytree_utils.GetNodeAnnotation(node.parent, pytree_utils.Annotation.SUBTYPE) if not attr or subtypes.COMP_FOR not in attr: - _AppendSubtypeRec(node.parent.children[0], subtypes.COMP_EXPR) + sibling = node.prev_sibling + while sibling: + _AppendSubtypeRec(sibling, subtypes.COMP_EXPR) + sibling = sibling.prev_sibling self.DefaultNodeVisit(node) def Visit_old_comp_for(self, node): # pylint: disable=invalid-name diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index c299d1c85..607f8c5d5 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -1031,6 +1031,8 @@ def DictValueIsContainer(opening, closing): current = opening.next_token.next_token while current and current != closing: + if subtypes.DICT_SET_GENERATOR in current.subtypes: + break if subtypes.DICTIONARY_KEY in current.subtypes: prev = PreviousNonCommentToken(current) if prev.value == ',': diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 657d1e246..935c7c311 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1624,6 +1624,18 @@ def testDictSetGenerator(self): llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) + unformatted_code = textwrap.dedent("""\ + foo = { + x: x + for x in fnord + } + """) # noqa + expected_code = textwrap.dedent("""\ + foo = {x: x for x in fnord} + """) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) + def testUnaryOpInDictionaryValue(self): code = textwrap.dedent("""\ beta = "123" @@ -3123,8 +3135,10 @@ def testForceMultilineDict_True(self): try: style.SetGlobalStyle( style.CreateStyleFromConfig('{force_multiline_dict: true}')) - unformatted_code = textwrap.dedent( - "responseDict = {'childDict': {'spam': 'eggs'}}\n") + unformatted_code = textwrap.dedent("""\ + responseDict = {'childDict': {'spam': 'eggs'}} + generatedDict = {x: x for x in 'value'} + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) actual = reformatter.Reformat(llines) expected = textwrap.dedent("""\ @@ -3133,6 +3147,9 @@ def testForceMultilineDict_True(self): 'spam': 'eggs' } } + generatedDict = { + x: x for x in 'value' + } """) self.assertCodeEqual(expected, actual) finally: @@ -3144,6 +3161,7 @@ def testForceMultilineDict_False(self): style.CreateStyleFromConfig('{force_multiline_dict: false}')) unformatted_code = textwrap.dedent("""\ responseDict = {'childDict': {'spam': 'eggs'}} + generatedDict = {x: x for x in 'value'} """) expected_formatted_code = unformatted_code llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index 8616169c9..c70507788 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -130,6 +130,36 @@ def testFuncCallWithDefaultAssign(self): ]) def testSetComprehension(self): + code = textwrap.dedent("""\ + def foo(value): + return {value.lower()} + """) + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckFormatTokenSubtypes(llines, [ + [ + ('def', {subtypes.NONE}), + ('foo', {subtypes.FUNC_DEF}), + ('(', {subtypes.NONE}), + ('value', { + subtypes.NONE, + subtypes.PARAMETER_START, + subtypes.PARAMETER_STOP, + }), + (')', {subtypes.NONE}), + (':', {subtypes.NONE}), + ], + [ + ('return', {subtypes.NONE}), + ('{', {subtypes.NONE}), + ('value', {subtypes.NONE}), + ('.', {subtypes.NONE}), + ('lower', {subtypes.NONE}), + ('(', {subtypes.NONE}), + (')', {subtypes.NONE}), + ('}', {subtypes.NONE}), + ], + ]) + code = textwrap.dedent("""\ def foo(strs): return {s.lower() for s in strs} @@ -167,6 +197,209 @@ def foo(strs): ], ]) + code = textwrap.dedent("""\ + def foo(strs): + return {s + s.lower() for s in strs} + """) + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckFormatTokenSubtypes(llines, [ + [ + ('def', {subtypes.NONE}), + ('foo', {subtypes.FUNC_DEF}), + ('(', {subtypes.NONE}), + ('strs', { + subtypes.NONE, + subtypes.PARAMETER_START, + subtypes.PARAMETER_STOP, + }), + (')', {subtypes.NONE}), + (':', {subtypes.NONE}), + ], + [ + ('return', {subtypes.NONE}), + ('{', {subtypes.NONE}), + ('s', {subtypes.COMP_EXPR}), + ('+', {subtypes.BINARY_OPERATOR, subtypes.COMP_EXPR}), + ('s', {subtypes.COMP_EXPR}), + ('.', {subtypes.COMP_EXPR}), + ('lower', {subtypes.COMP_EXPR}), + ('(', {subtypes.COMP_EXPR}), + (')', {subtypes.COMP_EXPR}), + ('for', { + subtypes.DICT_SET_GENERATOR, + subtypes.COMP_FOR, + }), + ('s', {subtypes.COMP_FOR}), + ('in', {subtypes.COMP_FOR}), + ('strs', {subtypes.COMP_FOR}), + ('}', {subtypes.NONE}), + ], + ]) + + code = textwrap.dedent("""\ + def foo(strs): + return {c.lower() for s in strs for c in s} + """) + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckFormatTokenSubtypes(llines, [ + [ + ('def', {subtypes.NONE}), + ('foo', {subtypes.FUNC_DEF}), + ('(', {subtypes.NONE}), + ('strs', { + subtypes.NONE, + subtypes.PARAMETER_START, + subtypes.PARAMETER_STOP, + }), + (')', {subtypes.NONE}), + (':', {subtypes.NONE}), + ], + [ + ('return', {subtypes.NONE}), + ('{', {subtypes.NONE}), + ('c', {subtypes.COMP_EXPR}), + ('.', {subtypes.COMP_EXPR}), + ('lower', {subtypes.COMP_EXPR}), + ('(', {subtypes.COMP_EXPR}), + (')', {subtypes.COMP_EXPR}), + ('for', { + subtypes.DICT_SET_GENERATOR, + subtypes.COMP_FOR, + subtypes.COMP_EXPR, + }), + ('s', {subtypes.COMP_FOR, subtypes.COMP_EXPR}), + ('in', {subtypes.COMP_FOR, subtypes.COMP_EXPR}), + ('strs', {subtypes.COMP_FOR, subtypes.COMP_EXPR}), + ('for', { + subtypes.DICT_SET_GENERATOR, + subtypes.COMP_FOR, + }), + ('c', {subtypes.COMP_FOR}), + ('in', {subtypes.COMP_FOR}), + ('s', {subtypes.COMP_FOR}), + ('}', {subtypes.NONE}), + ], + ]) + + def testDictComprehension(self): + code = textwrap.dedent("""\ + def foo(value): + return {value: value.lower()} + """) + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckFormatTokenSubtypes(llines, [ + [ + ('def', {subtypes.NONE}), + ('foo', {subtypes.FUNC_DEF}), + ('(', {subtypes.NONE}), + ('value', { + subtypes.NONE, + subtypes.PARAMETER_START, + subtypes.PARAMETER_STOP, + }), + (')', {subtypes.NONE}), + (':', {subtypes.NONE}), + ], + [ + ('return', {subtypes.NONE}), + ('{', {subtypes.NONE}), + ('value', {subtypes.DICTIONARY_KEY, subtypes.DICTIONARY_KEY_PART}), + (':', {subtypes.NONE}), + ('value', {subtypes.DICTIONARY_VALUE}), + ('.', {subtypes.NONE}), + ('lower', {subtypes.NONE}), + ('(', {subtypes.NONE}), + (')', {subtypes.NONE}), + ('}', {subtypes.NONE}), + ], + ]) + + code = textwrap.dedent("""\ + def foo(strs): + return {s: s.lower() for s in strs} + """) + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckFormatTokenSubtypes(llines, [ + [ + ('def', {subtypes.NONE}), + ('foo', {subtypes.FUNC_DEF}), + ('(', {subtypes.NONE}), + ('strs', { + subtypes.NONE, + subtypes.PARAMETER_START, + subtypes.PARAMETER_STOP, + }), + (')', {subtypes.NONE}), + (':', {subtypes.NONE}), + ], + [ + ('return', {subtypes.NONE}), + ('{', {subtypes.NONE}), + ('s', {subtypes.DICTIONARY_KEY, subtypes.DICTIONARY_KEY_PART, subtypes.COMP_EXPR}), + (':', {subtypes.COMP_EXPR}), + ('s', {subtypes.DICTIONARY_VALUE, subtypes.COMP_EXPR}), + ('.', {subtypes.COMP_EXPR}), + ('lower', {subtypes.COMP_EXPR}), + ('(', {subtypes.COMP_EXPR}), + (')', {subtypes.COMP_EXPR}), + ('for', { + subtypes.DICT_SET_GENERATOR, + subtypes.COMP_FOR, + }), + ('s', {subtypes.COMP_FOR}), + ('in', {subtypes.COMP_FOR}), + ('strs', {subtypes.COMP_FOR}), + ('}', {subtypes.NONE}), + ], + ]) + + code = textwrap.dedent("""\ + def foo(strs): + return {c: c.lower() for s in strs for c in s} + """) + llines = yapf_test_helper.ParseAndUnwrap(code) + self._CheckFormatTokenSubtypes(llines, [ + [ + ('def', {subtypes.NONE}), + ('foo', {subtypes.FUNC_DEF}), + ('(', {subtypes.NONE}), + ('strs', { + subtypes.NONE, + subtypes.PARAMETER_START, + subtypes.PARAMETER_STOP, + }), + (')', {subtypes.NONE}), + (':', {subtypes.NONE}), + ], + [ + ('return', {subtypes.NONE}), + ('{', {subtypes.NONE}), + ('c', {subtypes.DICTIONARY_KEY, subtypes.DICTIONARY_KEY_PART, subtypes.COMP_EXPR}), + (':', {subtypes.COMP_EXPR}), + ('c', {subtypes.DICTIONARY_VALUE, subtypes.COMP_EXPR}), + ('.', {subtypes.COMP_EXPR}), + ('lower', {subtypes.COMP_EXPR}), + ('(', {subtypes.COMP_EXPR}), + (')', {subtypes.COMP_EXPR}), + ('for', { + subtypes.DICT_SET_GENERATOR, + subtypes.COMP_FOR, + subtypes.COMP_EXPR, + }), + ('s', {subtypes.COMP_FOR, subtypes.COMP_EXPR}), + ('in', {subtypes.COMP_FOR, subtypes.COMP_EXPR}), + ('strs', {subtypes.COMP_FOR, subtypes.COMP_EXPR}), + ('for', { + subtypes.DICT_SET_GENERATOR, + subtypes.COMP_FOR, + }), + ('c', {subtypes.COMP_FOR}), + ('in', {subtypes.COMP_FOR}), + ('s', {subtypes.COMP_FOR}), + ('}', {subtypes.NONE}), + ], + ]) + def testUnaryNotOperator(self): code = textwrap.dedent("""\ not a From fea4e9a9c71fead79c78b5ac10741ca32a637b4c Mon Sep 17 00:00:00 2001 From: dilmac Date: Wed, 25 Jan 2023 15:30:46 +0100 Subject: [PATCH 577/719] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 5734a5d76..fafc5815a 100644 --- a/README.rst +++ b/README.rst @@ -154,7 +154,7 @@ working directory from which YAPF is invoked. Note that no entry should begin with `./`. -If you use ``pyproject.toml``, exclude patterns are specified by ``ignore_pattens`` key +If you use ``pyproject.toml``, exclude patterns are specified by ``ignore_patterns`` key in ``[tool.yapfignore]`` section. For example: .. code-block:: ini From caebeab5cfed3fc0c577f1870ca15c606e7a584c Mon Sep 17 00:00:00 2001 From: Kapil Raj <103250862+raj-kapil@users.noreply.github.com> Date: Tue, 31 Jan 2023 03:08:32 +0530 Subject: [PATCH 578/719] bugfix for the missing homepage url in the package metadata (#1051) --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 013a23d64..c3a322641 100644 --- a/setup.py +++ b/setup.py @@ -44,6 +44,7 @@ def run(self): name='yapf', version=yapf.__version__, description='A formatter for Python code.', + url='https://github.com/google/yapf', long_description=fd.read(), license='Apache License, Version 2.0', author='Google Inc.', From 00c250eba122e51d796da7f02f82f727c8ab0e44 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 4 Feb 2023 04:34:24 -0800 Subject: [PATCH 579/719] Fix parsing of comments. All comments seem to end with a tokenize.NL token. This can interfere with regular parsing, because if we're currently parsing a comment block and then run into real code, we want to create the comment block "logical line" and start creating the logical line for the code. --- yapf/pyparser/pyparser.py | 76 ++++++++++++++++---------- yapf/pyparser/pyparser_utils.py | 4 +- yapf/pyparser/split_penalty_visitor.py | 9 +-- yapf/yapflib/yapf_api.py | 33 +++++++++++ yapftests/subtype_assigner_test.py | 10 +++- 5 files changed, 94 insertions(+), 38 deletions(-) diff --git a/yapf/pyparser/pyparser.py b/yapf/pyparser/pyparser.py index a8a28ebc8..4481ba66b 100644 --- a/yapf/pyparser/pyparser.py +++ b/yapf/pyparser/pyparser.py @@ -24,7 +24,8 @@ A "logical line" produced by Python's "tokenizer" module ends with a tokenize.NEWLINE, rather than a tokenize.NL, making it easy to separate them -out. +out. Comments all end with a tokentizer.NL, so we need to make sure we don't +errantly pick up non-comment tokens when parsing comment blocks. ParseCode(): parse the code producing a list of logical lines. """ @@ -40,8 +41,6 @@ from yapf.yapflib import format_token from yapf.yapflib import logical_line from yapf.yapflib import py3compat -from yapf.yapflib import style -from yapf.yapflib import subtypes CONTINUATION = token.N_TOKENS @@ -89,44 +88,61 @@ def _CreateLogicalLines(tokens): Returns: A list of LogicalLines. """ - logical_lines = [] - cur_logical_line = [] - prev_tok = None - depth = 0 + formatted_tokens = [] + # Convert tokens into "TokenInfo" and add tokens for continuation markers. + prev_tok = None for tok in tokens: tok = py3compat.TokenInfo(*tok) + + if (prev_tok and prev_tok.line.rstrip().endswith('\\') and + prev_tok.start[0] < tok.start[0]): + ctok = py3compat.TokenInfo( + type=CONTINUATION, + string='\\', + start=(prev_tok.start[0], prev_tok.start[1] + 1), + end=(prev_tok.end[0], prev_tok.end[0] + 2), + line=prev_tok.line) + ctok.lineno = ctok.start[0] + ctok.column = ctok.start[1] + ctok.value = '\\' + formatted_tokens.append(format_token.FormatToken(ctok, 'CONTINUATION')) + + tok.lineno = tok.start[0] + tok.column = tok.start[1] + tok.value = tok.string + formatted_tokens.append( + format_token.FormatToken(tok, token.tok_name[tok.type])) + prev_tok = tok + + # Generate logical lines. + logical_lines, cur_logical_line = [], [] + depth = 0 + for tok in formatted_tokens: + if tok.type == tokenize.ENDMARKER: + break + if tok.type == tokenize.NEWLINE: # End of a logical line. logical_lines.append(logical_line.LogicalLine(depth, cur_logical_line)) cur_logical_line = [] - prev_tok = None elif tok.type == tokenize.INDENT: depth += 1 elif tok.type == tokenize.DEDENT: depth -= 1 - elif tok.type not in {tokenize.NL, tokenize.ENDMARKER}: - if (prev_tok and prev_tok.line.rstrip().endswith('\\') and - prev_tok.start[0] < tok.start[0]): - # Insert a token for a line continuation. - ctok = py3compat.TokenInfo( - type=CONTINUATION, - string='\\', - start=(prev_tok.start[0], prev_tok.start[1] + 1), - end=(prev_tok.end[0], prev_tok.end[0] + 2), - line=prev_tok.line) - ctok.lineno = ctok.start[0] - ctok.column = ctok.start[1] - ctok.value = '\\' - cur_logical_line.append(format_token.FormatToken(ctok, 'CONTINUATION')) - tok.lineno = tok.start[0] - tok.column = tok.start[1] - tok.value = tok.string - cur_logical_line.append( - format_token.FormatToken(tok, token.tok_name[tok.type])) - prev_tok = tok - - # Link the FormatTokens in each line together to for a doubly linked list. + elif tok.type == tokenize.NL: + pass + else: + if (cur_logical_line and not tok.type == tokenize.COMMENT and + cur_logical_line[0].type == tokenize.COMMENT): + # We were parsing a comment block, but now we have real code to worry + # about. Store the comment and carry on. + logical_lines.append(logical_line.LogicalLine(depth, cur_logical_line)) + cur_logical_line = [] + + cur_logical_line.append(tok) + + # Link the FormatTokens in each line together to form a doubly linked list. for line in logical_lines: previous = line.first bracket_stack = [previous] if previous.OpensScope() else [] diff --git a/yapf/pyparser/pyparser_utils.py b/yapf/pyparser/pyparser_utils.py index 3f17b15a4..dee2449d0 100644 --- a/yapf/pyparser/pyparser_utils.py +++ b/yapf/pyparser/pyparser_utils.py @@ -16,7 +16,7 @@ This module collects various utilities related to the parse trees produced by the pyparser. - GetNodeTokens: produces a list of tokens from the logical lines within a + GetLogicalLine: produces a list of tokens from the logical lines within a range. GetTokensInSubRange: produces a sublist of tokens from a current token list within a range. @@ -29,7 +29,7 @@ """ -def GetTokens(logical_lines, node): +def GetLogicalLine(logical_lines, node): """Get a list of tokens within the node's range from the logical lines.""" start = TokenStart(node) end = TokenEnd(node) diff --git a/yapf/pyparser/split_penalty_visitor.py b/yapf/pyparser/split_penalty_visitor.py index 047b48a3d..8cd25c959 100644 --- a/yapf/pyparser/split_penalty_visitor.py +++ b/yapf/pyparser/split_penalty_visitor.py @@ -20,7 +20,6 @@ from yapf.yapflib import subtypes -# This is a skeleton of an AST visitor. class SplitPenalty(ast.NodeVisitor): """Compute split penalties between tokens.""" @@ -35,7 +34,7 @@ def __init__(self, logical_lines): token.split_penalty = split_penalty.UNBREAKABLE def _GetTokens(self, node): - return pyutils.GetTokens(self.logical_lines, node) + return pyutils.GetLogicalLine(self.logical_lines, node) ############################################################################ # Statements # @@ -54,6 +53,7 @@ def visit_FunctionDef(self, node): # decorator_list=[Call_1, Call_2, ..., Call_n], # keywords=[]) tokens = self._GetTokens(node) + for decorator in node.decorator_list: # The decorator token list begins after the '@'. The body of the decorator # is formatted like a normal "call." @@ -103,8 +103,8 @@ def visit_ClassDef(self, node): for decorator in node.decorator_list: # Don't split after the '@'. - decorator_range = self._GetTokens(decorator) - decorator_range[0].split_penalty = split_penalty.UNBREAKABLE + tokens = self._GetTokens(decorator) + tokens[0].split_penalty = split_penalty.UNBREAKABLE return self.generic_visit(node) @@ -288,6 +288,7 @@ def visit_BinOp(self, node): # RShift | BitOr | BitXor | BitAnd | FloorDiv # right=RExpr) tokens = self._GetTokens(node) + _IncreasePenalty(tokens[1:], split_penalty.EXPR) # Lower the split penalty to allow splitting before or after the arithmetic diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 475d0186d..ff87c7bd7 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -36,6 +36,8 @@ import re import sys +from yapf.pyparser import pyparser + from yapf.pytree import pytree_unwrapper from yapf.pytree import pytree_utils from yapf.pytree import blank_line_calculator @@ -148,6 +150,37 @@ def FormatTree(tree, style_config=None, lines=None, verify=False): return reformatter.Reformat(_SplitSemicolons(llines), verify, lines) +def FormatAST(ast, style_config=None, lines=None, verify=False): + """Format a parsed lib2to3 pytree. + + This provides an alternative entry point to YAPF. + + Arguments: + unformatted_source: (unicode) The code to format. + style_config: (string) Either a style name or a path to a file that contains + formatting style settings. If None is specified, use the default style + as set in style.DEFAULT_STYLE_FACTORY + lines: (list of tuples of integers) A list of tuples of lines, [start, end], + that we want to format. The lines are 1-based indexed. It can be used by + third-party code (e.g., IDEs) when reformatting a snippet of code rather + than a whole file. + verify: (bool) True if reformatted code should be verified for syntax. + + Returns: + The source formatted according to the given formatting style. + """ + _CheckPythonVersion() + style.SetGlobalStyle(style.CreateStyleFromConfig(style_config)) + + llines = pyparser.ParseCode(ast) + for lline in llines: + lline.CalculateFormattingInformation() + + lines = _LineRangesToSet(lines) + _MarkLinesToFormat(llines, lines) + return reformatter.Reformat(_SplitSemicolons(llines), verify, lines) + + def FormatCode(unformatted_source, filename='', style_config=None, diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index c70507788..3e632aa4f 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -335,7 +335,10 @@ def foo(strs): [ ('return', {subtypes.NONE}), ('{', {subtypes.NONE}), - ('s', {subtypes.DICTIONARY_KEY, subtypes.DICTIONARY_KEY_PART, subtypes.COMP_EXPR}), + ('s', { + subtypes.DICTIONARY_KEY, subtypes.DICTIONARY_KEY_PART, + subtypes.COMP_EXPR + }), (':', {subtypes.COMP_EXPR}), ('s', {subtypes.DICTIONARY_VALUE, subtypes.COMP_EXPR}), ('.', {subtypes.COMP_EXPR}), @@ -374,7 +377,10 @@ def foo(strs): [ ('return', {subtypes.NONE}), ('{', {subtypes.NONE}), - ('c', {subtypes.DICTIONARY_KEY, subtypes.DICTIONARY_KEY_PART, subtypes.COMP_EXPR}), + ('c', { + subtypes.DICTIONARY_KEY, subtypes.DICTIONARY_KEY_PART, + subtypes.COMP_EXPR + }), (':', {subtypes.COMP_EXPR}), ('c', {subtypes.DICTIONARY_VALUE, subtypes.COMP_EXPR}), ('.', {subtypes.COMP_EXPR}), From 75ca557675c9c8e9e246921f2ec41d93fc3ee225 Mon Sep 17 00:00:00 2001 From: Eugene Toder Date: Tue, 7 Feb 2023 11:31:20 -0500 Subject: [PATCH 580/719] Small fixes and optimizations * Default LineEnding() to LF when no new lines in the file and when tied with another line ending. Currently defaults to CRLF on Python 3.6+ and random on older versions. * Preserve line ending type when formatting a file that is a single new line. Currently always converts to LF. Also simplify logic. * Don't compute diffs when print_diff == False. --- yapf/yapflib/file_resources.py | 2 +- yapf/yapflib/yapf_api.py | 12 +++++------- yapftests/file_resources_test.py | 20 ++++++++++++++++++++ yapftests/yapf_test.py | 25 +++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 8 deletions(-) diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 6809ca9f8..da44b3981 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -195,7 +195,7 @@ def LineEnding(lines): endings[CR] += 1 elif line.endswith(LF): endings[LF] += 1 - return (sorted(endings, key=endings.get, reverse=True) or [LF])[0] + return sorted((LF, CRLF, CR), key=endings.get, reverse=True)[0] def _FindPythonFiles(filenames, recursive, exclude): diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index ff87c7bd7..13b02a44f 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -99,11 +99,10 @@ def FormatFile(filename, lines=lines, print_diff=print_diff, verify=verify) - if reformatted_source.rstrip('\n'): - lines = reformatted_source.rstrip('\n').split('\n') - reformatted_source = newline.join(iter(lines)) + newline + if newline != '\n': + reformatted_source = reformatted_source.replace('\n', newline) if in_place: - if original_source and original_source != reformatted_source: + if changed: file_resources.WriteReformattedCode(filename, reformatted_source, encoding, in_place) return None, encoding, changed @@ -221,10 +220,9 @@ def FormatCode(unformatted_source, if unformatted_source == reformatted_source: return '' if print_diff else reformatted_source, False - code_diff = _GetUnifiedDiff( - unformatted_source, reformatted_source, filename=filename) - if print_diff: + code_diff = _GetUnifiedDiff( + unformatted_source, reformatted_source, filename=filename) return code_diff, code_diff.strip() != '' # pylint: disable=g-explicit-bool-comparison # noqa return reformatted_source, True diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index f54f393d6..bd21d087c 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -560,6 +560,26 @@ def test_line_ending_weighted(self): actual = file_resources.LineEnding(lines) self.assertEqual(actual, '\n') + def test_line_ending_empty(self): + lines = [] + actual = file_resources.LineEnding(lines) + self.assertEqual(actual, '\n') + + def test_line_ending_no_newline(self): + lines = ['spam'] + actual = file_resources.LineEnding(lines) + self.assertEqual(actual, '\n') + + def test_line_ending_tie(self): + lines = [ + 'spam\n', + 'spam\n', + 'spam\r\n', + 'spam\r\n', + ] + actual = file_resources.LineEnding(lines) + self.assertEqual(actual, '\n') + if __name__ == '__main__': unittest.main() diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 6749bf0c1..007d75730 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -493,6 +493,31 @@ def testInPlaceReformattingBlank(self): reformatted_code = fd.read() self.assertEqual(reformatted_code, expected_formatted_code) + def testInPlaceReformattingWindowsNewLine(self): + unformatted_code = u'\r\n\r\n' + expected_formatted_code = u'\r\n' + with utils.TempFileContents( + self.test_tmpdir, unformatted_code, suffix='.py') as filepath: + p = subprocess.Popen(YAPF_BINARY + ['--in-place', filepath]) + p.wait() + with io.open(filepath, mode='r', encoding='utf-8', newline='') as fd: + reformatted_code = fd.read() + self.assertEqual(reformatted_code, expected_formatted_code) + + def testInPlaceReformattingNoNewLine(self): + unformatted_code = textwrap.dedent(u"def foo(): x = 37") + expected_formatted_code = textwrap.dedent("""\ + def foo(): + x = 37 + """) + with utils.TempFileContents( + self.test_tmpdir, unformatted_code, suffix='.py') as filepath: + p = subprocess.Popen(YAPF_BINARY + ['--in-place', filepath]) + p.wait() + with io.open(filepath, mode='r', newline='') as fd: + reformatted_code = fd.read() + self.assertEqual(reformatted_code, expected_formatted_code) + def testInPlaceReformattingEmpty(self): unformatted_code = u'' expected_formatted_code = u'' From 35115002e3e97af65a19d88418ba4b7e84f2fb02 Mon Sep 17 00:00:00 2001 From: Thiago Perrotta Date: Thu, 9 Feb 2023 17:36:23 +0100 Subject: [PATCH 581/719] Remove --disable-noqa from .flake8 config Closes #1053 --- .flake8 | 1 - 1 file changed, 1 deletion(-) diff --git a/.flake8 b/.flake8 index bb1ce94e7..315910712 100644 --- a/.flake8 +++ b/.flake8 @@ -13,6 +13,5 @@ ignore = # line break after binary operator W504 -disable-noqa indent-size = 2 max-line-length = 80 From 29acb5da69e13706351d53c316f67edb2ffee2cc Mon Sep 17 00:00:00 2001 From: Zak Greant Date: Sat, 18 Feb 2023 14:09:39 +0100 Subject: [PATCH 582/719] Minor fix + suggestion Suggested noting that the list args for spaces_before_comment may need to be quotes. Changed instance of "of of" to "of". --- README.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 5734a5d76..039308712 100644 --- a/README.rst +++ b/README.rst @@ -664,10 +664,15 @@ Knobs ``SPACES_BEFORE_COMMENT`` The number of spaces required before a trailing comment. This can be a single value (representing the number of spaces - before each trailing comment) or list of of values (representing + before each trailing comment) or list of values (representing alignment column values; trailing comments within a block will be aligned to the first column value that is greater than the maximum - line length within the block). For example: + line length within the block). + + **Note:** Lists of values may need to be quoted in some contexts + (eg. shells or editor config files). + + For example: With ``spaces_before_comment=5``: @@ -681,7 +686,7 @@ Knobs 1 + 1 # Adding values <-- 5 spaces between the end of the statement and comment - With ``spaces_before_comment=15, 20``: + With ``spaces_before_comment="15, 20"``: .. code-block:: python From d77ee00c80f3f418ac9665fac9f3d25c9da57c80 Mon Sep 17 00:00:00 2001 From: Thiago Perrotta Date: Fri, 24 Feb 2023 19:45:41 +0100 Subject: [PATCH 583/719] ci: run on every PR and on main branch Furthermore, update actions to the latest stable versions. --- .github/workflows/ci.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c219c3860..1f5f6d8c5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,21 +3,22 @@ name: YAPF -on: [push] +on: + pull_request: + push: + branches: 'main' jobs: build: - runs-on: ${{ matrix.os }} strategy: matrix: python-version: ["2.7", "3.7", "3.8", "3.9", "3.10"] os: [ubuntu-latest, macos-latest] - steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies From dea0469562128d4414d05ae986c3ea214bdefdd7 Mon Sep 17 00:00:00 2001 From: Sergei Lebedev Date: Mon, 21 Feb 2022 21:49:06 +0000 Subject: [PATCH 584/719] Generalized the ending comma heuristic to subscripts This commit ensures that G[A, B, C,] is split in a similar way to [A, B, C,] i.e. G[ A, B, C, ] instead of G[A, B, C,] assuming A, B and C do not fit on a single line. Long subscript expressions often occur when instantiating generic classes, and having YAPF reformat them to a more readable multi-line variant seems like a "good thing". --- Note that the heuristic is not perfect and in particular could produce unexpected/verbose outputs when one of the items is itself a list with an ending comma, e.g. G[[A,], B, C,] is reformatted to G[ [ A, ], B, C, ] where G could be typing.Callable. --- CHANGELOG | 1 + yapf/pytree/pytree_unwrapper.py | 4 ++++ yapf/yapflib/format_decision_state.py | 4 +++- yapftests/reformatter_basic_test.py | 13 +++++++++++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index f3ba6e9b3..467c491f4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,7 @@ - Moved 'pytree' parsing tools into its own subdirectory. - Add support for Python 3.10. - Format generated dicts with respect to same rules as regular dicts +- Generalized the ending comma heuristic to subscripts. ### Fixed - Split line before all comparison operators. diff --git a/yapf/pytree/pytree_unwrapper.py b/yapf/pytree/pytree_unwrapper.py index 3fe4ade08..ba1e0c423 100644 --- a/yapf/pytree/pytree_unwrapper.py +++ b/yapf/pytree/pytree_unwrapper.py @@ -285,6 +285,10 @@ def Visit_typedargslist(self, node): # pylint: disable=invalid-name _DetermineMustSplitAnnotation(node) self.DefaultNodeVisit(node) + def Visit_subscriptlist(self, node): # pylint: disable=invalid-name + _DetermineMustSplitAnnotation(node) + self.DefaultNodeVisit(node) + def DefaultLeafVisit(self, leaf): """Default visitor for tree leaves. diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index edab8adad..2468b1f9a 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -205,7 +205,9 @@ def MustSplit(self): (current.value in '}]' and style.Get('SPLIT_BEFORE_CLOSING_BRACKET') or current.value in '}])' and style.Get('INDENT_CLOSING_BRACKETS'))): # Split before the closing bracket if we can. - if subtypes.SUBSCRIPT_BRACKET not in current.subtypes: + if (subtypes.SUBSCRIPT_BRACKET not in current.subtypes or + (previous.value == ',' and + not style.Get('DISABLE_ENDING_COMMA_HEURISTIC'))): return current.node_split_penalty != split_penalty.UNBREAKABLE if (current.value == ')' and previous.value == ',' and diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 935c7c311..e07d46d69 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2645,6 +2645,19 @@ def testSubscriptExpression(self): llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) + def testSubscriptExpressionTerminatedByComma(self): + unformatted_code = textwrap.dedent("""\ + A[B, C,] + """) + expected_code = textwrap.dedent("""\ + A[ + B, + C, + ] + """) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) + def testListWithFunctionCalls(self): unformatted_code = textwrap.dedent("""\ def foo(): From 94a7fac2a2309307bf340c71e2e5cc2a07aeb930 Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Wed, 12 Apr 2023 16:24:46 -0400 Subject: [PATCH 585/719] Drop official support for all versions of Python not actively supported by the PSF (#1068) --- .github/workflows/ci.yml | 2 +- setup.py | 3 --- tox.ini | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f5f6d8c5..aca157b70 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: ["2.7", "3.7", "3.8", "3.9", "3.10"] + python-version: ["3.7", "3.8", "3.9", "3.10"] os: [ubuntu-latest, macos-latest] steps: - uses: actions/checkout@v3 diff --git a/setup.py b/setup.py index c3a322641..a62ebf530 100644 --- a/setup.py +++ b/setup.py @@ -61,10 +61,7 @@ def run(self): 'License :: OSI Approved :: Apache Software License', 'Operating System :: OS Independent', 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/tox.ini b/tox.ini index 5134916dc..e2e67a65a 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist=py27,py36,py37,py38,py39,py310 +envlist=py37,py38,py39,py310 [testenv] commands= From f603b4e5b7ba410626bfc5a4b80135ff007cdeb1 Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Wed, 12 Apr 2023 16:25:46 -0400 Subject: [PATCH 586/719] Support pyproject.toml by default (#1069) --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index a62ebf530..ea170a7e1 100644 --- a/setup.py +++ b/setup.py @@ -78,7 +78,7 @@ def run(self): cmdclass={ 'test': RunTests, }, - extras_require={ - 'pyproject': ['tomli'], - }, + install_requires=[ + 'tomli>=2.0.1' + ], ) From 3f14d3b3929c18aa6b62ddc40f47597ede0f93b6 Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Mon, 17 Apr 2023 15:43:01 -0400 Subject: [PATCH 587/719] Remove references from README.rst (#1071) --- README.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index fafc5815a..4d328d126 100644 --- a/README.rst +++ b/README.rst @@ -77,12 +77,10 @@ possible to run: Python versions =============== -YAPF supports Python 2.7 and 3.6.4+. (Note that some Python 3 features may fail -to parse with Python versions before 3.6.4.) +YAPF supports Python 3.7+. YAPF requires the code it formats to be valid Python for the version YAPF itself -runs under. Therefore, if you format Python 3 code with YAPF, run YAPF itself -under Python 3 (and similarly for Python 2). +runs under. So if formatting 3.7 Python run YAPF under 3.7 Usage From 47c46057ff78696c9ac9fdbbc019de880810f1a9 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 18 Apr 2023 21:01:02 +0000 Subject: [PATCH 588/719] Bump version to 0.33.0 --- CHANGELOG | 3 ++- setup.py | 4 +--- yapf/__init__.py | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 467c491f4..98954d0b6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.40.0] UNRELEASED +## [0.33.0] 2023-04-18 ### Added - Add a new Python parser to generate logical lines. - Added support for `# fmt: on` and `# fmt: off` pragmas. @@ -11,6 +11,7 @@ - Add support for Python 3.10. - Format generated dicts with respect to same rules as regular dicts - Generalized the ending comma heuristic to subscripts. +- Supports "pyproject.toml" by default. ### Fixed - Split line before all comparison operators. diff --git a/setup.py b/setup.py index ea170a7e1..61d8f99be 100644 --- a/setup.py +++ b/setup.py @@ -78,7 +78,5 @@ def run(self): cmdclass={ 'test': RunTests, }, - install_requires=[ - 'tomli>=2.0.1' - ], + install_requires=['tomli>=2.0.1'], ) diff --git a/yapf/__init__.py b/yapf/__init__.py index 94e445b59..2725e6751 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -38,7 +38,7 @@ from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.32.0' +__version__ = '0.33.0' def main(argv): From 5b122fc631863f45f6c20a6e2937d546c452a4f8 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Wed, 19 Apr 2023 00:56:46 +0200 Subject: [PATCH 589/719] ci.yml: Stop limiting push-CI to main branch .. to ease pull requests from topic branches --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aca157b70..2240cc973 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,6 @@ name: YAPF on: pull_request: push: - branches: 'main' jobs: build: From c4f6fabb978c93d5bdeeba139f29f64b6dc69fd3 Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Wed, 19 Apr 2023 16:12:50 -0400 Subject: [PATCH 590/719] Add windows-latest to build matrix --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aca157b70..71eb0f495 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: python-version: ["3.7", "3.8", "3.9", "3.10"] - os: [ubuntu-latest, macos-latest] + os: [macos-latest, ubuntu-latest, windows-latest] steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} From ca26c6266151576a9912698970fb11efd24dd831 Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Wed, 19 Apr 2023 16:25:09 -0400 Subject: [PATCH 591/719] ignore .venv dirs --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 960818e0f..da8e42b5e 100644 --- a/.gitignore +++ b/.gitignore @@ -34,4 +34,5 @@ /yapf.egg-info /.idea +/.venv*/ From d71adf664da9c3fb59634a19325d094b5a53bd0a Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Wed, 19 Apr 2023 16:29:45 -0400 Subject: [PATCH 592/719] Remove Python 3.6 tests --- yapftests/file_resources_test.py | 17 -------- yapftests/reformatter_pep8_test.py | 61 --------------------------- yapftests/reformatter_python3_test.py | 17 -------- yapftests/yapf_test.py | 45 -------------------- 4 files changed, 140 deletions(-) diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 1a516a1db..bc672ac85 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -90,23 +90,6 @@ def test_get_exclude_file_patterns_from_pyproject(self): sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)), sorted(ignore_patterns)) - @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') - def test_get_exclude_file_patterns_from_pyproject_with_wrong_syntax(self): - try: - import tomli - except ImportError: - return - local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') - ignore_patterns = ['temp/**/*.py', './wrong/syntax/*.py'] - with open(local_ignore_file, 'w') as f: - f.write('[tool.yapfignore]\n') - f.write('ignore_patterns=[') - f.writelines('\n,'.join(['"{}"'.format(p) for p in ignore_patterns])) - f.write(']') - - with self.assertRaises(errors.YapfError): - file_resources.GetExcludePatternsForDir(self.test_tmpdir) - def test_get_exclude_file_patterns_from_pyproject_no_ignore_section(self): try: import tomli diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index acc218d24..b03f47bb9 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -705,31 +705,6 @@ def _(): reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) - @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') - def testSpaceBetweenColonAndElipses(self): - style.SetGlobalStyle(style.CreatePEP8Style()) - code = textwrap.dedent("""\ - class MyClass(ABC): - - place: ... - """) - llines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(llines, verify=False)) - - @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') - def testSpaceBetweenDictColonAndElipses(self): - style.SetGlobalStyle(style.CreatePEP8Style()) - unformatted_code = textwrap.dedent("""\ - {0:"...", 1:...} - """) - expected_formatted_code = textwrap.dedent("""\ - {0: "...", 1: ...} - """) - - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - - class TestsForSpacesInsideBrackets(yapf_test_helper.YAPFTest): """Test the SPACE_INSIDE_BRACKETS style option.""" unformatted_code = textwrap.dedent("""\ @@ -838,42 +813,6 @@ def testDefault(self): llines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') - def testAwait(self): - style.SetGlobalStyle( - style.CreateStyleFromConfig('{space_inside_brackets: True}')) - unformatted_code = textwrap.dedent("""\ - import asyncio - import time - - @print_args - async def slow_operation(): - await asyncio.sleep(1) - # print("Slow operation {} complete".format(n)) - async def main(): - start = time.time() - if (await get_html()): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - import asyncio - import time - - - @print_args - async def slow_operation(): - await asyncio.sleep( 1 ) - - # print("Slow operation {} complete".format(n)) - async def main(): - start = time.time() - if ( await get_html() ): - pass - """) - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - - class TestsForSpacesAroundSubscriptColon(yapf_test_helper.YAPFTest): """Test the SPACES_AROUND_SUBSCRIPT_COLON style option.""" unformatted_code = textwrap.dedent("""\ diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index b5d68e86f..29ed94563 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -72,23 +72,6 @@ def foo(a, *, kw): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') - def testPEP448ParameterExpansion(self): - unformatted_code = textwrap.dedent("""\ - { ** x } - { **{} } - { **{ **x }, **x } - {'a': 1, **kw , 'b':3, **kw2 } - """) - expected_formatted_code = textwrap.dedent("""\ - {**x} - {**{}} - {**{**x}, **x} - {'a': 1, **kw, 'b': 3, **kw2} - """) - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - def testAnnotations(self): unformatted_code = textwrap.dedent("""\ def foo(a: list, b: "bar") -> dict: diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 007d75730..fe22ffdc8 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -63,13 +63,6 @@ def testNoEndingNewline(self): """) self._Check(unformatted_code, expected_formatted_code) - @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') - def testPrintAfterPeriod(self): - unformatted_code = textwrap.dedent("""a.print\n""") - expected_formatted_code = textwrap.dedent("""a.print\n""") - self._Check(unformatted_code, expected_formatted_code) - - class FormatFileTest(unittest.TestCase): def setUp(self): # pylint: disable=g-missing-super-call @@ -453,18 +446,6 @@ def assertYapfReformats(self, self.assertEqual(stderrdata, b'') self.assertMultiLineEqual(reformatted_code.decode('utf-8'), expected) - @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') - def testUnicodeEncodingPipedToFile(self): - unformatted_code = textwrap.dedent(u"""\ - def foo(): - print('⇒') - """) - with utils.NamedTempFile( - dirname=self.test_tmpdir, suffix='.py') as (out, _): - with utils.TempFileContents( - self.test_tmpdir, unformatted_code, suffix='.py') as filepath: - subprocess.check_call(YAPF_BINARY + ['--diff', filepath], stdout=out) - def testInPlaceReformatting(self): unformatted_code = textwrap.dedent(u"""\ def foo(): @@ -1555,32 +1536,6 @@ def inner_func(): expected_formatted_code, extra_options=['--lines', '1-8']) - @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') - def testNoSpacesAroundBinaryOperators(self): - unformatted_code = """\ -a = 4-b/c@d**37 -""" - expected_formatted_code = """\ -a = 4-b / c@d**37 -""" - self.assertYapfReformats( - unformatted_code, - expected_formatted_code, - extra_options=[ - '--style', - '{based_on_style: pep8, ' - 'no_spaces_around_selected_binary_operators: "@,**,-"}', - ]) - - @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6') - def testCP936Encoding(self): - unformatted_code = 'print("äž­æ–‡")\n' - expected_formatted_code = 'print("äž­æ–‡")\n' - self.assertYapfReformats( - unformatted_code, - expected_formatted_code, - env={'PYTHONIOENCODING': 'cp936'}) - def testDisableWithLineRanges(self): unformatted_code = """\ # yapf: disable From 1c4d067b0bdf01a1f825b1d903fd7b7ca4690e3f Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Wed, 19 Apr 2023 16:35:26 -0400 Subject: [PATCH 593/719] missing newline --- yapftests/yapf_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index fe22ffdc8..a276bee05 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -63,6 +63,7 @@ def testNoEndingNewline(self): """) self._Check(unformatted_code, expected_formatted_code) + class FormatFileTest(unittest.TestCase): def setUp(self): # pylint: disable=g-missing-super-call From 9b6428f5bef8e946c2769e7e6911768947ed552c Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Wed, 19 Apr 2023 16:40:13 -0400 Subject: [PATCH 594/719] format --- yapftests/reformatter_pep8_test.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index b03f47bb9..8764226e8 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -705,6 +705,7 @@ def _(): reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) + class TestsForSpacesInsideBrackets(yapf_test_helper.YAPFTest): """Test the SPACE_INSIDE_BRACKETS style option.""" unformatted_code = textwrap.dedent("""\ @@ -813,6 +814,7 @@ def testDefault(self): llines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) + class TestsForSpacesAroundSubscriptColon(yapf_test_helper.YAPFTest): """Test the SPACES_AROUND_SUBSCRIPT_COLON style option.""" unformatted_code = textwrap.dedent("""\ From fba1afbfb66efea46e861d6169e74c1b81b742bd Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Wed, 19 Apr 2023 00:32:36 +0200 Subject: [PATCH 595/719] Start supporting Python 3.11 officially --- .github/workflows/ci.yml | 2 +- setup.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fa4695dac..245a80c98 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: ["3.7", "3.8", "3.9", "3.10"] + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] os: [macos-latest, ubuntu-latest, windows-latest] steps: - uses: actions/checkout@v3 diff --git a/setup.py b/setup.py index 61d8f99be..d2807135c 100644 --- a/setup.py +++ b/setup.py @@ -66,6 +66,7 @@ def run(self): 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Quality Assurance', ], From 1a3bb9de904890c34dde343f3ccb2803d51b638e Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Wed, 19 Apr 2023 00:32:54 +0200 Subject: [PATCH 596/719] setup.py: Add Python-3-only classifier --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index d2807135c..7ffad56aa 100644 --- a/setup.py +++ b/setup.py @@ -67,6 +67,7 @@ def run(self): 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3 :: Only', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Quality Assurance', ], From 72d5a8f3b374e7451f8ab07e5a080f1a18329af0 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Wed, 19 Apr 2023 00:34:38 +0200 Subject: [PATCH 597/719] ci.yml: Save CI resources on in-between Python 3.9 and 3.10 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 245a80c98..e135b2a66 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.7", "3.8", "3.11"] # no particular need for 3.9 or 3.10 os: [macos-latest, ubuntu-latest, windows-latest] steps: - uses: actions/checkout@v3 From 5efa9461981db702ffadcbf3571aa4f56be0cf15 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Wed, 19 Apr 2023 00:49:39 +0200 Subject: [PATCH 598/719] setup.py: Formalize requirement for Python >=3.7 --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 61d8f99be..8311a85e0 100644 --- a/setup.py +++ b/setup.py @@ -78,5 +78,6 @@ def run(self): cmdclass={ 'test': RunTests, }, + python_requires='>=3.7', install_requires=['tomli>=2.0.1'], ) From 54d5af76c2481f1a24e229cc820cd243b99c76c4 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Wed, 19 Apr 2023 00:42:59 +0200 Subject: [PATCH 599/719] Drop Python <3.7 leftovers --- yapf/__init__.py | 2 +- yapf/pyparser/pyparser.py | 10 +- yapf/pyparser/pyparser_visitor.py.tmpl | 3 +- yapf/pytree/blank_line_calculator.py | 3 +- yapf/pytree/split_penalty.py | 13 ++- yapf/third_party/yapf_diff/yapf_diff.py | 5 +- yapf/yapflib/file_resources.py | 23 ++--- yapf/yapflib/format_token.py | 6 +- yapf/yapflib/logical_line.py | 14 ++- yapf/yapflib/object_state.py | 15 +-- yapf/yapflib/py3compat.py | 119 +----------------------- yapf/yapflib/style.py | 12 +-- yapf/yapflib/yapf_api.py | 19 +--- yapftests/comment_splicer_test.py | 6 +- yapftests/file_resources_test.py | 11 ++- yapftests/main_test.py | 5 +- yapftests/pytree_visitor_test.py | 6 +- yapftests/reformatter_basic_test.py | 21 ----- yapftests/reformatter_pep8_test.py | 19 ---- yapftests/reformatter_python3_test.py | 25 ----- yapftests/reformatter_verify_test.py | 100 -------------------- yapftests/utils.py | 5 - yapftests/yapf_test.py | 9 +- yapftests/yapf_test_helper.py | 3 - 24 files changed, 75 insertions(+), 379 deletions(-) delete mode 100644 yapftests/reformatter_verify_test.py diff --git a/yapf/__init__.py b/yapf/__init__.py index 2725e6751..99a4d6158 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -98,7 +98,7 @@ def main(argv): try: reformatted_source, _ = yapf_api.FormatCode( - py3compat.unicode('\n'.join(source) + '\n'), + str('\n'.join(source) + '\n'), filename='', style_config=style_config, lines=lines, diff --git a/yapf/pyparser/pyparser.py b/yapf/pyparser/pyparser.py index 4481ba66b..f32aaab80 100644 --- a/yapf/pyparser/pyparser.py +++ b/yapf/pyparser/pyparser.py @@ -33,14 +33,16 @@ # TODO: Call from yapf_api.FormatCode. import ast +import codecs import os import token import tokenize +from io import StringIO +from tokenize import TokenInfo from yapf.pyparser import split_penalty_visitor from yapf.yapflib import format_token from yapf.yapflib import logical_line -from yapf.yapflib import py3compat CONTINUATION = token.N_TOKENS @@ -66,7 +68,7 @@ def ParseCode(unformatted_source, filename=''): try: ast_tree = ast.parse(unformatted_source, filename) ast.fix_missing_locations(ast_tree) - readline = py3compat.StringIO(unformatted_source).readline + readline = StringIO(unformatted_source).readline tokens = tokenize.generate_tokens(readline) except Exception: raise @@ -93,11 +95,11 @@ def _CreateLogicalLines(tokens): # Convert tokens into "TokenInfo" and add tokens for continuation markers. prev_tok = None for tok in tokens: - tok = py3compat.TokenInfo(*tok) + tok = TokenInfo(*tok) if (prev_tok and prev_tok.line.rstrip().endswith('\\') and prev_tok.start[0] < tok.start[0]): - ctok = py3compat.TokenInfo( + ctok = TokenInfo( type=CONTINUATION, string='\\', start=(prev_tok.start[0], prev_tok.start[1] + 1), diff --git a/yapf/pyparser/pyparser_visitor.py.tmpl b/yapf/pyparser/pyparser_visitor.py.tmpl index 503cf2bee..0d8a75e23 100644 --- a/yapf/pyparser/pyparser_visitor.py.tmpl +++ b/yapf/pyparser/pyparser_visitor.py.tmpl @@ -16,12 +16,13 @@ This is a template for a pyparser visitor. Example use: import ast + from io import StringIO from yapf.pyparser import pyparser_visitor def parse_code(source, filename): ast_tree = ast.parse(source, filename) - readline = py3compat.StringIO(source).readline + readline = StringIO(source).readline tokens = tokenize.generate_tokens(readline) logical_lines = _CreateLogicalLines(tokens) diff --git a/yapf/pytree/blank_line_calculator.py b/yapf/pytree/blank_line_calculator.py index 9d218bf97..d47f2b560 100644 --- a/yapf/pytree/blank_line_calculator.py +++ b/yapf/pytree/blank_line_calculator.py @@ -26,7 +26,6 @@ from yapf.pytree import pytree_utils from yapf.pytree import pytree_visitor -from yapf.yapflib import py3compat from yapf.yapflib import style _NO_BLANK_LINES = 1 @@ -175,5 +174,5 @@ def _StartsInZerothColumn(node): def _AsyncFunction(node): - return (py3compat.PY3 and node.prev_sibling and + return (node.prev_sibling and node.prev_sibling.type == grammar_token.ASYNC) diff --git a/yapf/pytree/split_penalty.py b/yapf/pytree/split_penalty.py index b53ffbf85..81163e4d3 100644 --- a/yapf/pytree/split_penalty.py +++ b/yapf/pytree/split_penalty.py @@ -20,7 +20,6 @@ from yapf.pytree import pytree_utils from yapf.pytree import pytree_visitor -from yapf.yapflib import py3compat from yapf.yapflib import style from yapf.yapflib import subtypes @@ -154,7 +153,7 @@ def Visit_arglist(self, node): # pylint: disable=invalid-name self.DefaultNodeVisit(node) - for index in py3compat.range(1, len(node.children)): + for index in range(1, len(node.children)): child = node.children[index] if isinstance(child, pytree.Leaf) and child.value == ',': _SetUnbreakable(child) @@ -167,7 +166,7 @@ def Visit_argument(self, node): # pylint: disable=invalid-name # argument ::= test [comp_for] | test '=' test # Really [keyword '='] test self.DefaultNodeVisit(node) - for index in py3compat.range(1, len(node.children) - 1): + for index in range(1, len(node.children) - 1): child = node.children[index] if isinstance(child, pytree.Leaf) and child.value == '=': _SetSplitPenalty( @@ -179,7 +178,7 @@ def Visit_tname(self, node): # pylint: disable=invalid-name # tname ::= NAME [':' test] self.DefaultNodeVisit(node) - for index in py3compat.range(1, len(node.children) - 1): + for index in range(1, len(node.children) - 1): child = node.children[index] if isinstance(child, pytree.Leaf) and child.value == ':': _SetSplitPenalty( @@ -192,7 +191,7 @@ def Visit_dotted_name(self, node): # pylint: disable=invalid-name for child in node.children: self.Visit(child) start = 2 if hasattr(node.children[0], 'is_pseudo') else 1 - for i in py3compat.range(start, len(node.children)): + for i in range(start, len(node.children)): _SetUnbreakable(node.children[i]) def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name @@ -540,7 +539,7 @@ def RecExpression(node, first_child_leaf): def _SetBitwiseOperandPenalty(node, op): - for index in py3compat.range(1, len(node.children) - 1): + for index in range(1, len(node.children) - 1): child = node.children[index] if isinstance(child, pytree.Leaf) and child.value == op: if style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'): @@ -552,7 +551,7 @@ def _SetBitwiseOperandPenalty(node, op): def _SetExpressionOperandPenalty(node, ops): - for index in py3compat.range(1, len(node.children) - 1): + for index in range(1, len(node.children) - 1): child = node.children[index] if pytree_utils.NodeName(child) in ops: if style.Get('SPLIT_BEFORE_ARITHMETIC_OPERATOR'): diff --git a/yapf/third_party/yapf_diff/yapf_diff.py b/yapf/third_party/yapf_diff/yapf_diff.py index 810a6a2d4..de73667d0 100644 --- a/yapf/third_party/yapf_diff/yapf_diff.py +++ b/yapf/third_party/yapf_diff/yapf_diff.py @@ -32,10 +32,7 @@ import subprocess import sys -if sys.version_info.major >= 3: - from io import StringIO -else: - from io import BytesIO as StringIO +from io import StringIO def main(): diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index da44b3981..1dcadaec7 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -17,12 +17,16 @@ querying. """ +import codecs import fnmatch import os import re +import sys +from configparser import ConfigParser +from io import StringIO +from tokenize import detect_encoding from yapf.yapflib import errors -from yapf.yapflib import py3compat from yapf.yapflib import style CR = '\r' @@ -120,7 +124,7 @@ def GetDefaultStyleForDir(dirname, default_style=style.DEFAULT_STYLE): pass # It's okay if it's not there. else: with fd: - config = py3compat.ConfigParser() + config = ConfigParser() config.read_file(fd) if config.has_section('yapf'): return config_file @@ -178,11 +182,10 @@ def WriteReformattedCode(filename, in_place: (bool) If True, then write the reformatted code to the file. """ if in_place: - with py3compat.open_with_encoding( - filename, mode='w', encoding=encoding, newline='') as fd: + with codecs.open(filename, mode='w', encoding=encoding) as fd: fd.write(reformatted_code) else: - py3compat.EncodeAndWriteToStdout(reformatted_code) + sys.stdout.buffer.write(reformatted_code.encode('utf-8')) def LineEnding(lines): @@ -263,11 +266,10 @@ def IsPythonFile(filename): try: with open(filename, 'rb') as fd: - encoding = py3compat.detect_encoding(fd.readline)[0] + encoding = detect_encoding(fd.readline)[0] # Check for correctness of encoding. - with py3compat.open_with_encoding( - filename, mode='r', encoding=encoding) as fd: + with codecs.open(filename, mode='r', encoding=encoding) as fd: fd.read() except UnicodeDecodeError: encoding = 'latin-1' @@ -278,8 +280,7 @@ def IsPythonFile(filename): return False try: - with py3compat.open_with_encoding( - filename, mode='r', encoding=encoding) as fd: + with codecs.open(filename, mode='r', encoding=encoding) as fd: first_line = fd.readline(256) except IOError: return False @@ -290,4 +291,4 @@ def IsPythonFile(filename): def FileEncoding(filename): """Return the file's encoding.""" with open(filename, 'rb') as fd: - return py3compat.detect_encoding(fd.readline)[0] + return detect_encoding(fd.readline)[0] diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 6eea05473..41afd45cb 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -16,10 +16,10 @@ import keyword import re +from functools import lru_cache from lib2to3.pgen2 import token from yapf.pytree import pytree_utils -from yapf.yapflib import py3compat from yapf.yapflib import style from yapf.yapflib import subtypes @@ -239,7 +239,7 @@ def is_binary_op(self): return subtypes.BINARY_OPERATOR in self.subtypes @property - @py3compat.lru_cache() + @lru_cache() def is_arithmetic_op(self): """Token is an arithmetic operator.""" return self.value in frozenset({ @@ -277,7 +277,7 @@ def is_continuation(self): return self.type == CONTINUATION @property - @py3compat.lru_cache() + @lru_cache() def is_keyword(self): return keyword.iskeyword(self.value) diff --git a/yapf/yapflib/logical_line.py b/yapf/yapflib/logical_line.py index 7f03509fb..1528fc450 100644 --- a/yapf/yapflib/logical_line.py +++ b/yapf/yapflib/logical_line.py @@ -22,7 +22,6 @@ from yapf.pytree import pytree_utils from yapf.pytree import split_penalty from yapf.yapflib import format_token -from yapf.yapflib import py3compat from yapf.yapflib import style from yapf.yapflib import subtypes @@ -505,13 +504,12 @@ def _CanBreakBefore(prev_token, cur_token): """Return True if a line break may occur before the current token.""" pval = prev_token.value cval = cur_token.value - if py3compat.PY3: - if pval == 'yield' and cval == 'from': - # Don't break before a yield argument. - return False - if pval in {'async', 'await'} and cval in {'def', 'with', 'for'}: - # Don't break after sync keywords. - return False + if pval == 'yield' and cval == 'from': + # Don't break before a yield argument. + return False + if pval in {'async', 'await'} and cval in {'def', 'with', 'for'}: + # Don't break after sync keywords. + return False if cur_token.split_penalty >= split_penalty.UNBREAKABLE: return False if pval == '@': diff --git a/yapf/yapflib/object_state.py b/yapf/yapflib/object_state.py index ec259e682..2b7c068ea 100644 --- a/yapf/yapflib/object_state.py +++ b/yapf/yapflib/object_state.py @@ -22,7 +22,8 @@ from __future__ import division from __future__ import print_function -from yapf.yapflib import py3compat +from functools import lru_cache + from yapf.yapflib import style from yapf.yapflib import subtypes @@ -120,26 +121,26 @@ def has_typed_return(self): return self.closing_bracket.next_token.value == '->' @property - @py3compat.lru_cache() + @lru_cache() def has_default_values(self): return any(param.has_default_value for param in self.parameters) @property - @py3compat.lru_cache() + @lru_cache() def ends_in_comma(self): if not self.parameters: return False return self.parameters[-1].last_token.next_token.value == ',' @property - @py3compat.lru_cache() + @lru_cache() def last_token(self): token = self.opening_bracket.matching_bracket while not token.is_comment and token.next_token: token = token.next_token return token - @py3compat.lru_cache() + @lru_cache() def LastParamFitsOnLine(self, indent): """Return true if the last parameter fits on a single line.""" if not self.has_typed_return: @@ -151,7 +152,7 @@ def LastParamFitsOnLine(self, indent): total_length -= last_param.total_length - len(last_param.value) return total_length + indent <= style.Get('COLUMN_LIMIT') - @py3compat.lru_cache() + @lru_cache() def SplitBeforeClosingBracket(self, indent): """Return true if there's a split before the closing bracket.""" if style.Get('DEDENT_CLOSING_BRACKETS'): @@ -205,7 +206,7 @@ def __init__(self, first_token, last_token): self.last_token = last_token @property - @py3compat.lru_cache() + @lru_cache() def has_default_value(self): """Returns true if the parameter has a default value.""" tok = self.first_token diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py index e4cb9788f..c95d4b545 100644 --- a/yapf/yapflib/py3compat.py +++ b/yapf/yapflib/py3compat.py @@ -15,131 +15,20 @@ import codecs import io -import os import sys -PY3 = sys.version_info[0] >= 3 -PY36 = sys.version_info[0] >= 3 and sys.version_info[1] >= 6 -PY37 = sys.version_info[0] >= 3 and sys.version_info[1] >= 7 PY38 = sys.version_info[0] >= 3 and sys.version_info[1] >= 8 -if PY3: - StringIO = io.StringIO - BytesIO = io.BytesIO - import codecs # noqa: F811 - - def open_with_encoding(filename, mode, encoding, newline=''): # pylint: disable=unused-argument # noqa - return codecs.open(filename, mode=mode, encoding=encoding) - - import functools - lru_cache = functools.lru_cache - - range = range - ifilter = filter - - def raw_input(): - wrapper = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8') - return wrapper.buffer.raw.readall().decode('utf-8') - - import configparser - - # Mappings from strings to booleans (such as '1' to True, 'false' to False, - # etc.) - CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser.BOOLEAN_STATES - - import tokenize - detect_encoding = tokenize.detect_encoding - TokenInfo = tokenize.TokenInfo -else: - import __builtin__ - import cStringIO - from itertools import ifilter - - StringIO = BytesIO = cStringIO.StringIO - - open_with_encoding = io.open - - # Python 2.7 doesn't have a native LRU cache, so do nothing. - def lru_cache(maxsize=128, typed=False): - - def fake_wrapper(user_function): - return user_function - - return fake_wrapper - - range = xrange # noqa: F821 - - raw_input = raw_input - - import ConfigParser as configparser - CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser._boolean_states # pylint: disable=protected-access # noqa - - from lib2to3.pgen2 import tokenize - detect_encoding = tokenize.detect_encoding - - import collections - - class TokenInfo( - collections.namedtuple('TokenInfo', 'type string start end line')): - pass - - -def EncodeAndWriteToStdout(s, encoding='utf-8'): - """Encode the given string and emit to stdout. - - The string may contain non-ascii characters. This is a problem when stdout is - redirected, because then Python doesn't know the encoding and we may get a - UnicodeEncodeError. - - Arguments: - s: (string) The string to encode. - encoding: (string) The encoding of the string. - """ - if PY3: - sys.stdout.buffer.write(s.encode(encoding)) - elif sys.platform == 'win32': - # On python 2 and Windows universal newline transformation will be in - # effect on stdout. Python 2 will not let us avoid the easily because - # it happens based on whether the file handle is opened in O_BINARY or - # O_TEXT state. However we can tell Windows itself to change the current - # mode, and python 2 will follow suit. However we must take care to change - # the mode on the actual external stdout not just the current sys.stdout - # which may have been monkey-patched inside the python environment. - import msvcrt # pylint: disable=g-import-not-at-top - if sys.__stdout__ is sys.stdout: - msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) - sys.stdout.write(s.encode(encoding)) - else: - sys.stdout.write(s.encode(encoding)) - - -if PY3: - basestring = str - unicode = str # pylint: disable=redefined-builtin,invalid-name -else: - basestring = basestring - - def unicode(s): # pylint: disable=invalid-name - """Force conversion of s to unicode.""" - return __builtin__.unicode(s, 'utf-8') - - -# In Python 3.2+, readfp is deprecated in favor of read_file, which doesn't -# exist in Python 2 yet. To avoid deprecation warnings, subclass ConfigParser to -# fix this - now read_file works across all Python versions we care about. -class ConfigParser(configparser.ConfigParser): - if not PY3: - - def read_file(self, fp, source=None): - self.readfp(fp, filename=source) +def raw_input(): + wrapper = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8') + return wrapper.buffer.raw.readall().decode('utf-8') def removeBOM(source): """Remove any Byte-order-Mark bytes from the beginning of a file.""" bom = codecs.BOM_UTF8 - if PY3: - bom = bom.decode('utf-8') + bom = bom.decode('utf-8') if source.startswith(bom): return source[len(bom):] return source diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index c8397b323..3e5f5eb3e 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -16,9 +16,9 @@ import os import re import textwrap +from configparser import ConfigParser from yapf.yapflib import errors -from yapf.yapflib import py3compat class StyleConfigError(errors.YapfError): @@ -579,7 +579,7 @@ def _StringSetConverter(s): def _BoolConverter(s): """Option value converter for a boolean.""" - return py3compat.CONFIGPARSER_BOOLEAN_STATES[s.lower()] + return ConfigParser.BOOLEAN_STATES[s.lower()] def _IntListConverter(s): @@ -702,7 +702,7 @@ def GlobalStyles(): if isinstance(style_config, dict): config = _CreateConfigParserFromConfigDict(style_config) - elif isinstance(style_config, py3compat.basestring): + elif isinstance(style_config, str): style_factory = _STYLE_NAME_TO_FACTORY.get(style_config.lower()) if style_factory is not None: return style_factory() @@ -716,7 +716,7 @@ def GlobalStyles(): def _CreateConfigParserFromConfigDict(config_dict): - config = py3compat.ConfigParser() + config = ConfigParser() config.add_section('style') for key, value in config_dict.items(): config.set('style', key, str(value)) @@ -728,7 +728,7 @@ def _CreateConfigParserFromConfigString(config_string): if config_string[0] != '{' or config_string[-1] != '}': raise StyleConfigError( "Invalid style dict syntax: '{}'.".format(config_string)) - config = py3compat.ConfigParser() + config = ConfigParser() config.add_section('style') for key, value, _ in re.findall( r'([a-zA-Z0-9_]+)\s*[:=]\s*' @@ -746,7 +746,7 @@ def _CreateConfigParserFromConfigFile(config_filename): # Provide a more meaningful error here. raise StyleConfigError( '"{0}" is not a valid style or file path'.format(config_filename)) - config = py3compat.ConfigParser() + config = ConfigParser() if config_filename.endswith(PYPROJECT_TOML): try: diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 13b02a44f..19e86f028 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -32,6 +32,7 @@ verify: (bool) True if reformatted code should be verified for syntax. """ +import codecs import difflib import re import sys @@ -48,7 +49,6 @@ from yapf.yapflib import errors from yapf.yapflib import file_resources from yapf.yapflib import identify_container -from yapf.yapflib import py3compat from yapf.yapflib import reformatter from yapf.yapflib import style @@ -86,8 +86,6 @@ def FormatFile(filename, IOError: raised if there was an error reading the file. ValueError: raised if in_place and print_diff are both specified. """ - _CheckPythonVersion() - if in_place and print_diff: raise ValueError('Cannot pass both in_place and print_diff.') @@ -129,7 +127,6 @@ def FormatTree(tree, style_config=None, lines=None, verify=False): Returns: The source formatted according to the given formatting style. """ - _CheckPythonVersion() style.SetGlobalStyle(style.CreateStyleFromConfig(style_config)) # Run passes on the tree, modifying it in place. @@ -168,7 +165,6 @@ def FormatAST(ast, style_config=None, lines=None, verify=False): Returns: The source formatted according to the given formatting style. """ - _CheckPythonVersion() style.SetGlobalStyle(style.CreateStyleFromConfig(style_config)) llines = pyparser.ParseCode(ast) @@ -228,16 +224,6 @@ def FormatCode(unformatted_source, return reformatted_source, True -def _CheckPythonVersion(): # pragma: no cover - errmsg = 'yapf is only supported for Python 2.7 or 3.6+' - if sys.version_info[0] == 2: - if sys.version_info[1] < 7: - raise RuntimeError(errmsg) - elif sys.version_info[0] == 3: - if sys.version_info[1] < 6: - raise RuntimeError(errmsg) - - def ReadFile(filename, logger=None): """Read the contents of the file. @@ -259,8 +245,7 @@ def ReadFile(filename, logger=None): encoding = file_resources.FileEncoding(filename) # Preserves line endings. - with py3compat.open_with_encoding( - filename, mode='r', encoding=encoding, newline='') as fd: + with codecs.open(filename, mode='r', encoding=encoding) as fd: lines = fd.readlines() line_ending = file_resources.LineEnding(lines) diff --git a/yapftests/comment_splicer_test.py b/yapftests/comment_splicer_test.py index 2e0141bd4..f33491cd6 100644 --- a/yapftests/comment_splicer_test.py +++ b/yapftests/comment_splicer_test.py @@ -19,8 +19,6 @@ from yapf.pytree import pytree_utils from yapf.pytree import comment_splicer -from yapf.yapflib import py3compat - class CommentSplicerTest(unittest.TestCase): @@ -39,8 +37,8 @@ def _AssertNodeIsComment(self, node, text_in_comment=None): def _FindNthChildNamed(self, node, name, n=1): for i, child in enumerate( - py3compat.ifilter(lambda c: pytree_utils.NodeName(c) == name, - node.pre_order())): + filter(lambda c: pytree_utils.NodeName(c) == name, + node.pre_order())): if i == n - 1: return child raise RuntimeError('No Nth child for n={0}'.format(n)) diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index bc672ac85..b31001c1c 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -14,15 +14,16 @@ # limitations under the License. """Tests for yapf.file_resources.""" +import codecs import contextlib import os import shutil import tempfile import unittest +from io import BytesIO from yapf.yapflib import errors from yapf.yapflib import file_resources -from yapf.yapflib import py3compat from yapftests import utils @@ -438,7 +439,7 @@ def test_python_shebang(self): def test_with_latin_encoding(self): file1 = os.path.join(self.test_tmpdir, 'testfile1') - with py3compat.open_with_encoding(file1, mode='w', encoding='latin-1') as f: + with codecs.open(file1, mode='w', encoding='latin-1') as f: f.write(u'#! /bin/python2\n') self.assertTrue(file_resources.IsPythonFile(file1)) @@ -469,7 +470,7 @@ def test_trailing_slash(self): class BufferedByteStream(object): def __init__(self): - self.stream = py3compat.BytesIO() + self.stream = BytesIO() def getvalue(self): # pylint: disable=invalid-name return self.stream.getvalue().decode('utf-8') @@ -501,7 +502,7 @@ def test_write_to_file(self): def test_write_to_stdout(self): s = u'foobar' - stream = BufferedByteStream() if py3compat.PY3 else py3compat.StringIO() + stream = BufferedByteStream() with utils.stdout_redirector(stream): file_resources.WriteReformattedCode( None, s, in_place=False, encoding='utf-8') @@ -509,7 +510,7 @@ def test_write_to_stdout(self): def test_write_encoded_to_stdout(self): s = '\ufeff# -*- coding: utf-8 -*-\nresult = "passed"\n' # pylint: disable=anomalous-unicode-escape-in-string # noqa - stream = BufferedByteStream() if py3compat.PY3 else py3compat.StringIO() + stream = BufferedByteStream() with utils.stdout_redirector(stream): file_resources.WriteReformattedCode( None, s, in_place=False, encoding='utf-8') diff --git a/yapftests/main_test.py b/yapftests/main_test.py index c83b8b66a..5b7347686 100644 --- a/yapftests/main_test.py +++ b/yapftests/main_test.py @@ -15,6 +15,7 @@ """Tests for yapf.__init__.main.""" from contextlib import contextmanager +from io import StringIO import sys import unittest import yapf @@ -34,10 +35,10 @@ class IO(object): class Buffer(object): def __init__(self): - self.string_io = py3compat.StringIO() + self.string_io = StringIO() def write(self, s): - if py3compat.PY3 and isinstance(s, bytes): + if isinstance(s, bytes): s = str(s, 'utf-8') self.string_io.write(s) diff --git a/yapftests/pytree_visitor_test.py b/yapftests/pytree_visitor_test.py index 45a83b113..d9000133c 100644 --- a/yapftests/pytree_visitor_test.py +++ b/yapftests/pytree_visitor_test.py @@ -14,10 +14,10 @@ """Tests for yapf.pytree_visitor.""" import unittest +from io import StringIO from yapf.pytree import pytree_utils from yapf.pytree import pytree_visitor -from yapf.yapflib import py3compat class _NodeNameCollector(pytree_visitor.PyTreeVisitor): @@ -96,7 +96,7 @@ def testDumper(self): # PyTreeDumper is mainly a debugging utility, so only do basic sanity # checking. tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_SIMPLE_CODE) - stream = py3compat.StringIO() + stream = StringIO() pytree_visitor.PyTreeDumper(target_stream=stream).Visit(tree) dump_output = stream.getvalue() @@ -107,7 +107,7 @@ def testDumper(self): def testDumpPyTree(self): # Similar sanity checking for the convenience wrapper DumpPyTree tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_SIMPLE_CODE) - stream = py3compat.StringIO() + stream = StringIO() pytree_visitor.DumpPyTree(tree, target_stream=stream) dump_output = stream.getvalue() diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index e07d46d69..a8b2fdd9b 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2843,27 +2843,6 @@ def testSplitAfterComment(self): finally: style.SetGlobalStyle(style.CreateYapfStyle()) - @unittest.skipUnless(not py3compat.PY3, 'Requires Python 2.7') - def testAsyncAsNonKeyword(self): - try: - style.SetGlobalStyle(style.CreatePEP8Style()) - - # In Python 2, async may be used as a non-keyword identifier. - code = textwrap.dedent("""\ - from util import async - - - class A(object): - - def foo(self): - async.run() - """) - - llines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(llines)) - finally: - style.SetGlobalStyle(style.CreateYapfStyle()) - def testDisableEndingCommaHeuristic(self): code = textwrap.dedent("""\ x = [1, 2, 3, 4, 5, 6, 7,] diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 8764226e8..b6bf31164 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -16,7 +16,6 @@ import textwrap import unittest -from yapf.yapflib import py3compat from yapf.yapflib import reformatter from yapf.yapflib import style @@ -664,24 +663,6 @@ def testTwoWordComparisonOperators(self): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - @unittest.skipUnless(not py3compat.PY3, 'Requires Python 2.7') - def testAsyncAsNonKeyword(self): - # In Python 2, async may be used as a non-keyword identifier. - code = textwrap.dedent("""\ - from util import async - - - class A(object): - - def foo(self): - async.run() - - def bar(self): - pass - """) - llines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(llines, verify=False)) - def testStableInlinedDictionaryFormatting(self): unformatted_code = textwrap.dedent("""\ def _(): diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index 29ed94563..221859a58 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -17,14 +17,12 @@ import textwrap import unittest -from yapf.yapflib import py3compat from yapf.yapflib import reformatter from yapf.yapflib import style from yapftests import yapf_test_helper -@unittest.skipUnless(py3compat.PY3, 'Requires Python 3') class TestsForPython3Code(yapf_test_helper.YAPFTest): """Test a few constructs that are new Python 3 syntax.""" @@ -91,8 +89,6 @@ def testExecAsNonKeyword(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testAsyncFunctions(self): - if sys.version_info[1] < 5: - return code = textwrap.dedent("""\ import asyncio import time @@ -189,8 +185,6 @@ def testNoneKeyword(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testAsyncWithPrecedingComment(self): - if sys.version_info[1] < 5: - return unformatted_code = textwrap.dedent("""\ import asyncio @@ -217,8 +211,6 @@ async def foo(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testAsyncFunctionsNested(self): - if sys.version_info[1] < 5: - return code = textwrap.dedent("""\ async def outer(): @@ -229,8 +221,6 @@ async def inner(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testKeepTypesIntact(self): - if sys.version_info[1] < 5: - return unformatted_code = textwrap.dedent("""\ def _ReduceAbstractContainers( self, *args: Optional[automation_converter.PyiCollectionAbc]) -> List[ @@ -247,8 +237,6 @@ def _ReduceAbstractContainers( self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testContinuationIndentWithAsync(self): - if sys.version_info[1] < 5: - return unformatted_code = textwrap.dedent("""\ async def start_websocket(): async with session.ws_connect( @@ -265,9 +253,6 @@ async def start_websocket(): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingArguments(self): - if sys.version_info[1] < 5: - return - unformatted_code = """\ async def open_file(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None): pass @@ -335,8 +320,6 @@ def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): style.SetGlobalStyle(style.CreatePEP8Style()) def testDictUnpacking(self): - if sys.version_info[1] < 5: - return unformatted_code = """\ class Foo: def foo(self): @@ -360,8 +343,6 @@ def foo(self): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMultilineFormatString(self): - if sys.version_info[1] < 6: - return code = """\ # yapf: disable (f''' @@ -373,8 +354,6 @@ def testMultilineFormatString(self): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testEllipses(self): - if sys.version_info[1] < 6: - return code = """\ def dirichlet(x12345678901234567890123456789012345678901234567890=...) -> None: return @@ -404,8 +383,6 @@ def rrrrrrrrrrrrrrrrrrrrrr( self.assertCodeEqual(code, reformatter.Reformat(llines)) def testAsyncForElseNotIndentedInsideBody(self): - if sys.version_info[1] < 5: - return code = textwrap.dedent("""\ async def fn(): async for message in websocket: @@ -420,8 +397,6 @@ async def fn(): self.assertCodeEqual(code, reformatter.Reformat(llines)) def testForElseInAsyncNotMixedWithAsyncFor(self): - if sys.version_info[1] < 5: - return code = textwrap.dedent("""\ async def fn(): for i in range(10): diff --git a/yapftests/reformatter_verify_test.py b/yapftests/reformatter_verify_test.py deleted file mode 100644 index 33ba3a614..000000000 --- a/yapftests/reformatter_verify_test.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright 2016 Google Inc. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Tests for yapf.reformatter.""" - -import textwrap -import unittest - -from yapf.yapflib import py3compat -from yapf.yapflib import reformatter -from yapf.yapflib import style -from yapf.yapflib import verifier - -from yapftests import yapf_test_helper - - -@unittest.skipIf(py3compat.PY3, 'Requires Python 2') -class TestVerifyNoVerify(yapf_test_helper.YAPFTest): - - @classmethod - def setUpClass(cls): - style.SetGlobalStyle(style.CreatePEP8Style()) - - def testVerifyException(self): - unformatted_code = textwrap.dedent("""\ - class ABC(metaclass=type): - pass - """) - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - with self.assertRaises(verifier.InternalError): - reformatter.Reformat(llines, verify=True) - reformatter.Reformat(llines) # verify should be False by default. - - def testNoVerify(self): - unformatted_code = textwrap.dedent("""\ - class ABC(metaclass=type): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - class ABC(metaclass=type): - pass - """) - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines, verify=False)) - - def testVerifyFutureImport(self): - unformatted_code = textwrap.dedent("""\ - from __future__ import print_function - - def call_my_function(the_function): - the_function("hi") - - if __name__ == "__main__": - call_my_function(print) - """) - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - with self.assertRaises(verifier.InternalError): - reformatter.Reformat(llines, verify=True) - - expected_formatted_code = textwrap.dedent("""\ - from __future__ import print_function - - - def call_my_function(the_function): - the_function("hi") - - - if __name__ == "__main__": - call_my_function(print) - """) - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines, verify=False)) - - def testContinuationLineShouldBeDistinguished(self): - code = textwrap.dedent("""\ - class Foo(object): - - def bar(self): - if self.solo_generator_that_is_long is None and len( - self.generators + self.next_batch) == 1: - pass - """) - llines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(llines, verify=False)) - - -if __name__ == '__main__': - unittest.main() diff --git a/yapftests/utils.py b/yapftests/utils.py index 268b8c43a..e91752b8d 100644 --- a/yapftests/utils.py +++ b/yapftests/utils.py @@ -52,11 +52,6 @@ def NamedTempFile(mode='w+b', dirname=None, text=False): """Context manager creating a new temporary file in text mode.""" - if sys.version_info < (3, 5): # covers also python 2 - if suffix is None: - suffix = '' - if prefix is None: - prefix = 'tmp' (fd, fname) = tempfile.mkstemp( suffix=suffix, prefix=prefix, dir=dirname, text=text) f = io.open( diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index a276bee05..393a9f9d8 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -24,10 +24,10 @@ import textwrap import unittest +from io import StringIO from lib2to3.pgen2 import tokenize from yapf.yapflib import errors -from yapf.yapflib import py3compat from yapf.yapflib import style from yapf.yapflib import yapf_api @@ -272,10 +272,7 @@ def testFormatFileInPlace(self): result, _, _ = yapf_api.FormatFile(filepath, in_place=True) self.assertEqual(result, None) with open(filepath) as fd: - if sys.version_info[0] <= 2: - self.assertCodeEqual(formatted_code, fd.read().decode('ascii')) - else: - self.assertCodeEqual(formatted_code, fd.read()) + self.assertCodeEqual(formatted_code, fd.read()) self.assertRaises( ValueError, @@ -285,7 +282,7 @@ def testFormatFileInPlace(self): print_diff=True) def testNoFile(self): - stream = py3compat.StringIO() + stream = StringIO() handler = logging.StreamHandler(stream) logger = logging.getLogger('mylogger') logger.addHandler(handler) diff --git a/yapftests/yapf_test_helper.py b/yapftests/yapf_test_helper.py index cb56ec865..61aa2c51b 100644 --- a/yapftests/yapf_test_helper.py +++ b/yapftests/yapf_test_helper.py @@ -26,7 +26,6 @@ from yapf.pytree import split_penalty from yapf.pytree import subtype_assigner from yapf.yapflib import identify_container -from yapf.yapflib import py3compat from yapf.yapflib import style @@ -34,8 +33,6 @@ class YAPFTest(unittest.TestCase): def __init__(self, *args): super(YAPFTest, self).__init__(*args) - if not py3compat.PY3: - self.assertRaisesRegex = self.assertRaisesRegexp def assertCodeEqual(self, expected_code, code): if code != expected_code: From 750285ff32698f1564c918e178d39921b745ed70 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Tue, 25 Apr 2023 20:08:00 +0200 Subject: [PATCH 600/719] Pin GitHub Actions to specific commits for security (#1073) --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e135b2a66..dd4b71b13 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,9 +15,9 @@ jobs: python-version: ["3.7", "3.8", "3.11"] # no particular need for 3.9 or 3.10 os: [macos-latest, ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # v4.5.0 with: python-version: ${{ matrix.python-version }} - name: Install dependencies From 31995e7e6ddf9194a4071bf7eab7da5150f6988b Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Tue, 2 May 2023 21:27:19 +0200 Subject: [PATCH 601/719] Make GitHub Dependabot keep the GitHub Actions up to date (#1082) --- .github/dependabot.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..c963e3c8b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + + - package-ecosystem: "github-actions" + commit-message: + include: "scope" + prefix: "Actions" + directory: "/" + labels: + - "enhancement" + schedule: + interval: "weekly" From b98c7763e2ac75ab3d9025737ad1b2fbe8f0a7e7 Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Tue, 2 May 2023 15:32:58 -0400 Subject: [PATCH 602/719] tomli should be installed by yapf, toml no longer required (#1086) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dd4b71b13..3979432fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: python -m pip install --upgrade pip - name: Lint with flake8 run: | - python -m pip install toml flake8 + python -m pip install flake8 flake8 . --statistics - name: Test with pytest run: | From e98e567de830478ea3e2dd4649ec27ba812c5fc4 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Tue, 2 May 2023 21:35:09 +0200 Subject: [PATCH 603/719] pre-commit: Mass-apply end-of-file-fixer (#1078) --- .gitignore | 1 - yapf/third_party/yapf_diff/LICENSE | 1 - 2 files changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index da8e42b5e..51c8f0291 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,3 @@ /.idea /.venv*/ - diff --git a/yapf/third_party/yapf_diff/LICENSE b/yapf/third_party/yapf_diff/LICENSE index f9dc50615..bd8b243df 100644 --- a/yapf/third_party/yapf_diff/LICENSE +++ b/yapf/third_party/yapf_diff/LICENSE @@ -216,4 +216,3 @@ conflicts with the conditions of the GPLv2, you may retroactively and prospectively choose to deem waived or otherwise exclude such Section(s) of the License, but only in their entirety and only with respect to the Combined Software. - From cbe0a408f1e5c709dab058bcff79095e4f78570b Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Tue, 2 May 2023 21:36:24 +0200 Subject: [PATCH 604/719] pre-commit: Mass-apply double-quote-string-fixer (#1079) --- yapf/__init__.py | 2 +- yapf/yapflib/file_resources.py | 10 +++++----- yapf/yapflib/style.py | 6 +++--- yapftests/file_resources_test.py | 4 ++-- yapftests/format_token_test.py | 2 +- yapftests/yapf_test.py | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index 99a4d6158..f09518c3e 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -77,7 +77,7 @@ def main(argv): while True: # Test that sys.stdin has the "closed" attribute. When using pytest, it # co-opts sys.stdin, which makes the "main_tests.py" fail. This is gross. - if hasattr(sys.stdin, "closed") and sys.stdin.closed: + if hasattr(sys.stdin, 'closed') and sys.stdin.closed: break try: # Use 'raw_input' instead of 'sys.stdin.read', because otherwise the diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 1dcadaec7..31be6f6c5 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -56,8 +56,8 @@ def _GetExcludePatternsFromPyprojectToml(filename): import tomli as tomllib except ImportError: raise errors.YapfError( - "tomli package is needed for using pyproject.toml as a " - "configuration file") + 'tomli package is needed for using pyproject.toml as a ' + 'configuration file') if os.path.isfile(filename) and os.access(filename, os.R_OK): with open(filename, 'rb') as fd: @@ -141,8 +141,8 @@ def GetDefaultStyleForDir(dirname, default_style=style.DEFAULT_STYLE): import tomli as tomllib except ImportError: raise errors.YapfError( - "tomli package is needed for using pyproject.toml as a " - "configuration file") + 'tomli package is needed for using pyproject.toml as a ' + 'configuration file') pyproject_toml = tomllib.load(fd) style_dict = pyproject_toml.get('tool', {}).get('yapf', None) @@ -205,7 +205,7 @@ def _FindPythonFiles(filenames, recursive, exclude): """Find all Python files.""" if exclude and any(e.startswith('./') for e in exclude): raise errors.YapfError("path in '--exclude' should not start with ./") - exclude = exclude and [e.rstrip("/" + os.path.sep) for e in exclude] + exclude = exclude and [e.rstrip('/' + os.path.sep) for e in exclude] python_files = [] for filename in filenames: diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 3e5f5eb3e..a341f0e92 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -753,12 +753,12 @@ def _CreateConfigParserFromConfigFile(config_filename): import tomli as tomllib except ImportError: raise errors.YapfError( - "tomli package is needed for using pyproject.toml as a " - "configuration file") + 'tomli package is needed for using pyproject.toml as a ' + 'configuration file') with open(config_filename, 'rb') as style_file: pyproject_toml = tomllib.load(style_file) - style_dict = pyproject_toml.get("tool", {}).get("yapf", None) + style_dict = pyproject_toml.get('tool', {}).get('yapf', None) if style_dict is None: raise StyleConfigError( 'Unable to find section [tool.yapf] in {0}'.format(config_filename)) diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index b31001c1c..30b367324 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -390,7 +390,7 @@ def test_find_with_excluded_dirs(self): ])) self.assertEqual( - found, ['test3/foo/bar/bas/xxx/testfile3.py'.replace("/", os.path.sep)]) + found, ['test3/foo/bar/bas/xxx/testfile3.py'.replace('/', os.path.sep)]) found = sorted( file_resources.GetCommandLineFiles(['.'], @@ -401,7 +401,7 @@ def test_find_with_excluded_dirs(self): ])) self.assertEqual( - found, ['./test2/testinner/testfile2.py'.replace("/", os.path.sep)]) + found, ['./test2/testinner/testfile2.py'.replace('/', os.path.sep)]) def test_find_with_excluded_current_dir(self): with self.assertRaises(errors.YapfError): diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index 6ea24af63..18ebe48d5 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -70,7 +70,7 @@ def testSimple(self): pytree.Leaf(token.STRING, "'hello world'"), 'STRING') self.assertEqual( "FormatToken(name=DOCSTRING, value='hello world', column=0, " - "lineno=0, splitpenalty=0)", str(tok)) + 'lineno=0, splitpenalty=0)', str(tok)) self.assertTrue(tok.is_string) tok = format_token.FormatToken( diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 393a9f9d8..5e9eefe2b 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -484,7 +484,7 @@ def testInPlaceReformattingWindowsNewLine(self): self.assertEqual(reformatted_code, expected_formatted_code) def testInPlaceReformattingNoNewLine(self): - unformatted_code = textwrap.dedent(u"def foo(): x = 37") + unformatted_code = textwrap.dedent(u'def foo(): x = 37') expected_formatted_code = textwrap.dedent("""\ def foo(): x = 37 From 62419c65f012b9990f5a83cbf6252aa7938aaa8c Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Tue, 2 May 2023 21:36:43 +0200 Subject: [PATCH 605/719] pre-commit: Mass-apply trailing-whitespace (#1080) --- README.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 889f4ef11..b6bc7eb98 100644 --- a/README.rst +++ b/README.rst @@ -665,11 +665,11 @@ Knobs before each trailing comment) or list of values (representing alignment column values; trailing comments within a block will be aligned to the first column value that is greater than the maximum - line length within the block). - - **Note:** Lists of values may need to be quoted in some contexts + line length within the block). + + **Note:** Lists of values may need to be quoted in some contexts (eg. shells or editor config files). - + For example: With ``spaces_before_comment=5``: From dd81d9b213c33671861e6c362b9fb1e351a858e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 May 2023 19:38:59 +0000 Subject: [PATCH 606/719] Actions(deps): Bump actions/setup-python from 4.5.0 to 4.6.0 (#1087) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4.5.0 to 4.6.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435...57ded4d7d5e986d7296eab16560982c6dd7c923b) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3979432fd..6cc5028c7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # v4.5.0 + uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b # v4.6.0 with: python-version: ${{ matrix.python-version }} - name: Install dependencies From 4480b11fcc8d4a35cedb0aa4b2a485f6c7a1e9bd Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Tue, 2 May 2023 21:55:49 +0200 Subject: [PATCH 607/719] Document Python support (i.e. get existing docs back in sync) (#1083) * HACKING.rst: Update for Python >=3.7 requirement * CHANGELOG: Document Python <3.7 departure and Python 3.11 arrival * pyparser.py: Update for Python >=3.7 requirement * README.rst: Drop Python 2.7 leftover --- CHANGELOG | 6 ++++++ HACKING.rst | 2 +- README.rst | 6 ------ yapf/pyparser/pyparser.py | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 98954d0b6..a76e19aec 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,12 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.40.0] UNRELEASED +### Added +- Support for Python 3.11 +### Removed +- Support for Python <3.7 + ## [0.33.0] 2023-04-18 ### Added - Add a new Python parser to generate logical lines. diff --git a/HACKING.rst b/HACKING.rst index cc27c5ac7..297101a85 100644 --- a/HACKING.rst +++ b/HACKING.rst @@ -13,7 +13,7 @@ Releasing a new version ----------------------- * Run tests: python setup.py test - [don't forget to run with Python 2.7 and 3.6] + [don't forget to run with at least Python 3.7 and 3.11] * Bump version in yapf/__init__.py diff --git a/README.rst b/README.rst index b6bc7eb98..c4c56fbae 100644 --- a/README.rst +++ b/README.rst @@ -54,12 +54,6 @@ To install YAPF from PyPI: $ pip install yapf -(optional) If you are using Python 2.7 and want to enable multiprocessing: - -.. code-block:: shell - - $ pip install futures - YAPF is still considered in "alpha" stage, and the released version may change often; therefore, the best way to keep up-to-date with the latest development is to clone this repository. diff --git a/yapf/pyparser/pyparser.py b/yapf/pyparser/pyparser.py index f32aaab80..a7b4e33c3 100644 --- a/yapf/pyparser/pyparser.py +++ b/yapf/pyparser/pyparser.py @@ -15,8 +15,8 @@ Parse Python code into a list of logical lines, represented by LogicalLine objects. This uses Python's tokenizer to generate the tokens. As such, YAPF must -be run with the appropriate Python version---Python 2.7 for Python2 code, Python -3.x for Python3 code, etc. +be run with the appropriate Python version---Python >=3.7 for Python 3.7 code, +Python >=3.8 for Python 3.8 code, etc. This parser uses Python's native "tokenizer" module to generate a list of tokens for the source code. It then uses Python's native "ast" module to assign From 04decc4970ef061a17b109113bc24dc945b31b1a Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Tue, 2 May 2023 22:01:02 +0200 Subject: [PATCH 608/719] Remove more Python 2 leftovers (tool 2to3) (#1084) --- yapf/__init__.py | 1 - yapf/pytree/subtype_assigner.py | 4 +- yapf/third_party/yapf_diff/yapf_diff.py | 1 - yapf/yapflib/object_state.py | 4 - yapf/yapflib/reformatter.py | 2 - yapftests/blank_line_calculator_test.py | 16 ++-- yapftests/comment_splicer_test.py | 3 +- yapftests/file_resources_test.py | 14 ++-- yapftests/line_joiner_test.py | 12 +-- yapftests/reformatter_style_config_test.py | 8 +- yapftests/style_test.py | 20 ++--- yapftests/yapf_test.py | 96 +++++++++++----------- 12 files changed, 86 insertions(+), 95 deletions(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index f09518c3e..14c693d33 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -25,7 +25,6 @@ If no filenames are specified, YAPF reads the code from stdin. """ -from __future__ import print_function import argparse import logging diff --git a/yapf/pytree/subtype_assigner.py b/yapf/pytree/subtype_assigner.py index c93d69df2..97b0e501e 100644 --- a/yapf/pytree/subtype_assigner.py +++ b/yapf/pytree/subtype_assigner.py @@ -458,7 +458,7 @@ def _InsertPseudoParentheses(node): lparen = pytree.Leaf( grammar_token.LPAR, - u'(', + '(', context=('', (first.get_lineno(), first.column - 1))) last_lineno = last.get_lineno() if last.type == grammar_token.STRING and '\n' in last.value: @@ -469,7 +469,7 @@ def _InsertPseudoParentheses(node): else: last_column = last.column + len(last.value) + 1 rparen = pytree.Leaf( - grammar_token.RPAR, u')', context=('', (last_lineno, last_column))) + grammar_token.RPAR, ')', context=('', (last_lineno, last_column))) lparen.is_pseudo = True rparen.is_pseudo = True diff --git a/yapf/third_party/yapf_diff/yapf_diff.py b/yapf/third_party/yapf_diff/yapf_diff.py index de73667d0..adc6fe452 100644 --- a/yapf/third_party/yapf_diff/yapf_diff.py +++ b/yapf/third_party/yapf_diff/yapf_diff.py @@ -24,7 +24,6 @@ should be careful to ensure that the path in the diff is correct relative to the current working directory. """ -from __future__ import absolute_import, division, print_function import argparse import difflib diff --git a/yapf/yapflib/object_state.py b/yapf/yapflib/object_state.py index 2b7c068ea..cb8c51b05 100644 --- a/yapf/yapflib/object_state.py +++ b/yapf/yapflib/object_state.py @@ -18,10 +18,6 @@ requirements. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from functools import lru_cache from yapf.yapflib import style diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 14e0bde70..f8c4bc407 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -19,8 +19,6 @@ Reformat(): the main function exported by this module. """ -from __future__ import unicode_literals - import collections import heapq import re diff --git a/yapftests/blank_line_calculator_test.py b/yapftests/blank_line_calculator_test.py index 18fa83e0b..e8613b7d2 100644 --- a/yapftests/blank_line_calculator_test.py +++ b/yapftests/blank_line_calculator_test.py @@ -278,7 +278,7 @@ class DeployAPIHTTPError(Error): self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testLinesOnRangeBoundary(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def A(): pass @@ -292,7 +292,7 @@ def D(): # 9 def E(): pass """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def A(): pass @@ -315,7 +315,7 @@ def E(): self.assertTrue(changed) def testLinesRangeBoundaryNotOutside(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def A(): pass @@ -329,7 +329,7 @@ def B(): # 6 def C(): pass """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def A(): pass @@ -348,7 +348,7 @@ def C(): self.assertFalse(changed) def testLinesRangeRemove(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def A(): pass @@ -363,7 +363,7 @@ def B(): # 6 def C(): pass """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def A(): pass @@ -382,7 +382,7 @@ def C(): self.assertTrue(changed) def testLinesRangeRemoveSome(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def A(): pass @@ -398,7 +398,7 @@ def B(): # 7 def C(): pass """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def A(): pass diff --git a/yapftests/comment_splicer_test.py b/yapftests/comment_splicer_test.py index f33491cd6..36c25b2d1 100644 --- a/yapftests/comment_splicer_test.py +++ b/yapftests/comment_splicer_test.py @@ -37,8 +37,7 @@ def _AssertNodeIsComment(self, node, text_in_comment=None): def _FindNthChildNamed(self, node, name, n=1): for i, child in enumerate( - filter(lambda c: pytree_utils.NodeName(c) == name, - node.pre_order())): + [c for c in node.pre_order() if pytree_utils.NodeName(c) == name]): if i == n - 1: return child raise RuntimeError('No Nth child for n={0}'.format(n)) diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 30b367324..888dea473 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -429,25 +429,25 @@ def test_empty_without_py_extension(self): def test_python_shebang(self): file1 = os.path.join(self.test_tmpdir, 'testfile1') with open(file1, 'w') as f: - f.write(u'#!/usr/bin/python\n') + f.write('#!/usr/bin/python\n') self.assertTrue(file_resources.IsPythonFile(file1)) file2 = os.path.join(self.test_tmpdir, 'testfile2.run') with open(file2, 'w') as f: - f.write(u'#! /bin/python2\n') + f.write('#! /bin/python2\n') self.assertTrue(file_resources.IsPythonFile(file1)) def test_with_latin_encoding(self): file1 = os.path.join(self.test_tmpdir, 'testfile1') with codecs.open(file1, mode='w', encoding='latin-1') as f: - f.write(u'#! /bin/python2\n') + f.write('#! /bin/python2\n') self.assertTrue(file_resources.IsPythonFile(file1)) def test_with_invalid_encoding(self): file1 = os.path.join(self.test_tmpdir, 'testfile1') with open(file1, 'w') as f: - f.write(u'#! /bin/python2\n') - f.write(u'# -*- coding: iso-3-14159 -*-\n') + f.write('#! /bin/python2\n') + f.write('# -*- coding: iso-3-14159 -*-\n') self.assertFalse(file_resources.IsPythonFile(file1)) @@ -491,7 +491,7 @@ def tearDownClass(cls): # pylint: disable=g-missing-super-call shutil.rmtree(cls.test_tmpdir) def test_write_to_file(self): - s = u'foobar\n' + s = 'foobar\n' with utils.NamedTempFile(dirname=self.test_tmpdir) as (f, fname): file_resources.WriteReformattedCode( fname, s, in_place=True, encoding='utf-8') @@ -501,7 +501,7 @@ def test_write_to_file(self): self.assertEqual(f2.read(), s) def test_write_to_stdout(self): - s = u'foobar' + s = 'foobar' stream = BufferedByteStream() with utils.stdout_redirector(stream): file_resources.WriteReformattedCode( diff --git a/yapftests/line_joiner_test.py b/yapftests/line_joiner_test.py index 2eaf16478..4fb55f4a3 100644 --- a/yapftests/line_joiner_test.py +++ b/yapftests/line_joiner_test.py @@ -39,20 +39,20 @@ def _CheckLineJoining(self, code, join_lines): self.assertCodeEqual(line_joiner.CanMergeMultipleLines(llines), join_lines) def testSimpleSingleLineStatement(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent("""\ if isinstance(a, int): continue """) self._CheckLineJoining(code, join_lines=True) def testSimpleMultipleLineStatement(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent("""\ if isinstance(b, int): continue """) self._CheckLineJoining(code, join_lines=False) def testSimpleMultipleLineComplexStatement(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent("""\ if isinstance(c, int): while True: continue @@ -60,19 +60,19 @@ def testSimpleMultipleLineComplexStatement(self): self._CheckLineJoining(code, join_lines=False) def testSimpleMultipleLineStatementWithComment(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent("""\ if isinstance(d, int): continue # We're pleased that d's an int. """) self._CheckLineJoining(code, join_lines=True) def testSimpleMultipleLineStatementWithLargeIndent(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent("""\ if isinstance(e, int): continue """) self._CheckLineJoining(code, join_lines=True) def testOverColumnLimit(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent("""\ if instance(bbbbbbbbbbbbbbbbbbbbbbbbb, int): cccccccccccccccccccccccccc = ddddddddddddddddddddd """) # noqa self._CheckLineJoining(code, join_lines=False) diff --git a/yapftests/reformatter_style_config_test.py b/yapftests/reformatter_style_config_test.py index c5726cb30..befd27b9e 100644 --- a/yapftests/reformatter_style_config_test.py +++ b/yapftests/reformatter_style_config_test.py @@ -30,11 +30,11 @@ def setUp(self): def testSetGlobalStyle(self): try: style.SetGlobalStyle(style.CreateYapfStyle()) - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ for i in range(5): print('bar') """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ for i in range(5): print('bar') """) @@ -45,11 +45,11 @@ def testSetGlobalStyle(self): style.SetGlobalStyle(style.CreatePEP8Style()) style.DEFAULT_STYLE = self.current_style - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ for i in range(5): print('bar') """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ for i in range(5): print('bar') """) diff --git a/yapftests/style_test.py b/yapftests/style_test.py index d2203d9ac..731c1d98b 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -136,7 +136,7 @@ def tearDownClass(cls): # pylint: disable=g-missing-super-call shutil.rmtree(cls.test_tmpdir) def testDefaultBasedOnStyle(self): - cfg = textwrap.dedent(u'''\ + cfg = textwrap.dedent('''\ [style] continuation_indent_width = 20 ''') @@ -146,7 +146,7 @@ def testDefaultBasedOnStyle(self): self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) def testDefaultBasedOnPEP8Style(self): - cfg = textwrap.dedent(u'''\ + cfg = textwrap.dedent('''\ [style] based_on_style = pep8 continuation_indent_width = 40 @@ -157,7 +157,7 @@ def testDefaultBasedOnPEP8Style(self): self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 40) def testDefaultBasedOnGoogleStyle(self): - cfg = textwrap.dedent(u'''\ + cfg = textwrap.dedent('''\ [style] based_on_style = google continuation_indent_width = 20 @@ -168,7 +168,7 @@ def testDefaultBasedOnGoogleStyle(self): self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) def testDefaultBasedOnFacebookStyle(self): - cfg = textwrap.dedent(u'''\ + cfg = textwrap.dedent('''\ [style] based_on_style = facebook continuation_indent_width = 20 @@ -179,7 +179,7 @@ def testDefaultBasedOnFacebookStyle(self): self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) def testBoolOptionValue(self): - cfg = textwrap.dedent(u'''\ + cfg = textwrap.dedent('''\ [style] based_on_style = pep8 SPLIT_BEFORE_NAMED_ASSIGNS=False @@ -192,7 +192,7 @@ def testBoolOptionValue(self): self.assertEqual(cfg['SPLIT_BEFORE_LOGICAL_OPERATOR'], True) def testStringListOptionValue(self): - cfg = textwrap.dedent(u'''\ + cfg = textwrap.dedent('''\ [style] based_on_style = pep8 I18N_FUNCTION_CALL = N_, V_, T_ @@ -208,7 +208,7 @@ def testErrorNoStyleFile(self): style.CreateStyleFromConfig('/8822/xyznosuchfile') def testErrorNoStyleSection(self): - cfg = textwrap.dedent(u'''\ + cfg = textwrap.dedent('''\ [s] indent_width=2 ''') @@ -218,7 +218,7 @@ def testErrorNoStyleSection(self): style.CreateStyleFromConfig(filepath) def testErrorUnknownStyleOption(self): - cfg = textwrap.dedent(u'''\ + cfg = textwrap.dedent('''\ [style] indent_width=2 hummus=2 @@ -246,7 +246,7 @@ def testPyprojectTomlParseYapfSection(self): except ImportError: return - cfg = textwrap.dedent(u'''\ + cfg = textwrap.dedent('''\ [tool.yapf] based_on_style = "pep8" continuation_indent_width = 40 @@ -307,7 +307,7 @@ def testDefaultBasedOnStyleNotStrict(self): self.assertEqual(cfg['INDENT_WIDTH'], 2) def testDefaultBasedOnExplicitlyUnicodeTypeString(self): - cfg = style.CreateStyleFromConfig(u'{}') + cfg = style.CreateStyleFromConfig('{}') self.assertIsInstance(cfg, dict) def testDefaultBasedOnDetaultTypeString(self): diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 5e9eefe2b..4fdb89251 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -83,15 +83,15 @@ def assertCodeEqual(self, expected_code, code): self.fail(msg) def testFormatFile(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ if True: pass """) - expected_formatted_code_pep8 = textwrap.dedent(u"""\ + expected_formatted_code_pep8 = textwrap.dedent("""\ if True: pass """) - expected_formatted_code_yapf = textwrap.dedent(u"""\ + expected_formatted_code_yapf = textwrap.dedent("""\ if True: pass """) @@ -103,7 +103,7 @@ def testFormatFile(self): self.assertCodeEqual(expected_formatted_code_yapf, formatted_code) def testDisableLinesPattern(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ if a: b # yapf: disable @@ -111,7 +111,7 @@ def testDisableLinesPattern(self): if h: i """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ if a: b # yapf: disable @@ -124,7 +124,7 @@ def testDisableLinesPattern(self): self.assertCodeEqual(expected_formatted_code, formatted_code) def testDisableAndReenableLinesPattern(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ if a: b # yapf: disable @@ -133,7 +133,7 @@ def testDisableAndReenableLinesPattern(self): if h: i """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ if a: b # yapf: disable @@ -147,7 +147,7 @@ def testDisableAndReenableLinesPattern(self): self.assertCodeEqual(expected_formatted_code, formatted_code) def testFmtOnOff(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ if a: b # fmt: off @@ -156,7 +156,7 @@ def testFmtOnOff(self): if h: i """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ if a: b # fmt: off @@ -170,7 +170,7 @@ def testFmtOnOff(self): self.assertCodeEqual(expected_formatted_code, formatted_code) def testDisablePartOfMultilineComment(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ if a: b # This is a multiline comment that disables YAPF. @@ -182,7 +182,7 @@ def testDisablePartOfMultilineComment(self): if h: i """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ if a: b # This is a multiline comment that disables YAPF. @@ -197,7 +197,7 @@ def testDisablePartOfMultilineComment(self): formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(expected_formatted_code, formatted_code) - code = textwrap.dedent(u"""\ + code = textwrap.dedent("""\ def foo_function(): # some comment # yapf: disable @@ -214,7 +214,7 @@ def foo_function(): self.assertCodeEqual(code, formatted_code) def testEnabledDisabledSameComment(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent("""\ # yapf: disable a(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, ccccccccccccccccccccccccccccccc, ddddddddddddddddddddddd, eeeeeeeeeeeeeeeeeeeeeeeeeee) # yapf: enable @@ -227,21 +227,21 @@ def testEnabledDisabledSameComment(self): self.assertCodeEqual(code, formatted_code) def testFormatFileLinesSelection(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ if a: b if f: g if h: i """) - expected_formatted_code_lines1and2 = textwrap.dedent(u"""\ + expected_formatted_code_lines1and2 = textwrap.dedent("""\ if a: b if f: g if h: i """) - expected_formatted_code_lines3 = textwrap.dedent(u"""\ + expected_formatted_code_lines3 = textwrap.dedent("""\ if a: b if f: g @@ -257,17 +257,17 @@ def testFormatFileLinesSelection(self): self.assertCodeEqual(expected_formatted_code_lines3, formatted_code) def testFormatFileDiff(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ if True: pass """) with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: diff, _, _ = yapf_api.FormatFile(filepath, print_diff=True) - self.assertIn(u'+ pass', diff) + self.assertIn('+ pass', diff) def testFormatFileInPlace(self): - unformatted_code = u'True==False\n' - formatted_code = u'True == False\n' + unformatted_code = 'True==False\n' + formatted_code = 'True == False\n' with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: result, _, _ = yapf_api.FormatFile(filepath, in_place=True) self.assertEqual(result, None) @@ -292,7 +292,7 @@ def testNoFile(self): "[Errno 2] No such file or directory: 'not_a_file.py'\n") def testCommentsUnformatted(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent("""\ foo = [# A list of things # bork 'one', @@ -304,7 +304,7 @@ def testCommentsUnformatted(self): self.assertCodeEqual(code, formatted_code) def testDisabledHorizontalFormattingOnNewLine(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent("""\ # yapf: disable a = [ 1] @@ -315,12 +315,12 @@ def testDisabledHorizontalFormattingOnNewLine(self): self.assertCodeEqual(code, formatted_code) def testSplittingSemicolonStatements(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def f(): x = y + 42 ; z = n * 42 if True: a += 1 ; b += 1; c += 1 """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def f(): x = y + 42 z = n * 42 @@ -334,12 +334,12 @@ def f(): self.assertCodeEqual(expected_formatted_code, formatted_code) def testSemicolonStatementsDisabled(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def f(): x = y + 42 ; z = n * 42 # yapf: disable if True: a += 1 ; b += 1; c += 1 """) - expected_formatted_code = textwrap.dedent(u"""\ + expected_formatted_code = textwrap.dedent("""\ def f(): x = y + 42 ; z = n * 42 # yapf: disable if True: @@ -352,7 +352,7 @@ def f(): self.assertCodeEqual(expected_formatted_code, formatted_code) def testDisabledSemiColonSeparatedStatements(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent("""\ # yapf: disable if True: a ; b """) @@ -361,7 +361,7 @@ def testDisabledSemiColonSeparatedStatements(self): self.assertCodeEqual(code, formatted_code) def testDisabledMultilineStringInDictionary(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent("""\ # yapf: disable A = [ @@ -380,7 +380,7 @@ def testDisabledMultilineStringInDictionary(self): self.assertCodeEqual(code, formatted_code) def testDisabledWithPrecedingText(self): - code = textwrap.dedent(u"""\ + code = textwrap.dedent("""\ # TODO(fix formatting): yapf: disable A = [ @@ -399,7 +399,7 @@ def testDisabledWithPrecedingText(self): self.assertCodeEqual(code, formatted_code) def testCRLFLineEnding(self): - code = u'class _():\r\n pass\r\n' + code = 'class _():\r\n pass\r\n' with utils.TempFileContents(self.test_tmpdir, code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='yapf') self.assertCodeEqual(code, formatted_code) @@ -445,7 +445,7 @@ def assertYapfReformats(self, self.assertMultiLineEqual(reformatted_code.decode('utf-8'), expected) def testInPlaceReformatting(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ def foo(): x = 37 """) @@ -462,8 +462,8 @@ def foo(): self.assertEqual(reformatted_code, expected_formatted_code) def testInPlaceReformattingBlank(self): - unformatted_code = u'\n\n' - expected_formatted_code = u'\n' + unformatted_code = '\n\n' + expected_formatted_code = '\n' with utils.TempFileContents( self.test_tmpdir, unformatted_code, suffix='.py') as filepath: p = subprocess.Popen(YAPF_BINARY + ['--in-place', filepath]) @@ -473,8 +473,8 @@ def testInPlaceReformattingBlank(self): self.assertEqual(reformatted_code, expected_formatted_code) def testInPlaceReformattingWindowsNewLine(self): - unformatted_code = u'\r\n\r\n' - expected_formatted_code = u'\r\n' + unformatted_code = '\r\n\r\n' + expected_formatted_code = '\r\n' with utils.TempFileContents( self.test_tmpdir, unformatted_code, suffix='.py') as filepath: p = subprocess.Popen(YAPF_BINARY + ['--in-place', filepath]) @@ -484,7 +484,7 @@ def testInPlaceReformattingWindowsNewLine(self): self.assertEqual(reformatted_code, expected_formatted_code) def testInPlaceReformattingNoNewLine(self): - unformatted_code = textwrap.dedent(u'def foo(): x = 37') + unformatted_code = textwrap.dedent('def foo(): x = 37') expected_formatted_code = textwrap.dedent("""\ def foo(): x = 37 @@ -498,8 +498,8 @@ def foo(): self.assertEqual(reformatted_code, expected_formatted_code) def testInPlaceReformattingEmpty(self): - unformatted_code = u'' - expected_formatted_code = u'' + unformatted_code = '' + expected_formatted_code = '' with utils.TempFileContents( self.test_tmpdir, unformatted_code, suffix='.py') as filepath: p = subprocess.Popen(YAPF_BINARY + ['--in-place', filepath]) @@ -551,7 +551,7 @@ def foo(): # trail def foo(): # trail x = 37 """) - style_file = textwrap.dedent(u'''\ + style_file = textwrap.dedent('''\ [style] based_on_style = yapf spaces_before_comment = 4 @@ -571,7 +571,7 @@ def testSetCustomStyleSpacesBeforeComment(self): a_very_long_statement_that_extends_way_beyond # Comment short # This is a shorter statement """) # noqa - style_file = textwrap.dedent(u'''\ + style_file = textwrap.dedent('''\ [style] spaces_before_comment = 15, 20 ''') @@ -591,7 +591,7 @@ def testReadSingleLineCodeFromStdin(self): self.assertYapfReformats(unformatted_code, expected_formatted_code) def testEncodingVerification(self): - unformatted_code = textwrap.dedent(u"""\ + unformatted_code = textwrap.dedent("""\ '''The module docstring.''' # -*- coding: utf-8 -*- def f(): @@ -1186,7 +1186,7 @@ def testCoalesceBrackets(self): """) with utils.NamedTempFile(dirname=self.test_tmpdir, mode='w') as (f, name): f.write( - textwrap.dedent(u'''\ + textwrap.dedent('''\ [style] column_limit=82 coalesce_brackets = True @@ -1278,7 +1278,7 @@ def foo_function(): if True: pass """ # noqa: W191,E101 - style_contents = u"""\ + style_contents = """\ [style] based_on_style = yapf USE_TABS = true @@ -1302,7 +1302,7 @@ def f(): 'world', ] """ # noqa: W191,E101 - style_contents = u"""\ + style_contents = """\ [style] based_on_style = yapf USE_TABS = true @@ -1327,7 +1327,7 @@ def foo_function( 'world', ] """ # noqa: W191,E101 - style_contents = u"""\ + style_contents = """\ [style] based_on_style = yapf USE_TABS = true @@ -1355,7 +1355,7 @@ def foo_function(arg1, arg2, 'world', ] """ # noqa: W191,E101 - style_contents = u"""\ + style_contents = """\ [style] based_on_style = yapf USE_TABS = true @@ -1383,7 +1383,7 @@ def foo_function( 'world', ] """ - style_contents = u"""\ + style_contents = """\ [style] based_on_style = yapf COLUMN_LIMIT=32 @@ -1410,7 +1410,7 @@ def foo_function(arg1, arg2, 'world', ] """ - style_contents = u"""\ + style_contents = """\ [style] based_on_style = yapf COLUMN_LIMIT=32 From ee4a5affda6344e75b13b5d33856d686d93eb895 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Tue, 2 May 2023 22:53:36 +0200 Subject: [PATCH 609/719] Resolve py3compat.py (#1088) --- yapf/__init__.py | 21 +++++++++++++++--- yapf/yapflib/py3compat.py | 34 ----------------------------- yapftests/main_test.py | 8 +++---- yapftests/reformatter_basic_test.py | 6 +++-- 4 files changed, 25 insertions(+), 44 deletions(-) delete mode 100644 yapf/yapflib/py3compat.py diff --git a/yapf/__init__.py b/yapf/__init__.py index 14c693d33..39b15c9d5 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -27,19 +27,34 @@ """ import argparse +import codecs +import io import logging import os import sys from yapf.yapflib import errors from yapf.yapflib import file_resources -from yapf.yapflib import py3compat from yapf.yapflib import style from yapf.yapflib import yapf_api __version__ = '0.33.0' +def _raw_input(): + wrapper = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8') + return wrapper.buffer.raw.readall().decode('utf-8') + + +def _removeBOM(source): + """Remove any Byte-order-Mark bytes from the beginning of a file.""" + bom = codecs.BOM_UTF8 + bom = bom.decode('utf-8') + if source.startswith(bom): + return source[len(bom):] + return source + + def main(argv): """Main program. @@ -83,7 +98,7 @@ def main(argv): # user will need to hit 'Ctrl-D' more than once if they're inputting # the program by hand. 'raw_input' throws an EOFError exception if # 'Ctrl-D' is pressed, which makes it easy to bail out of this loop. - original_source.append(py3compat.raw_input()) + original_source.append(_raw_input()) except EOFError: break except KeyboardInterrupt: @@ -93,7 +108,7 @@ def main(argv): style_config = file_resources.GetDefaultStyleForDir(os.getcwd()) source = [line.rstrip() for line in original_source] - source[0] = py3compat.removeBOM(source[0]) + source[0] = _removeBOM(source[0]) try: reformatted_source, _ = yapf_api.FormatCode( diff --git a/yapf/yapflib/py3compat.py b/yapf/yapflib/py3compat.py deleted file mode 100644 index c95d4b545..000000000 --- a/yapf/yapflib/py3compat.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2015 Google Inc. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Utilities for Python2 / Python3 compatibility.""" - -import codecs -import io -import sys - -PY38 = sys.version_info[0] >= 3 and sys.version_info[1] >= 8 - - -def raw_input(): - wrapper = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8') - return wrapper.buffer.raw.readall().decode('utf-8') - - -def removeBOM(source): - """Remove any Byte-order-Mark bytes from the beginning of a file.""" - bom = codecs.BOM_UTF8 - bom = bom.decode('utf-8') - if source.startswith(bom): - return source[len(bom):] - return source diff --git a/yapftests/main_test.py b/yapftests/main_test.py index 5b7347686..7241a023f 100644 --- a/yapftests/main_test.py +++ b/yapftests/main_test.py @@ -20,8 +20,6 @@ import unittest import yapf -from yapf.yapflib import py3compat - from yapftests import yapf_test_helper @@ -79,11 +77,11 @@ def patch_raw_input(lines=lines()): return next(lines) try: - orig_raw_import = yapf.py3compat.raw_input - yapf.py3compat.raw_input = patch_raw_input + orig_raw_import = yapf._raw_input + yapf._raw_input = patch_raw_input yield finally: - yapf.py3compat.raw_input = orig_raw_import + yapf._raw_input = orig_raw_import class RunMainTest(yapf_test_helper.YAPFTest): diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index a8b2fdd9b..2edbc3175 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -13,15 +13,17 @@ # limitations under the License. """Basic tests for yapf.reformatter.""" +import sys import textwrap import unittest -from yapf.yapflib import py3compat from yapf.yapflib import reformatter from yapf.yapflib import style from yapftests import yapf_test_helper +PY38 = sys.version_info[0] >= 3 and sys.version_info[1] >= 8 + class BasicReformatterTest(yapf_test_helper.YAPFTest): @@ -3162,7 +3164,7 @@ def testForceMultilineDict_False(self): finally: style.SetGlobalStyle(style.CreateYapfStyle()) - @unittest.skipUnless(py3compat.PY38, 'Requires Python 3.8') + @unittest.skipUnless(PY38, 'Requires Python 3.8') def testWalrus(self): unformatted_code = textwrap.dedent("""\ if (x := len([1]*1000)>100): From 727d2df217051b2e7df7d570c099957d7b65fc59 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Tue, 2 May 2023 22:54:21 +0200 Subject: [PATCH 610/719] Remove duplicate .pre-commit-*.yml files (#1089) Identical .yaml copies are still in place. Before: > # ls -1 .pre-commit-*.y* > .pre-commit-config.yaml > .pre-commit-config.yml > .pre-commit-hooks.yaml > .pre-commit-hooks.yml After: > # ls -1 .pre-commit-*.y* > .pre-commit-config.yaml > .pre-commit-hooks.yaml --- .pre-commit-config.yml | 30 ------------------------------ .pre-commit-hooks.yml | 9 --------- 2 files changed, 39 deletions(-) delete mode 100644 .pre-commit-config.yml delete mode 100644 .pre-commit-hooks.yml diff --git a/.pre-commit-config.yml b/.pre-commit-config.yml deleted file mode 100644 index 3bd65c26f..000000000 --- a/.pre-commit-config.yml +++ /dev/null @@ -1,30 +0,0 @@ -# File introduces automated checks triggered on git events -# to enable run `pip install pre-commit && pre-commit install` - -repos: - - repo: local - hooks: - - id: yapf - name: yapf - language: python - entry: yapf - args: [-i, -vv] - types: [python] - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.2.0 - hooks: - - id: trailing-whitespace - - id: check-docstring-first - - id: check-json - - id: check-added-large-files - - id: check-yaml - - id: debug-statements - - id: requirements-txt-fixer - - id: check-merge-conflict - - id: double-quote-string-fixer - - id: end-of-file-fixer - - id: sort-simple-yaml - - repo: meta - hooks: - - id: check-hooks-apply - - id: check-useless-excludes diff --git a/.pre-commit-hooks.yml b/.pre-commit-hooks.yml deleted file mode 100644 index 3eba1f2e7..000000000 --- a/.pre-commit-hooks.yml +++ /dev/null @@ -1,9 +0,0 @@ -# File configures YAPF to be used as a git hook with https://github.com/pre-commit/pre-commit - -- id: yapf - name: yapf - description: "A formatter for Python files." - entry: yapf - args: [-i] #inplace - language: python - types: [python] From 6c4b34cda19c789bd2b5c5c27ce6f72785aeab43 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Tue, 2 May 2023 23:20:03 +0200 Subject: [PATCH 611/719] Resolve py2 grammar (alternative to #776) (#1090) * Resolve use of Python 2 grammar + fix three related test cases * Simplify ParseCodeToTree with identical semantics --- yapf/pytree/pytree_utils.py | 29 +++++++------------------ yapftests/pytree_utils_test.py | 12 ++++------ yapftests/reformatter_buganizer_test.py | 2 +- 3 files changed, 13 insertions(+), 30 deletions(-) diff --git a/yapf/pytree/pytree_utils.py b/yapf/pytree/pytree_utils.py index 66a54e617..43ef8763d 100644 --- a/yapf/pytree/pytree_utils.py +++ b/yapf/pytree/pytree_utils.py @@ -84,11 +84,10 @@ def LastLeafNode(node): # context where a keyword is disallowed). # It forgets to do the same for 'exec' though. Luckily, Python is amenable to # monkey-patching. -_GRAMMAR_FOR_PY3 = pygram.python_grammar_no_print_statement.copy() -del _GRAMMAR_FOR_PY3.keywords['exec'] - -_GRAMMAR_FOR_PY2 = pygram.python_grammar.copy() -del _GRAMMAR_FOR_PY2.keywords['nonlocal'] +# Note that pygram.python_grammar_no_print_and_exec_statement with "_and_exec" +# will require Python >=3.8. +_PYTHON_GRAMMAR = pygram.python_grammar_no_print_statement.copy() +del _PYTHON_GRAMMAR.keywords['exec'] def ParseCodeToTree(code): @@ -110,24 +109,12 @@ def ParseCodeToTree(code): code += os.linesep try: - # Try to parse using a Python 3 grammar, which is more permissive (print and - # exec are not keywords). - parser_driver = driver.Driver(_GRAMMAR_FOR_PY3, convert=pytree.convert) + parser_driver = driver.Driver(_PYTHON_GRAMMAR, convert=pytree.convert) tree = parser_driver.parse_string(code, debug=False) except parse.ParseError: - # Now try to parse using a Python 2 grammar; If this fails, then - # there's something else wrong with the code. - try: - parser_driver = driver.Driver(_GRAMMAR_FOR_PY2, convert=pytree.convert) - tree = parser_driver.parse_string(code, debug=False) - except parse.ParseError: - # Raise a syntax error if the code is invalid python syntax. - try: - ast.parse(code) - except SyntaxError as e: - raise e - else: - raise + # Raise a syntax error if the code is invalid python syntax. + ast.parse(code) + raise return _WrapEndMarker(tree) diff --git a/yapftests/pytree_utils_test.py b/yapftests/pytree_utils_test.py index c175f833e..c55f668b4 100644 --- a/yapftests/pytree_utils_test.py +++ b/yapftests/pytree_utils_test.py @@ -63,16 +63,12 @@ def testPrintFunctionToTree(self): self.assertEqual('simple_stmt', pytree_utils.NodeName(tree.children[0])) def testPrintStatementToTree(self): - tree = pytree_utils.ParseCodeToTree('print "hello world"\n') - self.assertEqual('file_input', pytree_utils.NodeName(tree)) - self.assertEqual(2, len(tree.children)) - self.assertEqual('simple_stmt', pytree_utils.NodeName(tree.children[0])) + with self.assertRaises(SyntaxError): + pytree_utils.ParseCodeToTree('print "hello world"\n') def testClassNotLocal(self): - tree = pytree_utils.ParseCodeToTree('class nonlocal: pass\n') - self.assertEqual('file_input', pytree_utils.NodeName(tree)) - self.assertEqual(2, len(tree.children)) - self.assertEqual('classdef', pytree_utils.NodeName(tree.children[0])) + with self.assertRaises(SyntaxError): + pytree_utils.ParseCodeToTree('class nonlocal: pass\n') class InsertNodesBeforeAfterTest(unittest.TestCase): diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 54a62b588..254000840 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -511,7 +511,7 @@ def testB38343525(self): # This does bar. @arg.String('some_path_to_a_file', required=True) def f(): - print 1 + print(1) """ llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) From afdee7887e42bd0ada3514d7634f4a644de32579 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 4 May 2023 17:15:09 -0700 Subject: [PATCH 612/719] Fix test check for raised exception --- yapftests/yapf_test.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 4fdb89251..7ee8a0c65 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -282,14 +282,11 @@ def testFormatFileInPlace(self): print_diff=True) def testNoFile(self): - stream = StringIO() - handler = logging.StreamHandler(stream) - logger = logging.getLogger('mylogger') - logger.addHandler(handler) - self.assertRaises( - IOError, yapf_api.FormatFile, 'not_a_file.py', logger=logger.error) - self.assertEqual(stream.getvalue(), - "[Errno 2] No such file or directory: 'not_a_file.py'\n") + with self.assertRaises(IOError) as context: + yapf_api.FormatFile('not_a_file.py') + + self.assertEqual(str(context.exception), + "[Errno 2] No such file or directory: 'not_a_file.py'") def testCommentsUnformatted(self): code = textwrap.dedent("""\ From a1d888ccfe0edf4c19f534db1802002a1999172a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 4 May 2023 17:15:51 -0700 Subject: [PATCH 613/719] Move third party code to the top-level directory --- setup.py | 2 +- {yapf/third_party => third_party}/__init__.py | 0 {yapf/third_party => third_party}/yapf_diff/LICENSE | 0 {yapf/third_party => third_party}/yapf_diff/__init__.py | 0 {yapf/third_party => third_party}/yapf_diff/yapf_diff.py | 0 5 files changed, 1 insertion(+), 1 deletion(-) rename {yapf/third_party => third_party}/__init__.py (100%) rename {yapf/third_party => third_party}/yapf_diff/LICENSE (100%) rename {yapf/third_party => third_party}/yapf_diff/__init__.py (100%) rename {yapf/third_party => third_party}/yapf_diff/yapf_diff.py (100%) diff --git a/setup.py b/setup.py index 20cb117b0..0412f677a 100644 --- a/setup.py +++ b/setup.py @@ -74,7 +74,7 @@ def run(self): entry_points={ 'console_scripts': [ 'yapf = yapf:run_main', - 'yapf-diff = yapf.third_party.yapf_diff.yapf_diff:main', + 'yapf-diff = third_party.yapf_diff.yapf_diff:main', ], }, cmdclass={ diff --git a/yapf/third_party/__init__.py b/third_party/__init__.py similarity index 100% rename from yapf/third_party/__init__.py rename to third_party/__init__.py diff --git a/yapf/third_party/yapf_diff/LICENSE b/third_party/yapf_diff/LICENSE similarity index 100% rename from yapf/third_party/yapf_diff/LICENSE rename to third_party/yapf_diff/LICENSE diff --git a/yapf/third_party/yapf_diff/__init__.py b/third_party/yapf_diff/__init__.py similarity index 100% rename from yapf/third_party/yapf_diff/__init__.py rename to third_party/yapf_diff/__init__.py diff --git a/yapf/third_party/yapf_diff/yapf_diff.py b/third_party/yapf_diff/yapf_diff.py similarity index 100% rename from yapf/third_party/yapf_diff/yapf_diff.py rename to third_party/yapf_diff/yapf_diff.py From 4abb0cb57f27223b5cdb110c80f5cfc13d640900 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 4 May 2023 17:20:55 -0700 Subject: [PATCH 614/719] Remove tabs --- yapftests/yapf_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 7ee8a0c65..33cc143eb 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -286,7 +286,7 @@ def testNoFile(self): yapf_api.FormatFile('not_a_file.py') self.assertEqual(str(context.exception), - "[Errno 2] No such file or directory: 'not_a_file.py'") + "[Errno 2] No such file or directory: 'not_a_file.py'") def testCommentsUnformatted(self): code = textwrap.dedent("""\ From 6982ebb6689cd6dd358f72f802514ad74ea49cb2 Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Fri, 19 May 2023 08:08:07 -0400 Subject: [PATCH 615/719] Add isort pre-commit and lint with isort and yapf in CI (#1093) * add empty .isort.cfg * force_single_line * add pre-commit-config, apply sort * remove unused pre-commit-hooks * Lint with isort * Lint with Yapf. * move yapftests to its own section * verbose output --- .github/workflows/ci.yml | 8 ++++++++ .isort.cfg | 5 +++++ .pre-commit-config.yaml | 8 +++++--- setup.py | 4 +++- third_party/yapf_diff/yapf_diff.py | 1 - yapf/__init__.py | 2 +- yapf/pytree/blank_line_calculator.py | 3 +-- yapf/pytree/pytree_utils.py | 1 - yapf/pytree/pytree_visitor.py | 1 - yapf/pytree/split_penalty.py | 1 - yapf/yapflib/format_token.py | 1 - yapf/yapflib/logical_line.py | 4 ++-- yapf/yapflib/reformatter.py | 1 - yapf/yapflib/yapf_api.py | 5 ++--- yapftests/comment_splicer_test.py | 2 +- yapftests/format_decision_state_test.py | 1 - yapftests/format_token_test.py | 1 - yapftests/logical_line_test.py | 1 - yapftests/main_test.py | 5 +++-- yapftests/pytree_utils_test.py | 1 - yapftests/split_penalty_test.py | 1 - yapftests/yapf_test.py | 6 +++--- 22 files changed, 34 insertions(+), 29 deletions(-) create mode 100644 .isort.cfg diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6cc5028c7..23e9f8e94 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,3 +32,11 @@ jobs: pip install pytest pip install pytest-cov pytest + - name: Lint with isort + run: | + pip install isort + isort . --check --diff + - name: Lint with yapf + run: | + pip install . + yapf . -vv --diff --recursive diff --git a/.isort.cfg b/.isort.cfg new file mode 100644 index 000000000..69720b92c --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,5 @@ +[settings] +force_single_line=true +known_yapftests=yapftests + +sections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER,YAPFTESTS diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3bd65c26f..049a1a2f5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,6 +2,11 @@ # to enable run `pip install pre-commit && pre-commit install` repos: + - repo: https://github.com/pycqa/isort + rev: 5.11.5 + hooks: + - id: isort + name: isort (python) - repo: local hooks: - id: yapf @@ -15,15 +20,12 @@ repos: hooks: - id: trailing-whitespace - id: check-docstring-first - - id: check-json - id: check-added-large-files - id: check-yaml - id: debug-statements - - id: requirements-txt-fixer - id: check-merge-conflict - id: double-quote-string-fixer - id: end-of-file-fixer - - id: sort-simple-yaml - repo: meta hooks: - id: check-hooks-apply diff --git a/setup.py b/setup.py index 0412f677a..106d2b10f 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,9 @@ import sys import unittest -from setuptools import find_packages, setup, Command +from setuptools import Command +from setuptools import find_packages +from setuptools import setup import yapf diff --git a/third_party/yapf_diff/yapf_diff.py b/third_party/yapf_diff/yapf_diff.py index adc6fe452..a22abd953 100644 --- a/third_party/yapf_diff/yapf_diff.py +++ b/third_party/yapf_diff/yapf_diff.py @@ -30,7 +30,6 @@ import re import subprocess import sys - from io import StringIO diff --git a/yapf/__init__.py b/yapf/__init__.py index 39b15c9d5..aa5c37b2a 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -200,8 +200,8 @@ def FormatFiles(filenames, """ changed = False if parallel: - import multiprocessing # pylint: disable=g-import-not-at-top import concurrent.futures # pylint: disable=g-import-not-at-top + import multiprocessing # pylint: disable=g-import-not-at-top workers = min(multiprocessing.cpu_count(), len(filenames)) with concurrent.futures.ProcessPoolExecutor(workers) as executor: future_formats = [ diff --git a/yapf/pytree/blank_line_calculator.py b/yapf/pytree/blank_line_calculator.py index d47f2b560..7bccb0978 100644 --- a/yapf/pytree/blank_line_calculator.py +++ b/yapf/pytree/blank_line_calculator.py @@ -174,5 +174,4 @@ def _StartsInZerothColumn(node): def _AsyncFunction(node): - return (node.prev_sibling and - node.prev_sibling.type == grammar_token.ASYNC) + return (node.prev_sibling and node.prev_sibling.type == grammar_token.ASYNC) diff --git a/yapf/pytree/pytree_utils.py b/yapf/pytree/pytree_utils.py index 43ef8763d..8b3c4065c 100644 --- a/yapf/pytree/pytree_utils.py +++ b/yapf/pytree/pytree_utils.py @@ -26,7 +26,6 @@ import ast import os - from lib2to3 import pygram from lib2to3 import pytree from lib2to3.pgen2 import driver diff --git a/yapf/pytree/pytree_visitor.py b/yapf/pytree/pytree_visitor.py index 314431e84..4f6c605ee 100644 --- a/yapf/pytree/pytree_visitor.py +++ b/yapf/pytree/pytree_visitor.py @@ -25,7 +25,6 @@ """ import sys - from lib2to3 import pytree from yapf.pytree import pytree_utils diff --git a/yapf/pytree/split_penalty.py b/yapf/pytree/split_penalty.py index 81163e4d3..ccb3880d4 100644 --- a/yapf/pytree/split_penalty.py +++ b/yapf/pytree/split_penalty.py @@ -14,7 +14,6 @@ """Computation of split penalties before/between tokens.""" import re - from lib2to3 import pytree from lib2to3.pgen2 import token as grammar_token diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 41afd45cb..c572391e3 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -15,7 +15,6 @@ import keyword import re - from functools import lru_cache from lib2to3.pgen2 import token diff --git a/yapf/yapflib/logical_line.py b/yapf/yapflib/logical_line.py index 1528fc450..780db8a2a 100644 --- a/yapf/yapflib/logical_line.py +++ b/yapf/yapflib/logical_line.py @@ -19,14 +19,14 @@ perform the wrapping required to comply with the style guide. """ +from lib2to3.fixer_util import syms as python_symbols + from yapf.pytree import pytree_utils from yapf.pytree import split_penalty from yapf.yapflib import format_token from yapf.yapflib import style from yapf.yapflib import subtypes -from lib2to3.fixer_util import syms as python_symbols - class LogicalLine(object): """Represents a single logical line in the output. diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index f8c4bc407..b7c883e5f 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -22,7 +22,6 @@ import collections import heapq import re - from lib2to3 import pytree from lib2to3.pgen2 import token diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 19e86f028..be5467a38 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -38,12 +38,11 @@ import sys from yapf.pyparser import pyparser - -from yapf.pytree import pytree_unwrapper -from yapf.pytree import pytree_utils from yapf.pytree import blank_line_calculator from yapf.pytree import comment_splicer from yapf.pytree import continuation_splicer +from yapf.pytree import pytree_unwrapper +from yapf.pytree import pytree_utils from yapf.pytree import split_penalty from yapf.pytree import subtype_assigner from yapf.yapflib import errors diff --git a/yapftests/comment_splicer_test.py b/yapftests/comment_splicer_test.py index 36c25b2d1..64cb7083e 100644 --- a/yapftests/comment_splicer_test.py +++ b/yapftests/comment_splicer_test.py @@ -16,8 +16,8 @@ import textwrap import unittest -from yapf.pytree import pytree_utils from yapf.pytree import comment_splicer +from yapf.pytree import pytree_utils class CommentSplicerTest(unittest.TestCase): diff --git a/yapftests/format_decision_state_test.py b/yapftests/format_decision_state_test.py index 63961f332..3bff578da 100644 --- a/yapftests/format_decision_state_test.py +++ b/yapftests/format_decision_state_test.py @@ -17,7 +17,6 @@ import unittest from yapf.pytree import pytree_utils - from yapf.yapflib import format_decision_state from yapf.yapflib import logical_line from yapf.yapflib import style diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index 18ebe48d5..5703e5a8b 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -14,7 +14,6 @@ """Tests for yapf.format_token.""" import unittest - from lib2to3 import pytree from lib2to3.pgen2 import token diff --git a/yapftests/logical_line_test.py b/yapftests/logical_line_test.py index d18262a7c..9188b32fc 100644 --- a/yapftests/logical_line_test.py +++ b/yapftests/logical_line_test.py @@ -15,7 +15,6 @@ import textwrap import unittest - from lib2to3 import pytree from lib2to3.pgen2 import token diff --git a/yapftests/main_test.py b/yapftests/main_test.py index 7241a023f..b5d9b926e 100644 --- a/yapftests/main_test.py +++ b/yapftests/main_test.py @@ -14,10 +14,11 @@ # limitations under the License. """Tests for yapf.__init__.main.""" -from contextlib import contextmanager -from io import StringIO import sys import unittest +from contextlib import contextmanager +from io import StringIO + import yapf from yapftests import yapf_test_helper diff --git a/yapftests/pytree_utils_test.py b/yapftests/pytree_utils_test.py index c55f668b4..b228fcb46 100644 --- a/yapftests/pytree_utils_test.py +++ b/yapftests/pytree_utils_test.py @@ -14,7 +14,6 @@ """Tests for yapf.pytree_utils.""" import unittest - from lib2to3 import pygram from lib2to3 import pytree from lib2to3.pgen2 import token diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index f7474a398..c08cf5a28 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -16,7 +16,6 @@ import sys import textwrap import unittest - from lib2to3 import pytree from yapf.pytree import pytree_utils diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 33cc143eb..09659e735 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -23,7 +23,6 @@ import tempfile import textwrap import unittest - from io import StringIO from lib2to3.pgen2 import tokenize @@ -285,8 +284,9 @@ def testNoFile(self): with self.assertRaises(IOError) as context: yapf_api.FormatFile('not_a_file.py') - self.assertEqual(str(context.exception), - "[Errno 2] No such file or directory: 'not_a_file.py'") + self.assertEqual( + str(context.exception), + "[Errno 2] No such file or directory: 'not_a_file.py'") def testCommentsUnformatted(self): code = textwrap.dedent("""\ From 318391af2c18c1a27c7e40cadd50442dca53b886 Mon Sep 17 00:00:00 2001 From: Eugene Toder Date: Tue, 23 May 2023 15:19:49 -0400 Subject: [PATCH 616/719] Add --print-modified to print modified files (#1054) Prints modified files when in place mode is used. This helps debugging formatting issues and makes developers more aware of the changes made by yapf. --- CHANGELOG | 2 ++ README.rst | 1 + yapf/__init__.py | 24 ++++++++++++++++++------ yapftests/yapf_test.py | 10 ++++++++++ 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a76e19aec..ec69b5ce6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,8 @@ ## [0.40.0] UNRELEASED ### Added - Support for Python 3.11 +- Add the `--print-modified` flag to print out file names of modified files when + running in in-place mode. ### Removed - Support for Python <3.7 diff --git a/README.rst b/README.rst index c4c56fbae..8b6e78104 100644 --- a/README.rst +++ b/README.rst @@ -116,6 +116,7 @@ Options:: --no-local-style don't search for local style definition -p, --parallel run YAPF in parallel when formatting multiple files. Requires concurrent.futures in Python 2.X + -m, --print-modified print out file names of modified files -vv, --verbose print out file names while processing diff --git a/yapf/__init__.py b/yapf/__init__.py index aa5c37b2a..ce183e9d0 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -145,7 +145,8 @@ def main(argv): verify=args.verify, parallel=args.parallel, quiet=args.quiet, - verbose=args.verbose) + verbose=args.verbose, + print_modified=args.print_modified) return 1 if changed and (args.diff or args.quiet) else 0 @@ -175,7 +176,8 @@ def FormatFiles(filenames, verify=False, parallel=False, quiet=False, - verbose=False): + verbose=False, + print_modified=False): """Format a list of files. Arguments: @@ -194,6 +196,7 @@ def FormatFiles(filenames, parallel: (bool) True if should format multiple files in parallel. quiet: (bool) True if should output nothing. verbose: (bool) True if should print out filenames while processing. + print_modified: (bool) True if should print out filenames of modified files. Returns: True if the source code changed in any of the files being formatted. @@ -207,14 +210,15 @@ def FormatFiles(filenames, future_formats = [ executor.submit(_FormatFile, filename, lines, style_config, no_local_style, in_place, print_diff, verify, quiet, - verbose) for filename in filenames + verbose, print_modified) for filename in filenames ] for future in concurrent.futures.as_completed(future_formats): changed |= future.result() else: for filename in filenames: changed |= _FormatFile(filename, lines, style_config, no_local_style, - in_place, print_diff, verify, quiet, verbose) + in_place, print_diff, verify, quiet, verbose, + print_modified) return changed @@ -226,10 +230,11 @@ def _FormatFile(filename, print_diff=False, verify=False, quiet=False, - verbose=False): + verbose=False, + print_modified=False): """Format an individual file.""" if verbose and not quiet: - print('Reformatting %s' % filename) + print(f'Reformatting {filename}') if style_config is None and not no_local_style: style_config = file_resources.GetDefaultStyleForDir( @@ -252,6 +257,8 @@ def _FormatFile(filename, if not in_place and not quiet and reformatted_code: file_resources.WriteReformattedCode(filename, reformatted_code, encoding, in_place) + if print_modified and has_change and in_place and not quiet: + print(f'Formatted {filename}') return has_change @@ -358,6 +365,11 @@ def _BuildParser(): action='store_true', help=('run YAPF in parallel when formatting multiple files. Requires ' 'concurrent.futures in Python 2.X')) + parser.add_argument( + '-m', + '--print-modified', + action='store_true', + help='print out file names of modified files') parser.add_argument( '-vv', '--verbose', diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 09659e735..7c241bdda 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -505,6 +505,16 @@ def testInPlaceReformattingEmpty(self): reformatted_code = fd.read() self.assertEqual(reformatted_code, expected_formatted_code) + def testPrintModified(self): + for unformatted_code, has_change in [('1==2', True), ('1 == 2', False)]: + with utils.TempFileContents( + self.test_tmpdir, unformatted_code, suffix='.py') as filepath: + output = subprocess.check_output( + YAPF_BINARY + ['--in-place', '--print-modified', filepath], + text=True) + check = self.assertIn if has_change else self.assertNotIn + check(f'Formatted {filepath}', output) + def testReadFromStdin(self): unformatted_code = textwrap.dedent("""\ def foo(): From f7d42c4cb7d3d6c8e265f5c5eaa9edc7153fbbbe Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Thu, 25 May 2023 16:03:32 -0400 Subject: [PATCH 617/719] ignore VSCode settings, worktree dir (#1095) --- .gitignore | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitignore b/.gitignore index 51c8f0291..e2ff4c7fb 100644 --- a/.gitignore +++ b/.gitignore @@ -33,5 +33,12 @@ /.tox /yapf.egg-info +# IDEs /.idea +/.vscode/settings.json + +# Virtual Environment /.venv*/ + +# Worktrees +/.wt From 46d9c89342357c0d9799e89ff9c4790c07a74bae Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Sat, 27 May 2023 14:38:47 +0200 Subject: [PATCH 618/719] Make CI enforce pre-commit clean code (#1096) * pre-commit: Enforce pre-commit clean code via CI * ci.yml: Resolve duplication of isort and yapf By now pre-commit is already running these. * ci.yml: Move flake8 to pre-commit * README.rst: Add CI status badge for workflow "Run pre-commit" * README.rst: Fix link for CI workflow "YAPF" (ci.yml) --- .github/workflows/ci.yml | 12 ----------- .github/workflows/pre-commit.yml | 37 ++++++++++++++++++++++++++++++++ .pre-commit-config.yaml | 4 ++++ README.rst | 6 +++++- 4 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/pre-commit.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 23e9f8e94..966f896d9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,20 +23,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - - name: Lint with flake8 - run: | - python -m pip install flake8 - flake8 . --statistics - name: Test with pytest run: | pip install pytest pip install pytest-cov pytest - - name: Lint with isort - run: | - pip install isort - isort . --check --diff - - name: Lint with yapf - run: | - pip install . - yapf . -vv --diff --recursive diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 000000000..1d11c2627 --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,37 @@ +# Copyright (c) 2023 Sebastian Pipping +# Licensed under the Apache License Version 2.0 + +name: Run pre-commit + +# Drop permissions to minimum for security +permissions: + contents: read + +on: + pull_request: + push: + schedule: + - cron: '0 2 * * 5' # Every Friday at 2am + workflow_dispatch: + +jobs: + pre_commit_run: + name: Run pre-commit + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + + - uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # v4.5.0 + with: + python-version: 3.11 + + - name: Install yapf (to be available to pre-commit) + run: |- + pip install \ + --disable-pip-version-check \ + --no-warn-script-location \ + --user \ + . + echo "PATH=${HOME}/.local/bin:${PATH}" >> "${GITHUB_ENV}" + + - uses: pre-commit/action@646c83fcd040023954eafda54b4db0192ce70507 # v3.0.0 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 049a1a2f5..b4adc7cb4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,6 +7,10 @@ repos: hooks: - id: isort name: isort (python) + - repo: https://github.com/pycqa/flake8 + rev: 6.0.0 + hooks: + - id: flake8 - repo: local hooks: - id: yapf diff --git a/README.rst b/README.rst index 8b6e78104..25e8c10d8 100644 --- a/README.rst +++ b/README.rst @@ -7,9 +7,13 @@ YAPF :alt: PyPI version .. image:: https://github.com/google/yapf/actions/workflows/ci.yml/badge.svg - :target: https://github.com/google/yapf/actions + :target: https://github.com/google/yapf/actions/workflows/ci.yml :alt: Build status +.. image:: https://github.com/google/yapf/actions/workflows/pre-commit.yml/badge.svg + :target: https://github.com/google/yapf/actions/workflows/pre-commit.yml + :alt: Run pre-commit + .. image:: https://coveralls.io/repos/google/yapf/badge.svg?branch=main :target: https://coveralls.io/r/google/yapf?branch=main :alt: Coverage status From e16ad587f90242dff4d2fce07a60ef6838186feb Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Sat, 27 May 2023 08:39:41 -0400 Subject: [PATCH 619/719] Build wheel against py3 only (#1098) * Build wheel against py3 only * put everything in setup.py --- setup.cfg | 2 -- setup.py | 6 ++++-- 2 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 setup.cfg diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 2a9acf13d..000000000 --- a/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[bdist_wheel] -universal = 1 diff --git a/setup.py b/setup.py index 106d2b10f..025ecda35 100644 --- a/setup.py +++ b/setup.py @@ -52,6 +52,9 @@ def run(self): author='Google Inc.', maintainer='Bill Wendling', maintainer_email='morbo@google.com', + options={'bdist_wheel': { + 'python_tag': 'py3' + }}, packages=find_packages('.'), project_urls={ 'Source': 'https://github.com/google/yapf', @@ -63,13 +66,12 @@ def run(self): 'License :: OSI Approved :: Apache Software License', 'Operating System :: OS Independent', 'Programming Language :: Python', - 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3 :: Only', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', - 'Programming Language :: Python :: 3 :: Only', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Quality Assurance', ], From cf7b6906f8b95749cf1ef20e9eb6281cd2210858 Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Wed, 7 Jun 2023 14:41:26 -0400 Subject: [PATCH 620/719] Flake8 fails unnecessarily if run before yapf (#1099) * run yapf before flake8 * since yapf runs before flake8 pre-installing is not required * remove verbosity * Revert "since yapf runs before flake8 pre-installing is not required", local repo does not perform an install This reverts commit f85b8675134f31a359b7ceb7ebe2d2a24445dc90. --- .pre-commit-config.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b4adc7cb4..3e78dd66e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,18 +7,18 @@ repos: hooks: - id: isort name: isort (python) - - repo: https://github.com/pycqa/flake8 - rev: 6.0.0 - hooks: - - id: flake8 - repo: local hooks: - id: yapf name: yapf language: python entry: yapf - args: [-i, -vv] + args: [-i] types: [python] + - repo: https://github.com/pycqa/flake8 + rev: 6.0.0 + hooks: + - id: flake8 - repo: https://github.com/pre-commit/pre-commit-hooks rev: v3.2.0 hooks: From 1631220bc38c660b762bbce5036ac0180eb14c17 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Jun 2023 20:42:19 +0200 Subject: [PATCH 621/719] Actions(deps): Bump actions/setup-python from 4.5.0 to 4.6.1 (#1100) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4.5.0 to 4.6.1. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v4.5.0...bd6b4b6205c4dbad673328db7b31b7fab9e241c0) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 966f896d9..6d5fdba30 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@57ded4d7d5e986d7296eab16560982c6dd7c923b # v4.6.0 + uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.0 with: python-version: ${{ matrix.python-version }} - name: Install dependencies diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 1d11c2627..10a7ec31d 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 - - uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # v4.5.0 + - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 with: python-version: 3.11 From b6771979179a68f7c1e5eef7877d02a17570646d Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Fri, 9 Jun 2023 01:39:47 -0400 Subject: [PATCH 622/719] ylib2to3 -- Fork lib2to3 with some blib2to3 backports; add structured pattern matching (match) and parenthesized-context-managers statement support (#1067) Add ylib2to3, a copy of blib2to3. - Yapf modifications to support match statement - Disable double indent when splitting parameters after keyword - Fix comment indent inside match - Add vscode settings to gitignore - Add testMatchStatementRemoveSpacesInCaseBracket - Add credit to black - Use post develop and install commands in setup.py - Use metadata for yapf.__version__ - Install YAPF as it's own step in GitHub CI - Remove PKG_INFO.ini, using importlib_metadata - Move yapf.third_party to third_party, install at yapf_third_party though This works, but you can't do a editable install with pip. You need to manually add a line to site-packages/easy-install.pth for the fully qualified path to /third_party --------- Co-authored-by: Charles --- .github/workflows/ci.yml | 22 +- .gitignore | 3 +- .isort.cfg | 1 + setup.py | 25 +- .../__init__.py | 0 .../yapf_third_party/_ylib2to3/Grammar.txt | 252 +++++ .../yapf_third_party/_ylib2to3/LICENSE | 254 ++++++ .../_ylib2to3/PatternGrammar.txt | 28 + .../yapf_third_party/_ylib2to3/README.rst | 9 + .../yapf_third_party/_ylib2to3/__init__.py | 1 + .../yapf_third_party/_ylib2to3/fixer_util.py | 491 ++++++++++ .../yapf_third_party/_ylib2to3/patcomp.py | 209 +++++ .../_ylib2to3/pgen2/__init__.py | 3 + .../yapf_third_party/_ylib2to3/pgen2/conv.py | 254 ++++++ .../_ylib2to3/pgen2/driver.py | 300 ++++++ .../_ylib2to3/pgen2/grammar.py | 188 ++++ .../_ylib2to3/pgen2/literals.py | 64 ++ .../yapf_third_party/_ylib2to3/pgen2/parse.py | 378 ++++++++ .../yapf_third_party/_ylib2to3/pgen2/pgen.py | 409 +++++++++ .../yapf_third_party/_ylib2to3/pgen2/token.py | 87 ++ .../_ylib2to3/pgen2/tokenize.py | 611 +++++++++++++ .../yapf_third_party/_ylib2to3/pygram.py | 40 + .../yapf_third_party/_ylib2to3/pytree.py | 861 ++++++++++++++++++ .../{ => yapf_third_party}/yapf_diff/LICENSE | 0 .../yapf_third_party/yapf_diff/__init__.py | 0 .../yapf_diff/yapf_diff.py | 0 yapf/__init__.py | 4 +- yapf/pytree/blank_line_calculator.py | 2 +- yapf/pytree/comment_splicer.py | 6 +- yapf/pytree/continuation_splicer.py | 2 +- yapf/pytree/pytree_unwrapper.py | 26 +- yapf/pytree/pytree_utils.py | 11 +- yapf/pytree/pytree_visitor.py | 3 +- yapf/pytree/split_penalty.py | 5 +- yapf/pytree/subtype_assigner.py | 6 +- yapf/yapflib/errors.py | 2 +- yapf/yapflib/file_resources.py | 1 - yapf/yapflib/format_decision_state.py | 6 +- yapf/yapflib/format_token.py | 10 +- yapf/yapflib/identify_container.py | 2 +- yapf/yapflib/logical_line.py | 2 +- yapf/yapflib/reformatter.py | 5 +- yapf/yapflib/yapf_api.py | 1 - yapftests/format_token_test.py | 5 +- yapftests/logical_line_test.py | 5 +- yapftests/pytree_utils_test.py | 7 +- yapftests/reformatter_basic_test.py | 37 + yapftests/split_penalty_test.py | 3 +- yapftests/style_test.py | 4 +- yapftests/yapf_test.py | 3 +- 50 files changed, 4590 insertions(+), 58 deletions(-) rename third_party/{yapf_diff => yapf_third_party}/__init__.py (100%) create mode 100644 third_party/yapf_third_party/_ylib2to3/Grammar.txt create mode 100644 third_party/yapf_third_party/_ylib2to3/LICENSE create mode 100644 third_party/yapf_third_party/_ylib2to3/PatternGrammar.txt create mode 100644 third_party/yapf_third_party/_ylib2to3/README.rst create mode 100644 third_party/yapf_third_party/_ylib2to3/__init__.py create mode 100644 third_party/yapf_third_party/_ylib2to3/fixer_util.py create mode 100644 third_party/yapf_third_party/_ylib2to3/patcomp.py create mode 100644 third_party/yapf_third_party/_ylib2to3/pgen2/__init__.py create mode 100644 third_party/yapf_third_party/_ylib2to3/pgen2/conv.py create mode 100644 third_party/yapf_third_party/_ylib2to3/pgen2/driver.py create mode 100644 third_party/yapf_third_party/_ylib2to3/pgen2/grammar.py create mode 100644 third_party/yapf_third_party/_ylib2to3/pgen2/literals.py create mode 100644 third_party/yapf_third_party/_ylib2to3/pgen2/parse.py create mode 100644 third_party/yapf_third_party/_ylib2to3/pgen2/pgen.py create mode 100644 third_party/yapf_third_party/_ylib2to3/pgen2/token.py create mode 100644 third_party/yapf_third_party/_ylib2to3/pgen2/tokenize.py create mode 100644 third_party/yapf_third_party/_ylib2to3/pygram.py create mode 100644 third_party/yapf_third_party/_ylib2to3/pytree.py rename third_party/{ => yapf_third_party}/yapf_diff/LICENSE (100%) create mode 100644 third_party/yapf_third_party/yapf_diff/__init__.py rename third_party/{ => yapf_third_party}/yapf_diff/yapf_diff.py (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6d5fdba30..c4102ff2c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,7 +1,7 @@ # This workflow will install Python dependencies, run tests and lint with a variety of Python versions # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions -name: YAPF +name: Test with pytest on: pull_request: @@ -20,11 +20,17 @@ jobs: uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.0 with: python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - - name: Test with pytest - run: | - pip install pytest - pip install pytest-cov + - name: Upgrade pip + run: >- + python -m pip install + --upgrade + --disable-pip-version-check + pip + - name: Perform package installs + run: >- + pip install + . pytest + pytest-cov + - name: Test with pytest + run: pytest diff --git a/.gitignore b/.gitignore index e2ff4c7fb..6a6928eae 100644 --- a/.gitignore +++ b/.gitignore @@ -13,8 +13,9 @@ *~ # Merge files created by git. *.orig -# Byte compiled python modules. +# Compiled python. *.pyc +*.pickle # vim swap files .*.sw? .sw? diff --git a/.isort.cfg b/.isort.cfg index 69720b92c..d9ce8b88c 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -1,5 +1,6 @@ [settings] force_single_line=true +known_third_party=yapf_third_party known_yapftests=yapftests sections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER,YAPFTESTS diff --git a/setup.py b/setup.py index 025ecda35..a294ccce3 100644 --- a/setup.py +++ b/setup.py @@ -21,8 +21,6 @@ from setuptools import find_packages from setuptools import setup -import yapf - class RunTests(Command): user_options = [] @@ -44,7 +42,7 @@ def run(self): with codecs.open('README.rst', 'r', 'utf-8') as fd: setup( name='yapf', - version=yapf.__version__, + version='0.33.0', description='A formatter for Python code.', url='https://github.com/google/yapf', long_description=fd.read(), @@ -55,7 +53,9 @@ def run(self): options={'bdist_wheel': { 'python_tag': 'py3' }}, - packages=find_packages('.'), + packages=find_packages(where='.', include=['yapf*', 'yapftests*']) + + find_packages(where='third_party'), + package_dir={'yapf_third_party': 'third_party/yapf_third_party'}, project_urls={ 'Source': 'https://github.com/google/yapf', }, @@ -78,12 +78,25 @@ def run(self): entry_points={ 'console_scripts': [ 'yapf = yapf:run_main', - 'yapf-diff = third_party.yapf_diff.yapf_diff:main', + 'yapf-diff = yapf_third_party.yapf_diff.yapf_diff:main', ], }, cmdclass={ 'test': RunTests, }, + package_data={ + 'yapf_third_party': [ + 'yapf_diff/LICENSE', + '_ylib2to3/Grammar.txt', + '_ylib2to3/PatternGrammar.txt', + '_ylib2to3/LICENSE', + ] + }, + include_package_data=True, python_requires='>=3.7', - install_requires=['tomli>=2.0.1'], + install_requires=[ + 'importlib-metadata>=6.6.0', + 'platformdirs>=3.5.1', + 'tomli>=2.0.1', + ], ) diff --git a/third_party/yapf_diff/__init__.py b/third_party/yapf_third_party/__init__.py similarity index 100% rename from third_party/yapf_diff/__init__.py rename to third_party/yapf_third_party/__init__.py diff --git a/third_party/yapf_third_party/_ylib2to3/Grammar.txt b/third_party/yapf_third_party/_ylib2to3/Grammar.txt new file mode 100644 index 000000000..bd8a452a3 --- /dev/null +++ b/third_party/yapf_third_party/_ylib2to3/Grammar.txt @@ -0,0 +1,252 @@ +# Grammar for 2to3. This grammar supports Python 2.x and 3.x. + +# NOTE WELL: You should also follow all the steps listed at +# https://devguide.python.org/grammar/ + +# Start symbols for the grammar: +# file_input is a module or sequence of commands read from an input file; +# single_input is a single interactive statement; +# eval_input is the input for the eval() and input() functions. +# NB: compound_stmt in single_input is followed by extra NEWLINE! +file_input: (NEWLINE | stmt)* ENDMARKER +single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE +eval_input: testlist NEWLINE* ENDMARKER + +decorator: '@' namedexpr_test NEWLINE +decorators: decorator+ +decorated: decorators (classdef | funcdef | async_funcdef) +async_funcdef: ASYNC funcdef +funcdef: 'def' NAME parameters ['->' test] ':' suite +parameters: '(' [typedargslist] ')' + +# The following definition for typedarglist is equivalent to this set of rules: +# +# arguments = argument (',' argument)* +# argument = tfpdef ['=' test] +# kwargs = '**' tname [','] +# args = '*' [tname_star] +# kwonly_kwargs = (',' argument)* [',' [kwargs]] +# args_kwonly_kwargs = args kwonly_kwargs | kwargs +# poskeyword_args_kwonly_kwargs = arguments [',' [args_kwonly_kwargs]] +# typedargslist_no_posonly = poskeyword_args_kwonly_kwargs | args_kwonly_kwargs +# typedarglist = arguments ',' '/' [',' [typedargslist_no_posonly]])|(typedargslist_no_posonly)" +# +# It needs to be fully expanded to allow our LL(1) parser to work on it. + +typedargslist: tfpdef ['=' test] (',' tfpdef ['=' test])* ',' '/' [ + ',' [((tfpdef ['=' test] ',')* ('*' [tname_star] (',' tname ['=' test])* + [',' ['**' tname [',']]] | '**' tname [',']) + | tfpdef ['=' test] (',' tfpdef ['=' test])* [','])] + ] | ((tfpdef ['=' test] ',')* ('*' [tname_star] (',' tname ['=' test])* + [',' ['**' tname [',']]] | '**' tname [',']) + | tfpdef ['=' test] (',' tfpdef ['=' test])* [',']) + +tname: NAME [':' test] +tname_star: NAME [':' (test|star_expr)] +tfpdef: tname | '(' tfplist ')' +tfplist: tfpdef (',' tfpdef)* [','] + +# The following definition for varargslist is equivalent to this set of rules: +# +# arguments = argument (',' argument )* +# argument = vfpdef ['=' test] +# kwargs = '**' vname [','] +# args = '*' [vname] +# kwonly_kwargs = (',' argument )* [',' [kwargs]] +# args_kwonly_kwargs = args kwonly_kwargs | kwargs +# poskeyword_args_kwonly_kwargs = arguments [',' [args_kwonly_kwargs]] +# vararglist_no_posonly = poskeyword_args_kwonly_kwargs | args_kwonly_kwargs +# varargslist = arguments ',' '/' [','[(vararglist_no_posonly)]] | (vararglist_no_posonly) +# +# It needs to be fully expanded to allow our LL(1) parser to work on it. + +varargslist: vfpdef ['=' test ](',' vfpdef ['=' test])* ',' '/' [',' [ + ((vfpdef ['=' test] ',')* ('*' [vname] (',' vname ['=' test])* + [',' ['**' vname [',']]] | '**' vname [',']) + | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) + ]] | ((vfpdef ['=' test] ',')* + ('*' [vname] (',' vname ['=' test])* [',' ['**' vname [',']]]| '**' vname [',']) + | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) + +vname: NAME +vfpdef: vname | '(' vfplist ')' +vfplist: vfpdef (',' vfpdef)* [','] + +stmt: simple_stmt | compound_stmt +simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE +small_stmt: (expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt | + import_stmt | global_stmt | exec_stmt | assert_stmt) +expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) | + ('=' (yield_expr|testlist_star_expr))*) +annassign: ':' test ['=' (yield_expr|testlist_star_expr)] +testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [','] +augassign: ('+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' | + '<<=' | '>>=' | '**=' | '//=') +# For normal and annotated assignments, additional restrictions enforced by the interpreter +print_stmt: 'print' ( [ test (',' test)* [','] ] | + '>>' test [ (',' test)+ [','] ] ) +del_stmt: 'del' exprlist +pass_stmt: 'pass' +flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt +break_stmt: 'break' +continue_stmt: 'continue' +return_stmt: 'return' [testlist_star_expr] +yield_stmt: yield_expr +raise_stmt: 'raise' [test ['from' test | ',' test [',' test]]] +import_stmt: import_name | import_from +import_name: 'import' dotted_as_names +import_from: ('from' ('.'* dotted_name | '.'+) + 'import' ('*' | '(' import_as_names ')' | import_as_names)) +import_as_name: NAME ['as' NAME] +dotted_as_name: dotted_name ['as' NAME] +import_as_names: import_as_name (',' import_as_name)* [','] +dotted_as_names: dotted_as_name (',' dotted_as_name)* +dotted_name: NAME ('.' NAME)* +global_stmt: ('global' | 'nonlocal') NAME (',' NAME)* +exec_stmt: 'exec' expr ['in' test [',' test]] +assert_stmt: 'assert' test [',' test] + +compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt | match_stmt +async_stmt: ASYNC (funcdef | with_stmt | for_stmt) +if_stmt: 'if' namedexpr_test ':' suite ('elif' namedexpr_test ':' suite)* ['else' ':' suite] +while_stmt: 'while' namedexpr_test ':' suite ['else' ':' suite] +for_stmt: 'for' exprlist 'in' testlist_star_expr ':' suite ['else' ':' suite] +try_stmt: ('try' ':' suite + ((except_clause ':' suite)+ + ['else' ':' suite] + ['finally' ':' suite] | + 'finally' ':' suite)) +with_stmt: 'with' asexpr_test (',' asexpr_test)* ':' suite + +# NB compile.c makes sure that the default except clause is last +except_clause: 'except' ['*'] [test [(',' | 'as') test]] +suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT + +# Backward compatibility cruft to support: +# [ x for x in lambda: True, lambda: False if x() ] +# even while also allowing: +# lambda x: 5 if x else 2 +# (But not a mix of the two) +testlist_safe: old_test [(',' old_test)+ [',']] +old_test: or_test | old_lambdef +old_lambdef: 'lambda' [varargslist] ':' old_test + +namedexpr_test: asexpr_test [':=' asexpr_test] + +# This is actually not a real rule, though since the parser is very +# limited in terms of the strategy about match/case rules, we are inserting +# a virtual case ( as ) as a valid expression. Unless a better +# approach is thought, the only side effect of this seem to be just allowing +# more stuff to be parser (which would fail on the ast). +asexpr_test: test ['as' test] + +test: or_test ['if' or_test 'else' test] | lambdef +or_test: and_test ('or' and_test)* +and_test: not_test ('and' not_test)* +not_test: 'not' not_test | comparison +comparison: expr (comp_op expr)* +comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not' +star_expr: '*' expr +expr: xor_expr ('|' xor_expr)* +xor_expr: and_expr ('^' and_expr)* +and_expr: shift_expr ('&' shift_expr)* +shift_expr: arith_expr (('<<'|'>>') arith_expr)* +arith_expr: term (('+'|'-') term)* +term: factor (('*'|'@'|'/'|'%'|'//') factor)* +factor: ('+'|'-'|'~') factor | power +power: [AWAIT] atom trailer* ['**' factor] +atom: ('(' [yield_expr|testlist_gexp] ')' | + '[' [listmaker] ']' | + '{' [dictsetmaker] '}' | + '`' testlist1 '`' | + NAME | NUMBER | STRING+ | '.' '.' '.') +listmaker: (namedexpr_test|star_expr) ( old_comp_for | (',' (namedexpr_test|star_expr))* [','] ) +testlist_gexp: (namedexpr_test|star_expr) ( old_comp_for | (',' (namedexpr_test|star_expr))* [','] ) +lambdef: 'lambda' [varargslist] ':' test +trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME +subscriptlist: (subscript|star_expr) (',' (subscript|star_expr))* [','] +subscript: test [':=' test] | [test] ':' [test] [sliceop] +sliceop: ':' [test] +exprlist: (expr|star_expr) (',' (expr|star_expr))* [','] +testlist: test (',' test)* [','] +dictsetmaker: ( ((test ':' asexpr_test | '**' expr) + (comp_for | (',' (test ':' asexpr_test | '**' expr))* [','])) | + ((test [':=' test] | star_expr) + (comp_for | (',' (test [':=' test] | star_expr))* [','])) ) + +classdef: 'class' NAME ['(' [arglist] ')'] ':' suite + +arglist: argument (',' argument)* [','] + +# "test '=' test" is really "keyword '=' test", but we have no such token. +# These need to be in a single rule to avoid grammar that is ambiguous +# to our LL(1) parser. Even though 'test' includes '*expr' in star_expr, +# we explicitly match '*' here, too, to give it proper precedence. +# Illegal combinations and orderings are blocked in ast.c: +# multiple (test comp_for) arguments are blocked; keyword unpackings +# that precede iterable unpackings are blocked; etc. +argument: ( test [comp_for] | + test ':=' test [comp_for] | + test 'as' test | + test '=' asexpr_test | + '**' test | + '*' test ) + +comp_iter: comp_for | comp_if +comp_for: [ASYNC] 'for' exprlist 'in' or_test [comp_iter] +comp_if: 'if' old_test [comp_iter] + +# As noted above, testlist_safe extends the syntax allowed in list +# comprehensions and generators. We can't use it indiscriminately in all +# derivations using a comp_for-like pattern because the testlist_safe derivation +# contains comma which clashes with trailing comma in arglist. +# +# This was an issue because the parser would not follow the correct derivation +# when parsing syntactically valid Python code. Since testlist_safe was created +# specifically to handle list comprehensions and generator expressions enclosed +# with parentheses, it's safe to only use it in those. That avoids the issue; we +# can parse code like set(x for x in [],). +# +# The syntax supported by this set of rules is not a valid Python 3 syntax, +# hence the prefix "old". +# +# See https://bugs.python.org/issue27494 +old_comp_iter: old_comp_for | old_comp_if +old_comp_for: [ASYNC] 'for' exprlist 'in' testlist_safe [old_comp_iter] +old_comp_if: 'if' old_test [old_comp_iter] + +testlist1: test (',' test)* + +# not used in grammar, but may appear in "node" passed from Parser to Compiler +encoding_decl: NAME + +yield_expr: 'yield' [yield_arg] +yield_arg: 'from' test | testlist_star_expr + + +# 3.10 match statement definition + +# PS: normally the grammar is much much more restricted, but +# at this moment for not trying to bother much with encoding the +# exact same DSL in a LL(1) parser, we will just accept an expression +# and let the ast.parse() step of the safe mode to reject invalid +# grammar. + +# The reason why it is more restricted is that, patterns are some +# sort of a DSL (more advanced than our LHS on assignments, but +# still in a very limited python subset). They are not really +# expressions, but who cares. If we can parse them, that is enough +# to reformat them. + +match_stmt: "match" subject_expr ':' NEWLINE INDENT case_block+ DEDENT + +# This is more permissive than the actual version. For example it +# accepts `match *something:`, even though single-item starred expressions +# are forbidden. +subject_expr: (namedexpr_test|star_expr) (',' (namedexpr_test|star_expr))* [','] + +# cases +case_block: "case" patterns [guard] ':' suite +guard: 'if' namedexpr_test +patterns: pattern (',' pattern)* [','] +pattern: (expr|star_expr) ['as' expr] diff --git a/third_party/yapf_third_party/_ylib2to3/LICENSE b/third_party/yapf_third_party/_ylib2to3/LICENSE new file mode 100644 index 000000000..ef8df0698 --- /dev/null +++ b/third_party/yapf_third_party/_ylib2to3/LICENSE @@ -0,0 +1,254 @@ +A. HISTORY OF THE SOFTWARE +========================== + +Python was created in the early 1990s by Guido van Rossum at Stichting +Mathematisch Centrum (CWI, see https://www.cwi.nl) in the Netherlands +as a successor of a language called ABC. Guido remains Python's +principal author, although it includes many contributions from others. + +In 1995, Guido continued his work on Python at the Corporation for +National Research Initiatives (CNRI, see https://www.cnri.reston.va.us) +in Reston, Virginia where he released several versions of the +software. + +In May 2000, Guido and the Python core development team moved to +BeOpen.com to form the BeOpen PythonLabs team. In October of the same +year, the PythonLabs team moved to Digital Creations, which became +Zope Corporation. In 2001, the Python Software Foundation (PSF, see +https://www.python.org/psf/) was formed, a non-profit organization +created specifically to own Python-related Intellectual Property. +Zope Corporation was a sponsoring member of the PSF. + +All Python releases are Open Source (see https://opensource.org for +the Open Source Definition). Historically, most, but not all, Python +releases have also been GPL-compatible; the table below summarizes +the various releases. + + Release Derived Year Owner GPL- + from compatible? (1) + + 0.9.0 thru 1.2 1991-1995 CWI yes + 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes + 1.6 1.5.2 2000 CNRI no + 2.0 1.6 2000 BeOpen.com no + 1.6.1 1.6 2001 CNRI yes (2) + 2.1 2.0+1.6.1 2001 PSF no + 2.0.1 2.0+1.6.1 2001 PSF yes + 2.1.1 2.1+2.0.1 2001 PSF yes + 2.1.2 2.1.1 2002 PSF yes + 2.1.3 2.1.2 2002 PSF yes + 2.2 and above 2.1.1 2001-now PSF yes + +Footnotes: + +(1) GPL-compatible doesn't mean that we're distributing Python under + the GPL. All Python licenses, unlike the GPL, let you distribute + a modified version without making your changes open source. The + GPL-compatible licenses make it possible to combine Python with + other software that is released under the GPL; the others don't. + +(2) According to Richard Stallman, 1.6.1 is not GPL-compatible, + because its license has a choice of law clause. According to + CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 + is "not incompatible" with the GPL. + +Thanks to the many outside volunteers who have worked under Guido's +direction to make these releases possible. + + +B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON +=============================================================== + +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby +grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +analyze, test, perform and/or display publicly, prepare derivative works, +distribute, and otherwise use Python alone or in any derivative version, +provided, however, that PSF's License Agreement and PSF's notice of copyright, +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 Python Software Foundation; All +Rights Reserved" are retained in Python alone or in any derivative version +prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 +------------------------------------------- + +BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 + +1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an +office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the +Individual or Organization ("Licensee") accessing and otherwise using +this software in source or binary form and its associated +documentation ("the Software"). + +2. Subject to the terms and conditions of this BeOpen Python License +Agreement, BeOpen hereby grants Licensee a non-exclusive, +royalty-free, world-wide license to reproduce, analyze, test, perform +and/or display publicly, prepare derivative works, distribute, and +otherwise use the Software alone or in any derivative version, +provided, however, that the BeOpen Python License is retained in the +Software, alone or in any derivative version prepared by Licensee. + +3. BeOpen is making the Software available to Licensee on an "AS IS" +basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE +SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS +AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY +DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +5. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +6. This License Agreement shall be governed by and interpreted in all +respects by the law of the State of California, excluding conflict of +law provisions. Nothing in this License Agreement shall be deemed to +create any relationship of agency, partnership, or joint venture +between BeOpen and Licensee. This License Agreement does not grant +permission to use BeOpen trademarks or trade names in a trademark +sense to endorse or promote products or services of Licensee, or any +third party. As an exception, the "BeOpen Python" logos available at +http://www.pythonlabs.com/logos.html may be used according to the +permissions granted on that web page. + +7. By copying, installing or otherwise using the software, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 +--------------------------------------- + +1. This LICENSE AGREEMENT is between the Corporation for National +Research Initiatives, having an office at 1895 Preston White Drive, +Reston, VA 20191 ("CNRI"), and the Individual or Organization +("Licensee") accessing and otherwise using Python 1.6.1 software in +source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, CNRI +hereby grants Licensee a nonexclusive, royalty-free, world-wide +license to reproduce, analyze, test, perform and/or display publicly, +prepare derivative works, distribute, and otherwise use Python 1.6.1 +alone or in any derivative version, provided, however, that CNRI's +License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) +1995-2001 Corporation for National Research Initiatives; All Rights +Reserved" are retained in Python 1.6.1 alone or in any derivative +version prepared by Licensee. Alternately, in lieu of CNRI's License +Agreement, Licensee may substitute the following text (omitting the +quotes): "Python 1.6.1 is made available subject to the terms and +conditions in CNRI's License Agreement. This Agreement together with +Python 1.6.1 may be located on the Internet using the following +unique, persistent identifier (known as a handle): 1895.22/1013. This +Agreement may also be obtained from a proxy server on the Internet +using the following URL: http://hdl.handle.net/1895.22/1013". + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python 1.6.1 or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python 1.6.1. + +4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" +basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. This License Agreement shall be governed by the federal +intellectual property law of the United States, including without +limitation the federal copyright law, and, to the extent such +U.S. federal law does not apply, by the law of the Commonwealth of +Virginia, excluding Virginia's conflict of law provisions. +Notwithstanding the foregoing, with regard to derivative works based +on Python 1.6.1 that incorporate non-separable material that was +previously distributed under the GNU General Public License (GPL), the +law of the Commonwealth of Virginia shall govern this License +Agreement only as to issues arising under or with respect to +Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this +License Agreement shall be deemed to create any relationship of +agency, partnership, or joint venture between CNRI and Licensee. This +License Agreement does not grant permission to use CNRI trademarks or +trade name in a trademark sense to endorse or promote products or +services of Licensee, or any third party. + +8. By clicking on the "ACCEPT" button where indicated, or by copying, +installing or otherwise using Python 1.6.1, Licensee agrees to be +bound by the terms and conditions of this License Agreement. + + ACCEPT + + +CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 +-------------------------------------------------- + +Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, +The Netherlands. All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/third_party/yapf_third_party/_ylib2to3/PatternGrammar.txt b/third_party/yapf_third_party/_ylib2to3/PatternGrammar.txt new file mode 100644 index 000000000..36bf81482 --- /dev/null +++ b/third_party/yapf_third_party/_ylib2to3/PatternGrammar.txt @@ -0,0 +1,28 @@ +# Copyright 2006 Google, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. + +# A grammar to describe tree matching patterns. +# Not shown here: +# - 'TOKEN' stands for any token (leaf node) +# - 'any' stands for any node (leaf or interior) +# With 'any' we can still specify the sub-structure. + +# The start symbol is 'Matcher'. + +Matcher: Alternatives ENDMARKER + +Alternatives: Alternative ('|' Alternative)* + +Alternative: (Unit | NegatedUnit)+ + +Unit: [NAME '='] ( STRING [Repeater] + | NAME [Details] [Repeater] + | '(' Alternatives ')' [Repeater] + | '[' Alternatives ']' + ) + +NegatedUnit: 'not' (STRING | NAME [Details] | '(' Alternatives ')') + +Repeater: '*' | '+' | '{' NUMBER [',' NUMBER] '}' + +Details: '<' Alternatives '>' diff --git a/third_party/yapf_third_party/_ylib2to3/README.rst b/third_party/yapf_third_party/_ylib2to3/README.rst new file mode 100644 index 000000000..21d69b89a --- /dev/null +++ b/third_party/yapf_third_party/_ylib2to3/README.rst @@ -0,0 +1,9 @@ +A fork of python's lib2to3 with select features backported from black's blib2to3. + +Reasons for forking: + +- black's fork of lib2to3 already considers newer features like Structured Pattern matching +- lib2to3 itself is deprecated and no longer getting support + +Maintenance moving forward: +- Most changes moving forward should only have to be done to the grammar files in this project. diff --git a/third_party/yapf_third_party/_ylib2to3/__init__.py b/third_party/yapf_third_party/_ylib2to3/__init__.py new file mode 100644 index 000000000..1de94366c --- /dev/null +++ b/third_party/yapf_third_party/_ylib2to3/__init__.py @@ -0,0 +1 @@ +"""fork of python's lib2to3 with some backports from black's blib2to3""" diff --git a/third_party/yapf_third_party/_ylib2to3/fixer_util.py b/third_party/yapf_third_party/_ylib2to3/fixer_util.py new file mode 100644 index 000000000..c8ff3ac9b --- /dev/null +++ b/third_party/yapf_third_party/_ylib2to3/fixer_util.py @@ -0,0 +1,491 @@ +"""Utility functions, node construction macros, etc.""" +# Author: Collin Winter + +from . import patcomp +# Local imports +from .pgen2 import token +from .pygram import python_symbols as syms +from .pytree import Leaf +from .pytree import Node + +########################################################### +# Common node-construction "macros" +########################################################### + + +def KeywordArg(keyword, value): + return Node(syms.argument, [keyword, Leaf(token.EQUAL, '='), value]) + + +def LParen(): + return Leaf(token.LPAR, '(') + + +def RParen(): + return Leaf(token.RPAR, ')') + + +def Assign(target, source): + """Build an assignment statement""" + if not isinstance(target, list): + target = [target] + if not isinstance(source, list): + source.prefix = ' ' + source = [source] + + return Node(syms.atom, target + [Leaf(token.EQUAL, '=', prefix=' ')] + source) + + +def Name(name, prefix=None): + """Return a NAME leaf""" + return Leaf(token.NAME, name, prefix=prefix) + + +def Attr(obj, attr): + """A node tuple for obj.attr""" + return [obj, Node(syms.trailer, [Dot(), attr])] + + +def Comma(): + """A comma leaf""" + return Leaf(token.COMMA, ',') + + +def Dot(): + """A period (.) leaf""" + return Leaf(token.DOT, '.') + + +def ArgList(args, lparen=LParen(), rparen=RParen()): + """A parenthesised argument list, used by Call()""" + node = Node(syms.trailer, [lparen.clone(), rparen.clone()]) + if args: + node.insert_child(1, Node(syms.arglist, args)) + return node + + +def Call(func_name, args=None, prefix=None): + """A function call""" + node = Node(syms.power, [func_name, ArgList(args)]) + if prefix is not None: + node.prefix = prefix + return node + + +def Newline(): + """A newline literal""" + return Leaf(token.NEWLINE, '\n') + + +def BlankLine(): + """A blank line""" + return Leaf(token.NEWLINE, '') + + +def Number(n, prefix=None): + return Leaf(token.NUMBER, n, prefix=prefix) + + +def Subscript(index_node): + """A numeric or string subscript""" + return Node(syms.trailer, + [Leaf(token.LBRACE, '['), index_node, + Leaf(token.RBRACE, ']')]) + + +def String(string, prefix=None): + """A string leaf""" + return Leaf(token.STRING, string, prefix=prefix) + + +def ListComp(xp, fp, it, test=None): + """A list comprehension of the form [xp for fp in it if test]. + + If test is None, the "if test" part is omitted. + """ + xp.prefix = '' + fp.prefix = ' ' + it.prefix = ' ' + for_leaf = Leaf(token.NAME, 'for') + for_leaf.prefix = ' ' + in_leaf = Leaf(token.NAME, 'in') + in_leaf.prefix = ' ' + inner_args = [for_leaf, fp, in_leaf, it] + if test: + test.prefix = ' ' + if_leaf = Leaf(token.NAME, 'if') + if_leaf.prefix = ' ' + inner_args.append(Node(syms.comp_if, [if_leaf, test])) + inner = Node(syms.listmaker, [xp, Node(syms.comp_for, inner_args)]) + return Node(syms.atom, + [Leaf(token.LBRACE, '['), inner, + Leaf(token.RBRACE, ']')]) + + +def FromImport(package_name, name_leafs): + """ Return an import statement in the form: + from package import name_leafs""" + # XXX: May not handle dotted imports properly (eg, package_name='foo.bar') + # #assert package_name == '.' or '.' not in package_name, "FromImport has "\ + # "not been tested with dotted package names -- use at your own "\ + # "peril!" + + for leaf in name_leafs: + # Pull the leaves out of their old tree + leaf.remove() + + children = [ + Leaf(token.NAME, 'from'), + Leaf(token.NAME, package_name, prefix=' '), + Leaf(token.NAME, 'import', prefix=' '), + Node(syms.import_as_names, name_leafs) + ] + imp = Node(syms.import_from, children) + return imp + + +def ImportAndCall(node, results, names): + """Returns an import statement and calls a method + of the module: + + import module + module.name()""" + obj = results['obj'].clone() + if obj.type == syms.arglist: + newarglist = obj.clone() + else: + newarglist = Node(syms.arglist, [obj.clone()]) + after = results['after'] + if after: + after = [n.clone() for n in after] + new = Node( + syms.power, + Attr(Name(names[0]), Name(names[1])) + [ + Node(syms.trailer, + [results['lpar'].clone(), newarglist, results['rpar'].clone()]) + ] + after) + new.prefix = node.prefix + return new + + +########################################################### +# Determine whether a node represents a given literal +########################################################### + + +def is_tuple(node): + """Does the node represent a tuple literal?""" + if isinstance(node, Node) and node.children == [LParen(), RParen()]: + return True + return (isinstance(node, Node) and len(node.children) == 3 and + isinstance(node.children[0], Leaf) and + isinstance(node.children[1], Node) and + isinstance(node.children[2], Leaf) and + node.children[0].value == '(' and node.children[2].value == ')') + + +def is_list(node): + """Does the node represent a list literal?""" + return (isinstance(node, Node) and len(node.children) > 1 and + isinstance(node.children[0], Leaf) and + isinstance(node.children[-1], Leaf) and + node.children[0].value == '[' and node.children[-1].value == ']') + + +########################################################### +# Misc +########################################################### + + +def parenthesize(node): + return Node(syms.atom, [LParen(), node, RParen()]) + + +consuming_calls = { + 'sorted', 'list', 'set', 'any', 'all', 'tuple', 'sum', 'min', 'max', + 'enumerate' +} + + +def attr_chain(obj, attr): + """Follow an attribute chain. + + If you have a chain of objects where a.foo -> b, b.foo-> c, etc, + use this to iterate over all objects in the chain. Iteration is + terminated by getattr(x, attr) is None. + + Args: + obj: the starting object + attr: the name of the chaining attribute + + Yields: + Each successive object in the chain. + """ + next = getattr(obj, attr) + while next: + yield next + next = getattr(next, attr) + + +p0 = """for_stmt< 'for' any 'in' node=any ':' any* > + | comp_for< 'for' any 'in' node=any any* > + """ +p1 = """ +power< + ( 'iter' | 'list' | 'tuple' | 'sorted' | 'set' | 'sum' | + 'any' | 'all' | 'enumerate' | (any* trailer< '.' 'join' >) ) + trailer< '(' node=any ')' > + any* +> +""" +p2 = """ +power< + ( 'sorted' | 'enumerate' ) + trailer< '(' arglist ')' > + any* +> +""" +pats_built = False + + +def in_special_context(node): + """ Returns true if node is in an environment where all that is required + of it is being iterable (ie, it doesn't matter if it returns a list + or an iterator). + See test_map_nochange in test_fixers.py for some examples and tests. + """ + global p0, p1, p2, pats_built + if not pats_built: + p0 = patcomp.compile_pattern(p0) + p1 = patcomp.compile_pattern(p1) + p2 = patcomp.compile_pattern(p2) + pats_built = True + patterns = [p0, p1, p2] + for pattern, parent in zip(patterns, attr_chain(node, 'parent')): + results = {} + if pattern.match(parent, results) and results['node'] is node: + return True + return False + + +def is_probably_builtin(node): + """ + Check that something isn't an attribute or function name etc. + """ + prev = node.prev_sibling + if prev is not None and prev.type == token.DOT: + # Attribute lookup. + return False + parent = node.parent + if parent.type in (syms.funcdef, syms.classdef): + return False + if parent.type == syms.expr_stmt and parent.children[0] is node: + # Assignment. + return False + if parent.type == syms.parameters or (parent.type == syms.typedargslist and ( + (prev is not None and prev.type == token.COMMA) or + parent.children[0] is node)): + # The name of an argument. + return False + return True + + +def find_indentation(node): + """Find the indentation of *node*.""" + while node is not None: + if node.type == syms.suite and len(node.children) > 2: + indent = node.children[1] + if indent.type == token.INDENT: + return indent.value + node = node.parent + return '' + + +########################################################### +# The following functions are to find bindings in a suite +########################################################### + + +def make_suite(node): + if node.type == syms.suite: + return node + node = node.clone() + parent, node.parent = node.parent, None + suite = Node(syms.suite, [node]) + suite.parent = parent + return suite + + +def find_root(node): + """Find the top level namespace.""" + # Scamper up to the top level namespace + while node.type != syms.file_input: + node = node.parent + if not node: + raise ValueError('root found before file_input node was found.') + return node + + +def does_tree_import(package, name, node): + """ Returns true if name is imported from package at the + top level of the tree which node belongs to. + To cover the case of an import like 'import foo', use + None for the package and 'foo' for the name. """ + binding = find_binding(name, find_root(node), package) + return bool(binding) + + +def is_import(node): + """Returns true if the node is an import statement.""" + return node.type in (syms.import_name, syms.import_from) + + +def touch_import(package, name, node): + """ Works like `does_tree_import` but adds an import statement + if it was not imported. """ + + def is_import_stmt(node): + return (node.type == syms.simple_stmt and node.children and + is_import(node.children[0])) + + root = find_root(node) + + if does_tree_import(package, name, root): + return + + # figure out where to insert the new import. First try to find + # the first import and then skip to the last one. + insert_pos = offset = 0 + for idx, node in enumerate(root.children): + if not is_import_stmt(node): + continue + for offset, node2 in enumerate(root.children[idx:]): + if not is_import_stmt(node2): + break + insert_pos = idx + offset + break + + # if there are no imports where we can insert, find the docstring. + # if that also fails, we stick to the beginning of the file + if insert_pos == 0: + for idx, node in enumerate(root.children): + if (node.type == syms.simple_stmt and node.children and + node.children[0].type == token.STRING): + insert_pos = idx + 1 + break + + if package is None: + import_ = Node( + syms.import_name, + [Leaf(token.NAME, 'import'), + Leaf(token.NAME, name, prefix=' ')]) + else: + import_ = FromImport(package, [Leaf(token.NAME, name, prefix=' ')]) + + children = [import_, Newline()] + root.insert_child(insert_pos, Node(syms.simple_stmt, children)) + + +_def_syms = {syms.classdef, syms.funcdef} + + +def find_binding(name, node, package=None): + """ Returns the node which binds variable name, otherwise None. + If optional argument package is supplied, only imports will + be returned. + See test cases for examples.""" + for child in node.children: + ret = None + if child.type == syms.for_stmt: + if _find(name, child.children[1]): + return child + n = find_binding(name, make_suite(child.children[-1]), package) + if n: + ret = n + elif child.type in (syms.if_stmt, syms.while_stmt): + n = find_binding(name, make_suite(child.children[-1]), package) + if n: + ret = n + elif child.type == syms.try_stmt: + n = find_binding(name, make_suite(child.children[2]), package) + if n: + ret = n + else: + for i, kid in enumerate(child.children[3:]): + if kid.type == token.COLON and kid.value == ':': + # i+3 is the colon, i+4 is the suite + n = find_binding(name, make_suite(child.children[i + 4]), package) + if n: + ret = n + elif child.type in _def_syms and child.children[1].value == name: + ret = child + elif _is_import_binding(child, name, package): + ret = child + elif child.type == syms.simple_stmt: + ret = find_binding(name, child, package) + elif child.type == syms.expr_stmt: + if _find(name, child.children[0]): + ret = child + + if ret: + if not package: + return ret + if is_import(ret): + return ret + return None + + +_block_syms = {syms.funcdef, syms.classdef, syms.trailer} + + +def _find(name, node): + nodes = [node] + while nodes: + node = nodes.pop() + if node.type > 256 and node.type not in _block_syms: + nodes.extend(node.children) + elif node.type == token.NAME and node.value == name: + return node + return None + + +def _is_import_binding(node, name, package=None): + """ Will return node if node will import name, or node + will import * from package. None is returned otherwise. + See test cases for examples. """ + + if node.type == syms.import_name and not package: + imp = node.children[1] + if imp.type == syms.dotted_as_names: + for child in imp.children: + if child.type == syms.dotted_as_name: + if child.children[2].value == name: + return node + elif child.type == token.NAME and child.value == name: + return node + elif imp.type == syms.dotted_as_name: + last = imp.children[-1] + if last.type == token.NAME and last.value == name: + return node + elif imp.type == token.NAME and imp.value == name: + return node + elif node.type == syms.import_from: + # str(...) is used to make life easier here, because + # from a.b import parses to ['import', ['a', '.', 'b'], ...] + if package and str(node.children[1]).strip() != package: + return None + n = node.children[3] + if package and _find('as', n): + # See test_from_import_as for explanation + return None + elif n.type == syms.import_as_names and _find(name, n): + return node + elif n.type == syms.import_as_name: + child = n.children[2] + if child.type == token.NAME and child.value == name: + return node + elif n.type == token.NAME and n.value == name: + return node + elif package and n.type == token.STAR: + return node + return None diff --git a/third_party/yapf_third_party/_ylib2to3/patcomp.py b/third_party/yapf_third_party/_ylib2to3/patcomp.py new file mode 100644 index 000000000..20b7893d3 --- /dev/null +++ b/third_party/yapf_third_party/_ylib2to3/patcomp.py @@ -0,0 +1,209 @@ +# Copyright 2006 Google, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. +"""Pattern compiler. + +The grammar is taken from PatternGrammar.txt. + +The compiler compiles a pattern to a pytree.*Pattern instance. +""" + +__author__ = 'Guido van Rossum ' + +# Python imports +import io + +# Really local imports +from . import pygram +from . import pytree +# Fairly local imports +from .pgen2 import driver +from .pgen2 import grammar +from .pgen2 import literals +from .pgen2 import parse +from .pgen2 import token +from .pgen2 import tokenize + + +class PatternSyntaxError(Exception): + pass + + +def tokenize_wrapper(input): + """Tokenizes a string suppressing significant whitespace.""" + skip = {token.NEWLINE, token.INDENT, token.DEDENT} + tokens = tokenize.generate_tokens(io.StringIO(input).readline) + for quintuple in tokens: + type, value, start, end, line_text = quintuple + if type not in skip: + yield quintuple + + +class PatternCompiler(object): + + def __init__(self, grammar_file=None): + """Initializer. + + Takes an optional alternative filename for the pattern grammar. + """ + if grammar_file is None: + self.grammar = pygram.pattern_grammar + self.syms = pygram.pattern_symbols + else: + self.grammar = driver.load_grammar(grammar_file) + self.syms = pygram.Symbols(self.grammar) + self.pygrammar = pygram.python_grammar + self.pysyms = pygram.python_symbols + self.driver = driver.Driver(self.grammar, convert=pattern_convert) + + def compile_pattern(self, input, debug=False, with_tree=False): + """Compiles a pattern string to a nested pytree.*Pattern object.""" + tokens = tokenize_wrapper(input) + try: + root = self.driver.parse_tokens(tokens, debug=debug) + except parse.ParseError as e: + raise PatternSyntaxError(str(e)) from None + if with_tree: + return self.compile_node(root), root + else: + return self.compile_node(root) + + def compile_node(self, node): + """Compiles a node, recursively. + + This is one big switch on the node type. + """ + # XXX Optimize certain Wildcard-containing-Wildcard patterns + # that can be merged + if node.type == self.syms.Matcher: + node = node.children[0] # Avoid unneeded recursion + + if node.type == self.syms.Alternatives: + # Skip the odd children since they are just '|' tokens + alts = [self.compile_node(ch) for ch in node.children[::2]] + if len(alts) == 1: + return alts[0] + p = pytree.WildcardPattern([[a] for a in alts], min=1, max=1) + return p.optimize() + + if node.type == self.syms.Alternative: + units = [self.compile_node(ch) for ch in node.children] + if len(units) == 1: + return units[0] + p = pytree.WildcardPattern([units], min=1, max=1) + return p.optimize() + + if node.type == self.syms.NegatedUnit: + pattern = self.compile_basic(node.children[1:]) + p = pytree.NegatedPattern(pattern) + return p.optimize() + + assert node.type == self.syms.Unit + + name = None + nodes = node.children + if len(nodes) >= 3 and nodes[1].type == token.EQUAL: + name = nodes[0].value + nodes = nodes[2:] + repeat = None + if len(nodes) >= 2 and nodes[-1].type == self.syms.Repeater: + repeat = nodes[-1] + nodes = nodes[:-1] + + # Now we've reduced it to: STRING | NAME [Details] | (...) | [...] + pattern = self.compile_basic(nodes, repeat) + + if repeat is not None: + assert repeat.type == self.syms.Repeater + children = repeat.children + child = children[0] + if child.type == token.STAR: + min = 0 + max = pytree.HUGE + elif child.type == token.PLUS: + min = 1 + max = pytree.HUGE + elif child.type == token.LBRACE: + assert children[-1].type == token.RBRACE + assert len(children) in (3, 5) + min = max = self.get_int(children[1]) + if len(children) == 5: + max = self.get_int(children[3]) + else: + assert False + if min != 1 or max != 1: + pattern = pattern.optimize() + pattern = pytree.WildcardPattern([[pattern]], min=min, max=max) + + if name is not None: + pattern.name = name + return pattern.optimize() + + def compile_basic(self, nodes, repeat=None): + # Compile STRING | NAME [Details] | (...) | [...] + assert len(nodes) >= 1 + node = nodes[0] + if node.type == token.STRING: + value = str(literals.evalString(node.value)) + return pytree.LeafPattern(_type_of_literal(value), value) + elif node.type == token.NAME: + value = node.value + if value.isupper(): + if value not in TOKEN_MAP: + raise PatternSyntaxError('Invalid token: %r' % value) + if nodes[1:]: + raise PatternSyntaxError("Can't have details for token") + return pytree.LeafPattern(TOKEN_MAP[value]) + else: + if value == 'any': + type = None + elif not value.startswith('_'): + type = getattr(self.pysyms, value, None) + if type is None: + raise PatternSyntaxError('Invalid symbol: %r' % value) + if nodes[1:]: # Details present + content = [self.compile_node(nodes[1].children[1])] + else: + content = None + return pytree.NodePattern(type, content) + elif node.value == '(': + return self.compile_node(nodes[1]) + elif node.value == '[': + assert repeat is None + subpattern = self.compile_node(nodes[1]) + return pytree.WildcardPattern([[subpattern]], min=0, max=1) + assert False, node + + def get_int(self, node): + assert node.type == token.NUMBER + return int(node.value) + + +# Map named tokens to the type value for a LeafPattern +TOKEN_MAP = { + 'NAME': token.NAME, + 'STRING': token.STRING, + 'NUMBER': token.NUMBER, + 'TOKEN': None +} + + +def _type_of_literal(value): + if value[0].isalpha(): + return token.NAME + elif value in grammar.opmap: + return grammar.opmap[value] + else: + return None + + +def pattern_convert(grammar, raw_node_info): + """Converts raw node information to a Node or Leaf instance.""" + type, value, context, children = raw_node_info + if children or type in grammar.number2symbol: + return pytree.Node(type, children, context=context) + else: + return pytree.Leaf(type, value, context=context) + + +def compile_pattern(pattern): + return PatternCompiler().compile_pattern(pattern) diff --git a/third_party/yapf_third_party/_ylib2to3/pgen2/__init__.py b/third_party/yapf_third_party/_ylib2to3/pgen2/__init__.py new file mode 100644 index 000000000..7c8380a16 --- /dev/null +++ b/third_party/yapf_third_party/_ylib2to3/pgen2/__init__.py @@ -0,0 +1,3 @@ +# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. +"""The pgen2 package.""" diff --git a/third_party/yapf_third_party/_ylib2to3/pgen2/conv.py b/third_party/yapf_third_party/_ylib2to3/pgen2/conv.py new file mode 100644 index 000000000..a446771b8 --- /dev/null +++ b/third_party/yapf_third_party/_ylib2to3/pgen2/conv.py @@ -0,0 +1,254 @@ +# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. +"""Convert graminit.[ch] spit out by pgen to Python code. + +Pgen is the Python parser generator. It is useful to quickly create a +parser from a grammar file in Python's grammar notation. But I don't +want my parsers to be written in C (yet), so I'm translating the +parsing tables to Python data structures and writing a Python parse +engine. + +Note that the token numbers are constants determined by the standard +Python tokenizer. The standard token module defines these numbers and +their names (the names are not used much). The token numbers are +hardcoded into the Python tokenizer and into pgen. A Python +implementation of the Python tokenizer is also available, in the +standard tokenize module. + +On the other hand, symbol numbers (representing the grammar's +non-terminals) are assigned by pgen based on the actual grammar +input. + +Note: this module is pretty much obsolete; the pgen module generates +equivalent grammar tables directly from the Grammar.txt input file +without having to invoke the Python pgen C program. + +""" + +# Python imports +import re + +# Local imports +from pgen2 import grammar +from pgen2 import token + + +class Converter(grammar.Grammar): + """Grammar subclass that reads classic pgen output files. + + The run() method reads the tables as produced by the pgen parser + generator, typically contained in two C files, graminit.h and + graminit.c. The other methods are for internal use only. + + See the base class for more documentation. + + """ + + def run(self, graminit_h, graminit_c): + """Load the grammar tables from the text files written by pgen.""" + self.parse_graminit_h(graminit_h) + self.parse_graminit_c(graminit_c) + self.finish_off() + + def parse_graminit_h(self, filename): + """Parse the .h file written by pgen. (Internal) + + This file is a sequence of #define statements defining the + nonterminals of the grammar as numbers. We build two tables + mapping the numbers to names and back. + + """ + try: + f = open(filename) + except OSError as err: + print("Can't open %s: %s" % (filename, err)) + return False + self.symbol2number = {} + self.number2symbol = {} + lineno = 0 + for line in f: + lineno += 1 + mo = re.match(r'^#define\s+(\w+)\s+(\d+)$', line) + if not mo and line.strip(): + print("%s(%s): can't parse %s" % (filename, lineno, line.strip())) + else: + symbol, number = mo.groups() + number = int(number) + assert symbol not in self.symbol2number + assert number not in self.number2symbol + self.symbol2number[symbol] = number + self.number2symbol[number] = symbol + return True + + def parse_graminit_c(self, filename): + """Parse the .c file written by pgen. (Internal) + + The file looks as follows. The first two lines are always this: + + #include "pgenheaders.h" + #include "grammar.h" + + After that come four blocks: + + 1) one or more state definitions + 2) a table defining dfas + 3) a table defining labels + 4) a struct defining the grammar + + A state definition has the following form: + - one or more arc arrays, each of the form: + static arc arcs__[] = { + {, }, + ... + }; + - followed by a state array, of the form: + static state states_[] = { + {, arcs__}, + ... + }; + + """ + try: + f = open(filename) + except OSError as err: + print("Can't open %s: %s" % (filename, err)) + return False + # The code below essentially uses f's iterator-ness! + lineno = 0 + + # Expect the two #include lines + lineno, line = lineno + 1, next(f) + assert line == '#include "pgenheaders.h"\n', (lineno, line) + lineno, line = lineno + 1, next(f) + assert line == '#include "grammar.h"\n', (lineno, line) + + # Parse the state definitions + lineno, line = lineno + 1, next(f) + allarcs = {} + states = [] + while line.startswith('static arc '): + while line.startswith('static arc '): + mo = re.match(r'static arc arcs_(\d+)_(\d+)\[(\d+)\] = {$', line) + assert mo, (lineno, line) + n, m, k = list(map(int, mo.groups())) + arcs = [] + for _ in range(k): + lineno, line = lineno + 1, next(f) + mo = re.match(r'\s+{(\d+), (\d+)},$', line) + assert mo, (lineno, line) + i, j = list(map(int, mo.groups())) + arcs.append((i, j)) + lineno, line = lineno + 1, next(f) + assert line == '};\n', (lineno, line) + allarcs[(n, m)] = arcs + lineno, line = lineno + 1, next(f) + mo = re.match(r'static state states_(\d+)\[(\d+)\] = {$', line) + assert mo, (lineno, line) + s, t = list(map(int, mo.groups())) + assert s == len(states), (lineno, line) + state = [] + for _ in range(t): + lineno, line = lineno + 1, next(f) + mo = re.match(r'\s+{(\d+), arcs_(\d+)_(\d+)},$', line) + assert mo, (lineno, line) + k, n, m = list(map(int, mo.groups())) + arcs = allarcs[n, m] + assert k == len(arcs), (lineno, line) + state.append(arcs) + states.append(state) + lineno, line = lineno + 1, next(f) + assert line == '};\n', (lineno, line) + lineno, line = lineno + 1, next(f) + self.states = states + + # Parse the dfas + dfas = {} + mo = re.match(r'static dfa dfas\[(\d+)\] = {$', line) + assert mo, (lineno, line) + ndfas = int(mo.group(1)) + for i in range(ndfas): + lineno, line = lineno + 1, next(f) + mo = re.match(r'\s+{(\d+), "(\w+)", (\d+), (\d+), states_(\d+),$', line) + assert mo, (lineno, line) + symbol = mo.group(2) + number, x, y, z = list(map(int, mo.group(1, 3, 4, 5))) + assert self.symbol2number[symbol] == number, (lineno, line) + assert self.number2symbol[number] == symbol, (lineno, line) + assert x == 0, (lineno, line) + state = states[z] + assert y == len(state), (lineno, line) + lineno, line = lineno + 1, next(f) + mo = re.match(r'\s+("(?:\\\d\d\d)*")},$', line) + assert mo, (lineno, line) + first = {} + rawbitset = eval(mo.group(1)) + for i, c in enumerate(rawbitset): + byte = ord(c) + for j in range(8): + if byte & (1 << j): + first[i * 8 + j] = 1 + dfas[number] = (state, first) + lineno, line = lineno + 1, next(f) + assert line == '};\n', (lineno, line) + self.dfas = dfas + + # Parse the labels + labels = [] + lineno, line = lineno + 1, next(f) + mo = re.match(r'static label labels\[(\d+)\] = {$', line) + assert mo, (lineno, line) + nlabels = int(mo.group(1)) + for i in range(nlabels): + lineno, line = lineno + 1, next(f) + mo = re.match(r'\s+{(\d+), (0|"\w+")},$', line) + assert mo, (lineno, line) + x, y = mo.groups() + x = int(x) + if y == '0': + y = None + else: + y = eval(y) + labels.append((x, y)) + lineno, line = lineno + 1, next(f) + assert line == '};\n', (lineno, line) + self.labels = labels + + # Parse the grammar struct + lineno, line = lineno + 1, next(f) + assert line == 'grammar _PyParser_Grammar = {\n', (lineno, line) + lineno, line = lineno + 1, next(f) + mo = re.match(r'\s+(\d+),$', line) + assert mo, (lineno, line) + ndfas = int(mo.group(1)) + assert ndfas == len(self.dfas) + lineno, line = lineno + 1, next(f) + assert line == '\tdfas,\n', (lineno, line) + lineno, line = lineno + 1, next(f) + mo = re.match(r'\s+{(\d+), labels},$', line) + assert mo, (lineno, line) + nlabels = int(mo.group(1)) + assert nlabels == len(self.labels), (lineno, line) + lineno, line = lineno + 1, next(f) + mo = re.match(r'\s+(\d+)$', line) + assert mo, (lineno, line) + start = int(mo.group(1)) + assert start in self.number2symbol, (lineno, line) + self.start = start + lineno, line = lineno + 1, next(f) + assert line == '};\n', (lineno, line) + try: + lineno, line = lineno + 1, next(f) + except StopIteration: + pass + else: + assert 0, (lineno, line) + + def finish_off(self): + """Create additional useful structures. (Internal).""" + self.keywords = {} # map from keyword strings to arc labels + self.tokens = {} # map from numeric token values to arc labels + for ilabel, (type, value) in enumerate(self.labels): + if type == token.NAME and value is not None: + self.keywords[value] = ilabel + elif value is None: + self.tokens[type] = ilabel diff --git a/third_party/yapf_third_party/_ylib2to3/pgen2/driver.py b/third_party/yapf_third_party/_ylib2to3/pgen2/driver.py new file mode 100644 index 000000000..9345fe5aa --- /dev/null +++ b/third_party/yapf_third_party/_ylib2to3/pgen2/driver.py @@ -0,0 +1,300 @@ +# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. + +# Modifications: +# Copyright 2006 Google, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. +"""Parser driver. + +This provides a high-level interface to parse a file into a syntax tree. + +""" + +__author__ = 'Guido van Rossum ' + +__all__ = ['Driver', 'load_grammar'] + +import io +import logging +import os +import pkgutil +import sys +# Python imports +from configparser import ConfigParser +from contextlib import contextmanager +from dataclasses import dataclass +from dataclasses import field +from pathlib import Path +from pkgutil import get_data +from typing import Any +from typing import Iterator +from typing import List +from typing import Optional + +from importlib_metadata import metadata +from platformdirs import user_cache_dir + +# Pgen imports +from . import grammar +from . import parse +from . import pgen +from . import token +from . import tokenize + + +@dataclass +class ReleaseRange: + start: int + end: Optional[int] = None + tokens: List[Any] = field(default_factory=list) + + def lock(self) -> None: + total_eaten = len(self.tokens) + self.end = self.start + total_eaten + + +class TokenProxy: + + def __init__(self, generator: Any) -> None: + self._tokens = generator + self._counter = 0 + self._release_ranges: List[ReleaseRange] = [] + + @contextmanager + def release(self) -> Iterator['TokenProxy']: + release_range = ReleaseRange(self._counter) + self._release_ranges.append(release_range) + try: + yield self + finally: + # Lock the last release range to the final position that + # has been eaten. + release_range.lock() + + def eat(self, point: int) -> Any: + eaten_tokens = self._release_ranges[-1].tokens + if point < len(eaten_tokens): + return eaten_tokens[point] + else: + while point >= len(eaten_tokens): + token = next(self._tokens) + eaten_tokens.append(token) + return token + + def __iter__(self) -> 'TokenProxy': + return self + + def __next__(self) -> Any: + # If the current position is already compromised (looked up) + # return the eaten token, if not just go further on the given + # token producer. + for release_range in self._release_ranges: + assert release_range.end is not None + + start, end = release_range.start, release_range.end + if start <= self._counter < end: + token = release_range.tokens[self._counter - start] + break + else: + token = next(self._tokens) + self._counter += 1 + return token + + def can_advance(self, to: int) -> bool: + # Try to eat, fail if it can't. The eat operation is cached + # so there wont be any additional cost of eating here + try: + self.eat(to) + except StopIteration: + return False + else: + return True + + +class Driver(object): + + def __init__(self, grammar, convert=None, logger=None): + self.grammar = grammar + if logger is None: + logger = logging.getLogger() + self.logger = logger + self.convert = convert + + def parse_tokens(self, tokens, debug=False): + """Parse a series of tokens and return the syntax tree.""" + # XXX Move the prefix computation into a wrapper around tokenize. + p = parse.Parser(self.grammar, self.convert) + proxy = TokenProxy(tokens) + p.setup(proxy=proxy) + lineno = 1 + column = 0 + type = value = start = end = line_text = None + prefix = '' + for quintuple in proxy: + type, value, start, end, line_text = quintuple + if start != (lineno, column): + assert (lineno, column) <= start, ((lineno, column), start) + s_lineno, s_column = start + if lineno < s_lineno: + prefix += '\n' * (s_lineno - lineno) + lineno = s_lineno + column = 0 + if column < s_column: + prefix += line_text[column:s_column] + column = s_column + if type in (tokenize.COMMENT, tokenize.NL): + prefix += value + lineno, column = end + if value.endswith('\n'): + lineno += 1 + column = 0 + continue + if type == token.OP: + type = grammar.opmap[value] + if debug: + self.logger.debug('%s %r (prefix=%r)', token.tok_name[type], value, + prefix) + if p.addtoken(type, value, (prefix, start)): + if debug: + self.logger.debug('Stop.') + break + prefix = '' + lineno, column = end + if value.endswith('\n'): + lineno += 1 + column = 0 + else: + # We never broke out -- EOF is too soon (how can this happen???) + raise parse.ParseError('incomplete input', type, value, (prefix, start)) + return p.rootnode + + def parse_stream_raw(self, stream, debug=False): + """Parse a stream and return the syntax tree.""" + tokens = tokenize.generate_tokens(stream.readline) + return self.parse_tokens(tokens, debug) + + def parse_stream(self, stream, debug=False): + """Parse a stream and return the syntax tree.""" + return self.parse_stream_raw(stream, debug) + + def parse_file(self, filename, encoding=None, debug=False): + """Parse a file and return the syntax tree.""" + with io.open(filename, 'r', encoding=encoding) as stream: + return self.parse_stream(stream, debug) + + def parse_string(self, text, debug=False): + """Parse a string and return the syntax tree.""" + tokens = tokenize.generate_tokens(io.StringIO(text).readline) + return self.parse_tokens(tokens, debug) + + +def _generate_pickle_name(gt): + # type:(str) -> str + """Get the filepath to write a pickle file to + given the path of a grammar textfile. + + The returned filepath should be in a user-specific cache directory. + + Args: + gt (str): path to grammar text file + + Returns: + str: path to pickle file + """ + + grammar_textfile_name = os.path.basename(gt) + head, tail = os.path.splitext(grammar_textfile_name) + if tail == '.txt': + tail = '' + cache_dir = user_cache_dir( + appname=metadata('yapf')['Name'].upper(), + appauthor=metadata('yapf')['Author'].split(' ')[0], + version=metadata('yapf')['Version'], + ) + return cache_dir + os.sep + head + tail + '-py' + '.'.join( + map(str, sys.version_info)) + '.pickle' + + +def load_grammar(gt='Grammar.txt', + gp=None, + save=True, + force=False, + logger=None): + # type:(str, str | None, bool, bool, logging.Logger | None) -> grammar.Grammar + """Load the grammar (maybe from a pickle).""" + if logger is None: + logger = logging.getLogger() + gp = _generate_pickle_name(gt) if gp is None else gp + grammar_text = gt + try: + newer = _newer(gp, gt) + except OSError as err: + logger.debug('OSError, could not check if newer: %s', err.args) + newer = True + if not os.path.exists(gt): + # Assume package data + gt_basename = os.path.basename(gt) + pd = pkgutil.get_data('yapf_third_party._ylib2to3', gt_basename) + if pd is None: + raise RuntimeError('Failed to load grammer %s from package' % gt_basename) + grammar_text = io.StringIO(pd.decode(encoding='utf-8')) + if force or not newer: + g = pgen.generate_grammar(grammar_text) + if save: + try: + Path(gp).parent.mkdir(parents=True, exist_ok=True) + g.dump(gp) + except OSError: + # Ignore error, caching is not vital. + pass + else: + g = grammar.Grammar() + g.load(gp) + return g + + +def _newer(a, b): + """Inquire whether file a was written since file b.""" + if not os.path.exists(a): + return False + if not os.path.exists(b): + return True + return os.path.getmtime(a) >= os.path.getmtime(b) + + +def load_packaged_grammar(package, grammar_source): + """Normally, loads a pickled grammar by doing + pkgutil.get_data(package, pickled_grammar) + where *pickled_grammar* is computed from *grammar_source* by adding the + Python version and using a ``.pickle`` extension. + + However, if *grammar_source* is an extant file, load_grammar(grammar_source) + is called instead. This facilitates using a packaged grammar file when needed + but preserves load_grammar's automatic regeneration behavior when possible. + + """ # noqa: E501 + if os.path.isfile(grammar_source): + return load_grammar(grammar_source) + pickled_name = _generate_pickle_name(os.path.basename(grammar_source)) + data = pkgutil.get_data(package, pickled_name) + g = grammar.Grammar() + g.loads(data) + return g + + +def main(*args): + """Main program, when run as a script: produce grammar pickle files. + + Calls load_grammar for each argument, a path to a grammar text file. + """ + if not args: + args = sys.argv[1:] + logging.basicConfig( + level=logging.INFO, stream=sys.stdout, format='%(message)s') + for gt in args: + load_grammar(gt, save=True, force=True) + return True + + +if __name__ == '__main__': + sys.exit(int(not main())) diff --git a/third_party/yapf_third_party/_ylib2to3/pgen2/grammar.py b/third_party/yapf_third_party/_ylib2to3/pgen2/grammar.py new file mode 100644 index 000000000..0840c3c71 --- /dev/null +++ b/third_party/yapf_third_party/_ylib2to3/pgen2/grammar.py @@ -0,0 +1,188 @@ +# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. +"""This module defines the data structures used to represent a grammar. + +These are a bit arcane because they are derived from the data +structures used by Python's 'pgen' parser generator. + +There's also a table here mapping operators to their names in the +token module; the Python tokenize module reports all operators as the +fallback token code OP, but the parser needs the actual token code. + +""" + +# Python imports +import pickle + +# Local imports +from . import token + + +class Grammar(object): + """Pgen parsing tables conversion class. + + Once initialized, this class supplies the grammar tables for the + parsing engine implemented by parse.py. The parsing engine + accesses the instance variables directly. The class here does not + provide initialization of the tables; several subclasses exist to + do this (see the conv and pgen modules). + + The load() method reads the tables from a pickle file, which is + much faster than the other ways offered by subclasses. The pickle + file is written by calling dump() (after loading the grammar + tables using a subclass). The report() method prints a readable + representation of the tables to stdout, for debugging. + + The instance variables are as follows: + + symbol2number -- a dict mapping symbol names to numbers. Symbol + numbers are always 256 or higher, to distinguish + them from token numbers, which are between 0 and + 255 (inclusive). + + number2symbol -- a dict mapping numbers to symbol names; + these two are each other's inverse. + + states -- a list of DFAs, where each DFA is a list of + states, each state is a list of arcs, and each + arc is a (i, j) pair where i is a label and j is + a state number. The DFA number is the index into + this list. (This name is slightly confusing.) + Final states are represented by a special arc of + the form (0, j) where j is its own state number. + + dfas -- a dict mapping symbol numbers to (DFA, first) + pairs, where DFA is an item from the states list + above, and first is a set of tokens that can + begin this grammar rule (represented by a dict + whose values are always 1). + + labels -- a list of (x, y) pairs where x is either a token + number or a symbol number, and y is either None + or a string; the strings are keywords. The label + number is the index in this list; label numbers + are used to mark state transitions (arcs) in the + DFAs. + + start -- the number of the grammar's start symbol. + + keywords -- a dict mapping keyword strings to arc labels. + + tokens -- a dict mapping token numbers to arc labels. + + """ + + def __init__(self): + self.symbol2number = {} + self.number2symbol = {} + self.states = [] + self.dfas = {} + self.labels = [(0, 'EMPTY')] + self.keywords = {} + self.soft_keywords = {} + self.tokens = {} + self.symbol2label = {} + self.start = 256 + + def dump(self, filename): + """Dump the grammar tables to a pickle file.""" + with open(filename, 'wb') as f: + pickle.dump(self.__dict__, f, pickle.HIGHEST_PROTOCOL) + + def load(self, filename): + """Load the grammar tables from a pickle file.""" + with open(filename, 'rb') as f: + d = pickle.load(f) + self.__dict__.update(d) + + def loads(self, pkl): + """Load the grammar tables from a pickle bytes object.""" + self.__dict__.update(pickle.loads(pkl)) + + def copy(self): + """ + Copy the grammar. + """ + new = self.__class__() + for dict_attr in ('symbol2number', 'number2symbol', 'dfas', 'keywords', + 'soft_keywords', 'tokens', 'symbol2label'): + setattr(new, dict_attr, getattr(self, dict_attr).copy()) + new.labels = self.labels[:] + new.states = self.states[:] + new.start = self.start + return new + + def report(self): + """Dump the grammar tables to standard output, for debugging.""" + from pprint import pprint + print('s2n') + pprint(self.symbol2number) + print('n2s') + pprint(self.number2symbol) + print('states') + pprint(self.states) + print('dfas') + pprint(self.dfas) + print('labels') + pprint(self.labels) + print('start', self.start) + + +# Map from operator to number (since tokenize doesn't do this) + +opmap_raw = """ +( LPAR +) RPAR +[ LSQB +] RSQB +: COLON +, COMMA +; SEMI ++ PLUS +- MINUS +* STAR +/ SLASH +| VBAR +& AMPER +< LESS +> GREATER += EQUAL +. DOT +% PERCENT +` BACKQUOTE +{ LBRACE +} RBRACE +@ AT +@= ATEQUAL +== EQEQUAL +!= NOTEQUAL +<> NOTEQUAL +<= LESSEQUAL +>= GREATEREQUAL +~ TILDE +^ CIRCUMFLEX +<< LEFTSHIFT +>> RIGHTSHIFT +** DOUBLESTAR ++= PLUSEQUAL +-= MINEQUAL +*= STAREQUAL +/= SLASHEQUAL +%= PERCENTEQUAL +&= AMPEREQUAL +|= VBAREQUAL +^= CIRCUMFLEXEQUAL +<<= LEFTSHIFTEQUAL +>>= RIGHTSHIFTEQUAL +**= DOUBLESTAREQUAL +// DOUBLESLASH +//= DOUBLESLASHEQUAL +-> RARROW +:= COLONEQUAL +""" + +opmap = {} +for line in opmap_raw.splitlines(): + if line: + op, name = line.split() + opmap[op] = getattr(token, name) diff --git a/third_party/yapf_third_party/_ylib2to3/pgen2/literals.py b/third_party/yapf_third_party/_ylib2to3/pgen2/literals.py new file mode 100644 index 000000000..62d1d2681 --- /dev/null +++ b/third_party/yapf_third_party/_ylib2to3/pgen2/literals.py @@ -0,0 +1,64 @@ +# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. +"""Safely evaluate Python string literals without using eval().""" + +import re + +simple_escapes = { + 'a': '\a', + 'b': '\b', + 'f': '\f', + 'n': '\n', + 'r': '\r', + 't': '\t', + 'v': '\v', + "'": "'", + '"': '"', + '\\': '\\' +} + + +def escape(m): + all, tail = m.group(0, 1) + assert all.startswith('\\') + esc = simple_escapes.get(tail) + if esc is not None: + return esc + if tail.startswith('x'): + hexes = tail[1:] + if len(hexes) < 2: + raise ValueError("invalid hex string escape ('\\%s')" % tail) + try: + i = int(hexes, 16) + except ValueError: + raise ValueError("invalid hex string escape ('\\%s')" % tail) from None + else: + try: + i = int(tail, 8) + except ValueError: + raise ValueError("invalid octal string escape ('\\%s')" % tail) from None + return chr(i) + + +def evalString(s): + assert s.startswith("'") or s.startswith('"'), repr(s[:1]) + q = s[0] + if s[:3] == q * 3: + q = q * 3 + assert s.endswith(q), repr(s[-len(q):]) + assert len(s) >= 2 * len(q) + s = s[len(q):-len(q)] + return re.sub(r"\\(\'|\"|\\|[abfnrtv]|x.{0,2}|[0-7]{1,3})", escape, s) + + +def test(): + for i in range(256): + c = chr(i) + s = repr(c) + e = evalString(s) + if e != c: + print(i, c, s, e) + + +if __name__ == '__main__': + test() diff --git a/third_party/yapf_third_party/_ylib2to3/pgen2/parse.py b/third_party/yapf_third_party/_ylib2to3/pgen2/parse.py new file mode 100644 index 000000000..924b0e74b --- /dev/null +++ b/third_party/yapf_third_party/_ylib2to3/pgen2/parse.py @@ -0,0 +1,378 @@ +# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. +"""Parser engine for the grammar tables generated by pgen. + +The grammar table must be loaded first. + +See Parser/parser.c in the Python distribution for additional info on +how this parsing engine works. + +""" +from contextlib import contextmanager +from typing import Any +from typing import Callable +from typing import Dict +from typing import Iterator +from typing import List +from typing import Optional +from typing import Set +from typing import Text +from typing import Tuple +from typing import cast + +from ..pytree import Context +from ..pytree import RawNode +from ..pytree import convert +# Local imports +from . import grammar +from . import token +from . import tokenize + +DFA = List[List[Tuple[int, int]]] +DFAS = Tuple[DFA, Dict[int, int]] + +# A placeholder node, used when parser is backtracking. +DUMMY_NODE = (-1, None, None, None) + + +def stack_copy( + stack: List[Tuple[DFAS, int, RawNode]]) -> List[Tuple[DFAS, int, RawNode]]: + """Nodeless stack copy.""" + return [(dfa, label, DUMMY_NODE) for dfa, label, _ in stack] + + +class Recorder: + + def __init__(self, parser: 'Parser', ilabels: List[int], + context: Context) -> None: + self.parser = parser + self._ilabels = ilabels + self.context = context # not really matter + + self._dead_ilabels: Set[int] = set() + self._start_point = self.parser.stack + self._points = {ilabel: stack_copy(self._start_point) for ilabel in ilabels} + + @property + def ilabels(self) -> Set[int]: + return self._dead_ilabels.symmetric_difference(self._ilabels) + + @contextmanager + def switch_to(self, ilabel: int) -> Iterator[None]: + with self.backtrack(): + self.parser.stack = self._points[ilabel] + try: + yield + except ParseError: + self._dead_ilabels.add(ilabel) + finally: + self.parser.stack = self._start_point + + @contextmanager + def backtrack(self) -> Iterator[None]: + """ + Use the node-level invariant ones for basic parsing operations (push/pop/shift). + These still will operate on the stack; but they won't create any new nodes, or + modify the contents of any other existing nodes. + This saves us a ton of time when we are backtracking, since we + want to restore to the initial state as quick as possible, which + can only be done by having as little mutatations as possible. + """ # noqa: E501 + is_backtracking = self.parser.is_backtracking + try: + self.parser.is_backtracking = True + yield + finally: + self.parser.is_backtracking = is_backtracking + + def add_token(self, tok_type: int, tok_val: Text, raw: bool = False) -> None: + func: Callable[..., Any] + if raw: + func = self.parser._addtoken + else: + func = self.parser.addtoken + + for ilabel in self.ilabels: + with self.switch_to(ilabel): + args = [tok_type, tok_val, self.context] + if raw: + args.insert(0, ilabel) + func(*args) + + def determine_route(self, + value: Text = None, + force: bool = False) -> Optional[int]: + alive_ilabels = self.ilabels + if len(alive_ilabels) == 0: + *_, most_successful_ilabel = self._dead_ilabels + raise ParseError('bad input', most_successful_ilabel, value, self.context) + + ilabel, *rest = alive_ilabels + if force or not rest: + return ilabel + else: + return None + + +class ParseError(Exception): + """Exception to signal the parser is stuck.""" + + def __init__(self, msg, type, value, context): + Exception.__init__( + self, '%s: type=%r, value=%r, context=%r' % (msg, type, value, context)) + self.msg = msg + self.type = type + self.value = value + self.context = context + + def __reduce__(self): + return type(self), (self.msg, self.type, self.value, self.context) + + +class Parser(object): + """Parser engine. + + The proper usage sequence is: + + p = Parser(grammar, [converter]) # create instance + p.setup([start]) # prepare for parsing + : + if p.addtoken(...): # parse a token; may raise ParseError + break + root = p.rootnode # root of abstract syntax tree + + A Parser instance may be reused by calling setup() repeatedly. + + A Parser instance contains state pertaining to the current token + sequence, and should not be used concurrently by different threads + to parse separate token sequences. + + See driver.py for how to get input tokens by tokenizing a file or + string. + + Parsing is complete when addtoken() returns True; the root of the + abstract syntax tree can then be retrieved from the rootnode + instance variable. When a syntax error occurs, addtoken() raises + the ParseError exception. There is no error recovery; the parser + cannot be used after a syntax error was reported (but it can be + reinitialized by calling setup()). + + """ + + def __init__(self, grammar, convert=None): + """Constructor. + + The grammar argument is a grammar.Grammar instance; see the + grammar module for more information. + + The parser is not ready yet for parsing; you must call the + setup() method to get it started. + + The optional convert argument is a function mapping concrete + syntax tree nodes to abstract syntax tree nodes. If not + given, no conversion is done and the syntax tree produced is + the concrete syntax tree. If given, it must be a function of + two arguments, the first being the grammar (a grammar.Grammar + instance), and the second being the concrete syntax tree node + to be converted. The syntax tree is converted from the bottom + up. + + A concrete syntax tree node is a (type, value, context, nodes) + tuple, where type is the node type (a token or symbol number), + value is None for symbols and a string for tokens, context is + None or an opaque value used for error reporting (typically a + (lineno, offset) pair), and nodes is a list of children for + symbols, and None for tokens. + + An abstract syntax tree node may be anything; this is entirely + up to the converter function. + + """ + self.grammar = grammar + self.convert = convert or (lambda grammar, node: node) + self.is_backtracking = False + + def setup(self, proxy, start=None): + """Prepare for parsing. + + This *must* be called before starting to parse. + + The optional argument is an alternative start symbol; it + defaults to the grammar's start symbol. + + You can use a Parser instance to parse any number of programs; + each time you call setup() the parser is reset to an initial + state determined by the (implicit or explicit) start symbol. + + """ + if start is None: + start = self.grammar.start + # Each stack entry is a tuple: (dfa, state, node). + # A node is a tuple: (type, value, context, children), + # where children is a list of nodes or None, and context may be None. + newnode = (start, None, None, []) + stackentry = (self.grammar.dfas[start], 0, newnode) + self.stack = [stackentry] + self.rootnode = None + self.used_names = set() # Aliased to self.rootnode.used_names in pop() + self.proxy = proxy + + def addtoken(self, type, value, context): + """Add a token; return True iff this is the end of the program.""" + # Map from token to label + ilabels = self.classify(type, value, context) + assert len(ilabels) >= 1 + + # If we have only one state to advance, we'll directly + # take it as is. + if len(ilabels) == 1: + [ilabel] = ilabels + return self._addtoken(ilabel, type, value, context) + + # If there are multiple states which we can advance (only + # happen under soft-keywords), then we will try all of them + # in parallel and as soon as one state can reach further than + # the rest, we'll choose that one. This is a pretty hacky + # and hopefully temporary algorithm. + # + # For a more detailed explanation, check out this post: + # https://tree.science/what-the-backtracking.html + + with self.proxy.release() as proxy: + counter, force = 0, False + recorder = Recorder(self, ilabels, context) + recorder.add_token(type, value, raw=True) + + next_token_value = value + while recorder.determine_route(next_token_value) is None: + if not proxy.can_advance(counter): + force = True + break + + next_token_type, next_token_value, *_ = proxy.eat(counter) + if next_token_type in (tokenize.COMMENT, tokenize.NL): + counter += 1 + continue + + if next_token_type == tokenize.OP: + next_token_type = grammar.opmap[next_token_value] + + recorder.add_token(next_token_type, next_token_value) + counter += 1 + + ilabel = cast(int, + recorder.determine_route(next_token_value, force=force)) + assert ilabel is not None + + return self._addtoken(ilabel, type, value, context) + + def _addtoken(self, ilabel: int, type: int, value: Text, + context: Context) -> bool: + # Loop until the token is shifted; may raise exceptions + while True: + dfa, state, node = self.stack[-1] + states, first = dfa + arcs = states[state] + # Look for a state with this label + for i, newstate in arcs: + t = self.grammar.labels[i][0] + if t >= 256: + # See if it's a symbol and if we're in its first set + itsdfa = self.grammar.dfas[t] + itsstates, itsfirst = itsdfa + if ilabel in itsfirst: + # Push a symbol + self.push(t, itsdfa, newstate, context) + break # To continue the outer while loop + + elif ilabel == i: + # Look it up in the list of labels + # Shift a token; we're done with it + self.shift(type, value, newstate, context) + # Pop while we are in an accept-only state + state = newstate + while states[state] == [(0, state)]: + self.pop() + if not self.stack: + # Done parsing! + return True + dfa, state, node = self.stack[-1] + states, first = dfa + # Done with this token + return False + + else: + if (0, state) in arcs: + # An accepting state, pop it and try something else + self.pop() + if not self.stack: + # Done parsing, but another token is input + raise ParseError('too much input', type, value, context) + else: + # No success finding a transition + raise ParseError('bad input', type, value, context) + + def classify(self, type, value, context): + """Turn a token into a label. (Internal) + + Depending on whether the value is a soft-keyword or not, + this function may return multiple labels to choose from.""" + if type == token.NAME: + # Keep a listing of all used names + self.used_names.add(value) + # Check for reserved words + if value in self.grammar.keywords: + return [self.grammar.keywords[value]] + elif value in self.grammar.soft_keywords: + assert type in self.grammar.tokens + return [ + self.grammar.soft_keywords[value], + self.grammar.tokens[type], + ] + + ilabel = self.grammar.tokens.get(type) + if ilabel is None: + raise ParseError('bad token', type, value, context) + return [ilabel] + + def shift(self, type: int, value: Text, newstate: int, + context: Context) -> None: + """Shift a token. (Internal)""" + if self.is_backtracking: + dfa, state, _ = self.stack[-1] + self.stack[-1] = (dfa, newstate, DUMMY_NODE) + else: + dfa, state, node = self.stack[-1] + rawnode: RawNode = (type, value, context, None) + newnode = convert(self.grammar, rawnode) + assert node[-1] is not None + node[-1].append(newnode) + self.stack[-1] = (dfa, newstate, node) + + def push(self, type: int, newdfa: DFAS, newstate: int, + context: Context) -> None: + """Push a nonterminal. (Internal)""" + if self.is_backtracking: + dfa, state, _ = self.stack[-1] + self.stack[-1] = (dfa, newstate, DUMMY_NODE) + self.stack.append((newdfa, 0, DUMMY_NODE)) + else: + dfa, state, node = self.stack[-1] + newnode: RawNode = (type, None, context, []) + self.stack[-1] = (dfa, newstate, node) + self.stack.append((newdfa, 0, newnode)) + + def pop(self) -> None: + """Pop a nonterminal. (Internal)""" + if self.is_backtracking: + self.stack.pop() + else: + popdfa, popstate, popnode = self.stack.pop() + newnode = convert(self.grammar, popnode) + if self.stack: + dfa, state, node = self.stack[-1] + assert node[-1] is not None + node[-1].append(newnode) + else: + self.rootnode = newnode + self.rootnode.used_names = self.used_names diff --git a/third_party/yapf_third_party/_ylib2to3/pgen2/pgen.py b/third_party/yapf_third_party/_ylib2to3/pgen2/pgen.py new file mode 100644 index 000000000..6b96478ad --- /dev/null +++ b/third_party/yapf_third_party/_ylib2to3/pgen2/pgen.py @@ -0,0 +1,409 @@ +# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. + +# Pgen imports +from io import StringIO + +from . import grammar +from . import token +from . import tokenize + + +class PgenGrammar(grammar.Grammar): + pass + + +class ParserGenerator(object): + + def __init__(self, filename=None, stream=None): + close_stream = None + if filename is None and stream is None: + raise RuntimeError( + 'Either a filename or a stream is expected, both were none') + if stream is None: + stream = open(filename, encoding='utf-8') + close_stream = stream.close + self.filename = filename + self.stream = stream + self.generator = tokenize.generate_tokens(stream.readline) + self.gettoken() # Initialize lookahead + self.dfas, self.startsymbol = self.parse() + if close_stream is not None: + close_stream() + self.first = {} # map from symbol name to set of tokens + self.addfirstsets() + + def make_grammar(self): + c = PgenGrammar() + names = list(self.dfas.keys()) + names.sort() + names.remove(self.startsymbol) + names.insert(0, self.startsymbol) + for name in names: + i = 256 + len(c.symbol2number) + c.symbol2number[name] = i + c.number2symbol[i] = name + for name in names: + dfa = self.dfas[name] + states = [] + for state in dfa: + arcs = [] + for label, next in sorted(state.arcs.items()): + arcs.append((self.make_label(c, label), dfa.index(next))) + if state.isfinal: + arcs.append((0, dfa.index(state))) + states.append(arcs) + c.states.append(states) + c.dfas[c.symbol2number[name]] = (states, self.make_first(c, name)) + c.start = c.symbol2number[self.startsymbol] + return c + + def make_first(self, c, name): + rawfirst = self.first[name] + first = {} + for label in sorted(rawfirst): + ilabel = self.make_label(c, label) + # assert ilabel not in first # XXX failed on <> ... != + first[ilabel] = 1 + return first + + def make_label(self, c, label): + # XXX Maybe this should be a method on a subclass of converter? + ilabel = len(c.labels) + if label[0].isalpha(): + # Either a symbol name or a named token + if label in c.symbol2number: + # A symbol name (a non-terminal) + if label in c.symbol2label: + return c.symbol2label[label] + else: + c.labels.append((c.symbol2number[label], None)) + c.symbol2label[label] = ilabel + return ilabel + else: + # A named token (NAME, NUMBER, STRING) + itoken = getattr(token, label, None) + assert isinstance(itoken, int), label + assert itoken in token.tok_name, label + if itoken in c.tokens: + return c.tokens[itoken] + else: + c.labels.append((itoken, None)) + c.tokens[itoken] = ilabel + return ilabel + else: + # Either a keyword or an operator + assert label[0] in ('"', "'"), label + value = eval(label) + if value[0].isalpha(): + if label[0] == '"': + keywords = c.soft_keywords + else: + keywords = c.keywords + + # A keyword + if value in keywords: + return keywords[value] + else: + c.labels.append((token.NAME, value)) + keywords[value] = ilabel + return ilabel + else: + # An operator (any non-numeric token) + itoken = grammar.opmap[value] # Fails if unknown token + if itoken in c.tokens: + return c.tokens[itoken] + else: + c.labels.append((itoken, None)) + c.tokens[itoken] = ilabel + return ilabel + + def addfirstsets(self): + names = list(self.dfas.keys()) + names.sort() + for name in names: + if name not in self.first: + self.calcfirst(name) + # print name, self.first[name].keys() + + def calcfirst(self, name): + dfa = self.dfas[name] + self.first[name] = None # dummy to detect left recursion + state = dfa[0] + totalset = {} + overlapcheck = {} + for label, next in state.arcs.items(): + if label in self.dfas: + if label in self.first: + fset = self.first[label] + if fset is None: + raise ValueError('recursion for rule %r' % name) + else: + self.calcfirst(label) + fset = self.first[label] + totalset.update(fset) + overlapcheck[label] = fset + else: + totalset[label] = 1 + overlapcheck[label] = {label: 1} + inverse = {} + for label, itsfirst in overlapcheck.items(): + for symbol in itsfirst: + if symbol in inverse: + raise ValueError('rule %s is ambiguous; %s is in the' + ' first sets of %s as well as %s' % + (name, symbol, label, inverse[symbol])) + inverse[symbol] = label + self.first[name] = totalset + + def parse(self): + dfas = {} + startsymbol = None + # MSTART: (NEWLINE | RULE)* ENDMARKER + while self.type != token.ENDMARKER: + while self.type == token.NEWLINE: + self.gettoken() + # RULE: NAME ':' RHS NEWLINE + name = self.expect(token.NAME) + self.expect(token.OP, ':') + a, z = self.parse_rhs() + self.expect(token.NEWLINE) + # self.dump_nfa(name, a, z) + dfa = self.make_dfa(a, z) + # self.dump_dfa(name, dfa) + self.simplify_dfa(dfa) + dfas[name] = dfa + # print name, oldlen, newlen + if startsymbol is None: + startsymbol = name + return dfas, startsymbol + + def make_dfa(self, start, finish): + # To turn an NFA into a DFA, we define the states of the DFA + # to correspond to *sets* of states of the NFA. Then do some + # state reduction. Let's represent sets as dicts with 1 for + # values. + assert isinstance(start, NFAState) + assert isinstance(finish, NFAState) + + def closure(state): + base = {} + addclosure(state, base) + return base + + def addclosure(state, base): + assert isinstance(state, NFAState) + if state in base: + return + base[state] = 1 + for label, next in state.arcs: + if label is None: + addclosure(next, base) + + states = [DFAState(closure(start), finish)] + for state in states: # NB states grows while we're iterating + arcs = {} + for nfastate in state.nfaset: + for label, next in nfastate.arcs: + if label is not None: + addclosure(next, arcs.setdefault(label, {})) + for label, nfaset in sorted(arcs.items()): + for st in states: + if st.nfaset == nfaset: + break + else: + st = DFAState(nfaset, finish) + states.append(st) + state.addarc(st, label) + return states # List of DFAState instances; first one is start + + def dump_nfa(self, name, start, finish): + print('Dump of NFA for', name) + todo = [start] + for i, state in enumerate(todo): + print(' State', i, state is finish and '(final)' or '') + for label, next in state.arcs: + if next in todo: + j = todo.index(next) + else: + j = len(todo) + todo.append(next) + if label is None: + print(' -> %d' % j) + else: + print(' %s -> %d' % (label, j)) + + def dump_dfa(self, name, dfa): + print('Dump of DFA for', name) + for i, state in enumerate(dfa): + print(' State', i, state.isfinal and '(final)' or '') + for label, next in sorted(state.arcs.items()): + print(' %s -> %d' % (label, dfa.index(next))) + + def simplify_dfa(self, dfa): + # This is not theoretically optimal, but works well enough. + # Algorithm: repeatedly look for two states that have the same + # set of arcs (same labels pointing to the same nodes) and + # unify them, until things stop changing. + + # dfa is a list of DFAState instances + changes = True + while changes: + changes = False + for i, state_i in enumerate(dfa): + for j in range(i + 1, len(dfa)): + state_j = dfa[j] + if state_i == state_j: + # print " unify", i, j + del dfa[j] + for state in dfa: + state.unifystate(state_j, state_i) + changes = True + break + + def parse_rhs(self): + # RHS: ALT ('|' ALT)* + a, z = self.parse_alt() + if self.value != '|': + return a, z + else: + aa = NFAState() + zz = NFAState() + aa.addarc(a) + z.addarc(zz) + while self.value == '|': + self.gettoken() + a, z = self.parse_alt() + aa.addarc(a) + z.addarc(zz) + return aa, zz + + def parse_alt(self): + # ALT: ITEM+ + a, b = self.parse_item() + while (self.value in ('(', '[') or self.type in (token.NAME, token.STRING)): + c, d = self.parse_item() + b.addarc(c) + b = d + return a, b + + def parse_item(self): + # ITEM: '[' RHS ']' | ATOM ['+' | '*'] + if self.value == '[': + self.gettoken() + a, z = self.parse_rhs() + self.expect(token.OP, ']') + a.addarc(z) + return a, z + else: + a, z = self.parse_atom() + value = self.value + if value not in ('+', '*'): + return a, z + self.gettoken() + z.addarc(a) + if value == '+': + return a, z + else: + return a, a + + def parse_atom(self): + # ATOM: '(' RHS ')' | NAME | STRING + if self.value == '(': + self.gettoken() + a, z = self.parse_rhs() + self.expect(token.OP, ')') + return a, z + elif self.type in (token.NAME, token.STRING): + a = NFAState() + z = NFAState() + a.addarc(z, self.value) + self.gettoken() + return a, z + else: + self.raise_error('expected (...) or NAME or STRING, got %s/%s', self.type, + self.value) + + def expect(self, type, value=None): + if self.type != type or (value is not None and self.value != value): + self.raise_error('expected %s/%s, got %s/%s', type, value, self.type, + self.value) + value = self.value + self.gettoken() + return value + + def gettoken(self): + tup = next(self.generator) + while tup[0] in (tokenize.COMMENT, tokenize.NL): + tup = next(self.generator) + self.type, self.value, self.begin, self.end, self.line = tup + # print token.tok_name[self.type], repr(self.value) + + def raise_error(self, msg, *args): + if args: + try: + msg = msg % args + except Exception: + msg = ' '.join([msg] + list(map(str, args))) + raise SyntaxError(msg, (self.filename, self.end[0], self.end[1], self.line)) + + +class NFAState(object): + + def __init__(self): + self.arcs = [] # list of (label, NFAState) pairs + + def addarc(self, next, label=None): + assert label is None or isinstance(label, str) + assert isinstance(next, NFAState) + self.arcs.append((label, next)) + + +class DFAState(object): + + def __init__(self, nfaset, final): + assert isinstance(nfaset, dict) + assert isinstance(next(iter(nfaset)), NFAState) + assert isinstance(final, NFAState) + self.nfaset = nfaset + self.isfinal = final in nfaset + self.arcs = {} # map from label to DFAState + + def addarc(self, next, label): + assert isinstance(label, str) + assert label not in self.arcs + assert isinstance(next, DFAState) + self.arcs[label] = next + + def unifystate(self, old, new): + for label, next in self.arcs.items(): + if next is old: + self.arcs[label] = new + + def __eq__(self, other): + # Equality test -- ignore the nfaset instance variable + assert isinstance(other, DFAState) + if self.isfinal != other.isfinal: + return False + # Can't just return self.arcs == other.arcs, because that + # would invoke this method recursively, with cycles... + if len(self.arcs) != len(other.arcs): + return False + for label, next in self.arcs.items(): + if next is not other.arcs.get(label): + return False + return True + + __hash__ = None # For Py3 compatibility. + + +def generate_grammar(filename_or_stream='Grammar.txt'): + # type:(str | StringIO) -> PgenGrammar + if isinstance(filename_or_stream, str): + p = ParserGenerator(filename_or_stream) + elif isinstance(filename_or_stream, StringIO): + p = ParserGenerator(stream=filename_or_stream) + else: + raise NotImplementedError('Type %s not implemented' % + type(filename_or_stream)) + return p.make_grammar() diff --git a/third_party/yapf_third_party/_ylib2to3/pgen2/token.py b/third_party/yapf_third_party/_ylib2to3/pgen2/token.py new file mode 100644 index 000000000..5d099707e --- /dev/null +++ b/third_party/yapf_third_party/_ylib2to3/pgen2/token.py @@ -0,0 +1,87 @@ +#! /usr/bin/env python3 +"""Token constants (from "token.h").""" + +# Taken from Python (r53757) and modified to include some tokens +# originally monkeypatched in by pgen2.tokenize + +# --start constants-- +ENDMARKER = 0 +NAME = 1 +NUMBER = 2 +STRING = 3 +NEWLINE = 4 +INDENT = 5 +DEDENT = 6 +LPAR = 7 +RPAR = 8 +LSQB = 9 +RSQB = 10 +COLON = 11 +COMMA = 12 +SEMI = 13 +PLUS = 14 +MINUS = 15 +STAR = 16 +SLASH = 17 +VBAR = 18 +AMPER = 19 +LESS = 20 +GREATER = 21 +EQUAL = 22 +DOT = 23 +PERCENT = 24 +BACKQUOTE = 25 +LBRACE = 26 +RBRACE = 27 +EQEQUAL = 28 +NOTEQUAL = 29 +LESSEQUAL = 30 +GREATEREQUAL = 31 +TILDE = 32 +CIRCUMFLEX = 33 +LEFTSHIFT = 34 +RIGHTSHIFT = 35 +DOUBLESTAR = 36 +PLUSEQUAL = 37 +MINEQUAL = 38 +STAREQUAL = 39 +SLASHEQUAL = 40 +PERCENTEQUAL = 41 +AMPEREQUAL = 42 +VBAREQUAL = 43 +CIRCUMFLEXEQUAL = 44 +LEFTSHIFTEQUAL = 45 +RIGHTSHIFTEQUAL = 46 +DOUBLESTAREQUAL = 47 +DOUBLESLASH = 48 +DOUBLESLASHEQUAL = 49 +AT = 50 +ATEQUAL = 51 +OP = 52 +COMMENT = 53 +NL = 54 +RARROW = 55 +AWAIT = 56 +ASYNC = 57 +ERRORTOKEN = 58 +COLONEQUAL = 59 +N_TOKENS = 60 +NT_OFFSET = 256 +# --end constants-- + +tok_name = {} +for _name, _value in list(globals().items()): + if isinstance(_value, int): + tok_name[_value] = _name + + +def ISTERMINAL(x): + return x < NT_OFFSET + + +def ISNONTERMINAL(x): + return x >= NT_OFFSET + + +def ISEOF(x): + return x == ENDMARKER diff --git a/third_party/yapf_third_party/_ylib2to3/pgen2/tokenize.py b/third_party/yapf_third_party/_ylib2to3/pgen2/tokenize.py new file mode 100644 index 000000000..dda83296f --- /dev/null +++ b/third_party/yapf_third_party/_ylib2to3/pgen2/tokenize.py @@ -0,0 +1,611 @@ +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Python Software Foundation. +# All rights reserved. +"""Tokenization help for Python programs. + +generate_tokens(readline) is a generator that breaks a stream of +text into Python tokens. It accepts a readline-like method which is called +repeatedly to get the next line of input (or "" for EOF). It generates +5-tuples with these members: + + the token type (see token.py) + the token (a string) + the starting (row, column) indices of the token (a 2-tuple of ints) + the ending (row, column) indices of the token (a 2-tuple of ints) + the original line (string) + +It is designed to match the working of the Python tokenizer exactly, except +that it produces COMMENT tokens for comments and gives type OP for all +operators + +Older entry points + tokenize_loop(readline, tokeneater) + tokenize(readline, tokeneater=printtoken) +are the same, except instead of generating tokens, tokeneater is a callback +function to which the 5 fields described above are passed as 5 arguments, +each time a new token is found.""" + +__author__ = 'Ka-Ping Yee ' +__credits__ = \ + 'GvR, ESR, Tim Peters, Thomas Wouters, Fred Drake, Skip Montanaro' + +import re +import string +from codecs import BOM_UTF8 +from codecs import lookup + +from . import token +from .token import ASYNC +from .token import AWAIT +from .token import COMMENT +from .token import DEDENT +from .token import ENDMARKER +from .token import ERRORTOKEN +from .token import INDENT +from .token import NAME +from .token import NEWLINE +from .token import NL +from .token import NUMBER +from .token import OP +from .token import STRING +from .token import tok_name + +__all__ = [x for x in dir(token) if x[0] != '_' + ] + ['tokenize', 'generate_tokens', 'untokenize'] +del token + +try: + bytes +except NameError: + # Support bytes type in Python <= 2.5, so 2to3 turns itself into + # valid Python 3 code. + bytes = str + + +def group(*choices): + return '(' + '|'.join(choices) + ')' + + +def any(*choices): + return group(*choices) + '*' + + +def maybe(*choices): + return group(*choices) + '?' + + +def _combinations(*l): # noqa: E741 + return set( + x + y for x in l for y in l + ('',) if x.casefold() != y.casefold()) + + +Whitespace = r'[ \f\t]*' +Comment = r'#[^\r\n]*' +Ignore = Whitespace + any(r'\\\r?\n' + Whitespace) + maybe(Comment) +Name = r'\w+' + +Binnumber = r'0[bB]_?[01]+(?:_[01]+)*' +Hexnumber = r'0[xX]_?[\da-fA-F]+(?:_[\da-fA-F]+)*[lL]?' +Octnumber = r'0[oO]?_?[0-7]+(?:_[0-7]+)*[lL]?' +Decnumber = group(r'[1-9]\d*(?:_\d+)*[lL]?', '0[lL]?') +Intnumber = group(Binnumber, Hexnumber, Octnumber, Decnumber) +Exponent = r'[eE][-+]?\d+(?:_\d+)*' +Pointfloat = group(r'\d+(?:_\d+)*\.(?:\d+(?:_\d+)*)?', + r'\.\d+(?:_\d+)*') + maybe(Exponent) +Expfloat = r'\d+(?:_\d+)*' + Exponent +Floatnumber = group(Pointfloat, Expfloat) +Imagnumber = group(r'\d+(?:_\d+)*[jJ]', Floatnumber + r'[jJ]') +Number = group(Imagnumber, Floatnumber, Intnumber) + +# Tail end of ' string. +Single = r"[^'\\]*(?:\\.[^'\\]*)*'" +# Tail end of " string. +Double = r'[^"\\]*(?:\\.[^"\\]*)*"' +# Tail end of ''' string. +Single3 = r"[^'\\]*(?:(?:\\.|'(?!''))[^'\\]*)*'''" +# Tail end of """ string. +Double3 = r'[^"\\]*(?:(?:\\.|"(?!""))[^"\\]*)*"""' +_litprefix = r'(?:[uUrRbBfF]|[rR][fFbB]|[fFbBuU][rR])?' +Triple = group(_litprefix + "'''", _litprefix + '"""') +# Single-line ' or " string. +String = group(_litprefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*'", + _litprefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*"') + +# Because of leftmost-then-longest match semantics, be sure to put the +# longest operators first (e.g., if = came before ==, == would get +# recognized as two instances of =). +Operator = group(r'\*\*=?', r'>>=?', r'<<=?', r'<>', r'!=', r'//=?', r'->', + r'[+\-*/%&@|^=<>]=?', r'~') + +Bracket = '[][(){}]' +Special = group(r'\r?\n', r':=', r'[:;.,`@]') +Funny = group(Operator, Bracket, Special) + +PlainToken = group(Number, Funny, String, Name) +Token = Ignore + PlainToken + +# First (or only) line of ' or " string. +ContStr = group( + _litprefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*" + group("'", r'\\\r?\n'), + _litprefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*' + group('"', r'\\\r?\n')) +PseudoExtras = group(r'\\\r?\n', Comment, Triple) +PseudoToken = Whitespace + group(PseudoExtras, Number, Funny, ContStr, Name) + +tokenprog, pseudoprog, single3prog, double3prog = map( + re.compile, (Token, PseudoToken, Single3, Double3)) + +_strprefixes = ( + _combinations('r', 'R', 'f', 'F') | _combinations('r', 'R', 'b', 'B') + | {'u', 'U', 'ur', 'uR', 'Ur', 'UR'}) + +endprogs = { + "'": re.compile(Single), + '"': re.compile(Double), + "'''": single3prog, + '"""': double3prog, + **{ + f"{prefix}'''": single3prog for prefix in _strprefixes + }, + **{ + f'{prefix}"""': double3prog for prefix in _strprefixes + }, + **{ + prefix: None for prefix in _strprefixes + } +} + +triple_quoted = ({"'''", '"""'} | {f"{prefix}'''" for prefix in _strprefixes} + | {f'{prefix}"""' for prefix in _strprefixes}) +single_quoted = ({"'", '"'} | {f"{prefix}'" for prefix in _strprefixes} + | {f'{prefix}"' for prefix in _strprefixes}) + +tabsize = 8 + + +class TokenError(Exception): + pass + + +class StopTokenizing(Exception): + pass + + +def printtoken(type, token, xxx_todo_changeme, xxx_todo_changeme1, + line): # for testing + (srow, scol) = xxx_todo_changeme + (erow, ecol) = xxx_todo_changeme1 + print('%d,%d-%d,%d:\t%s\t%s' % + (srow, scol, erow, ecol, tok_name[type], repr(token))) + + +def tokenize(readline, tokeneater=printtoken): + """ + The tokenize() function accepts two parameters: one representing the + input stream, and one providing an output mechanism for tokenize(). + + The first parameter, readline, must be a callable object which provides + the same interface as the readline() method of built-in file objects. + Each call to the function should return one line of input as a string. + + The second parameter, tokeneater, must also be a callable object. It is + called once for each token, with five arguments, corresponding to the + tuples generated by generate_tokens(). + """ + try: + tokenize_loop(readline, tokeneater) + except StopTokenizing: + pass + + +# backwards compatible interface +def tokenize_loop(readline, tokeneater): + for token_info in generate_tokens(readline): + tokeneater(*token_info) + + +class Untokenizer: + + def __init__(self): + self.tokens = [] + self.prev_row = 1 + self.prev_col = 0 + + def add_whitespace(self, start): + row, col = start + assert row <= self.prev_row + col_offset = col - self.prev_col + if col_offset: + self.tokens.append(' ' * col_offset) + + def untokenize(self, iterable): + for t in iterable: + if len(t) == 2: + self.compat(t, iterable) + break + tok_type, token, start, end, line = t + self.add_whitespace(start) + self.tokens.append(token) + self.prev_row, self.prev_col = end + if tok_type in (NEWLINE, NL): + self.prev_row += 1 + self.prev_col = 0 + return ''.join(self.tokens) + + def compat(self, token, iterable): + startline = False + indents = [] + toks_append = self.tokens.append + toknum, tokval = token + if toknum in (NAME, NUMBER): + tokval += ' ' + if toknum in (NEWLINE, NL): + startline = True + for tok in iterable: + toknum, tokval = tok[:2] + + if toknum in (NAME, NUMBER, ASYNC, AWAIT): + tokval += ' ' + + if toknum == INDENT: + indents.append(tokval) + continue + elif toknum == DEDENT: + indents.pop() + continue + elif toknum in (NEWLINE, NL): + startline = True + elif startline and indents: + toks_append(indents[-1]) + startline = False + toks_append(tokval) + + +cookie_re = re.compile(r'^[ \t\f]*#.*?coding[:=][ \t]*([-\w.]+)', re.ASCII) +blank_re = re.compile(br'^[ \t\f]*(?:[#\r\n]|$)', re.ASCII) + + +def _get_normal_name(orig_enc): + """Imitates get_normal_name in tokenizer.c.""" + # Only care about the first 12 characters. + enc = orig_enc[:12].lower().replace('_', '-') + if enc == 'utf-8' or enc.startswith('utf-8-'): + return 'utf-8' + if enc in ('latin-1', 'iso-8859-1', 'iso-latin-1') or \ + enc.startswith(('latin-1-', 'iso-8859-1-', 'iso-latin-1-')): + return 'iso-8859-1' + return orig_enc + + +def detect_encoding(readline): + """ + The detect_encoding() function is used to detect the encoding that should + be used to decode a Python source file. It requires one argument, readline, + in the same way as the tokenize() generator. + + It will call readline a maximum of twice, and return the encoding used + (as a string) and a list of any lines (left as bytes) it has read + in. + + It detects the encoding from the presence of a utf-8 bom or an encoding + cookie as specified in pep-0263. If both a bom and a cookie are present, but + disagree, a SyntaxError will be raised. If the encoding cookie is an invalid + charset, raise a SyntaxError. Note that if a utf-8 bom is found, + 'utf-8-sig' is returned. + + If no encoding is specified, then the default of 'utf-8' will be returned. + """ + bom_found = False + encoding = None + default = 'utf-8' + + def read_or_stop(): + try: + return readline() + except StopIteration: + return bytes() + + def find_cookie(line): + try: + line_string = line.decode('ascii') + except UnicodeDecodeError: + return None + match = cookie_re.match(line_string) + if not match: + return None + encoding = _get_normal_name(match.group(1)) + try: + codec = lookup(encoding) + except LookupError: + # This behaviour mimics the Python interpreter + raise SyntaxError('unknown encoding: ' + encoding) + + if bom_found: + if codec.name != 'utf-8': + # This behaviour mimics the Python interpreter + raise SyntaxError('encoding problem: utf-8') + encoding += '-sig' + return encoding + + first = read_or_stop() + if first.startswith(BOM_UTF8): + bom_found = True + first = first[3:] + default = 'utf-8-sig' + if not first: + return default, [] + + encoding = find_cookie(first) + if encoding: + return encoding, [first] + if not blank_re.match(first): + return default, [first] + + second = read_or_stop() + if not second: + return default, [first] + + encoding = find_cookie(second) + if encoding: + return encoding, [first, second] + + return default, [first, second] + + +def untokenize(iterable): + """Transform tokens back into Python source code. + + Each element returned by the iterable must be a token sequence + with at least two elements, a token number and token value. If + only two tokens are passed, the resulting output is poor. + + Round-trip invariant for full input: + Untokenized source will match input source exactly + + Round-trip invariant for limited input: + # Output text will tokenize the back to the input + t1 = [tok[:2] for tok in generate_tokens(f.readline)] + newcode = untokenize(t1) + readline = iter(newcode.splitlines(1)).next + t2 = [tok[:2] for tokin generate_tokens(readline)] + assert t1 == t2 + """ + ut = Untokenizer() + return ut.untokenize(iterable) + + +def generate_tokens(readline): + """ + The generate_tokens() generator requires one argument, readline, which + must be a callable object which provides the same interface as the + readline() method of built-in file objects. Each call to the function + should return one line of input as a string. Alternately, readline + can be a callable function terminating with StopIteration: + readline = open(myfile).next # Example of alternate readline + + The generator produces 5-tuples with these members: the token type; the + token string; a 2-tuple (srow, scol) of ints specifying the row and + column where the token begins in the source; a 2-tuple (erow, ecol) of + ints specifying the row and column where the token ends in the source; + and the line on which the token was found. The line passed is the + physical line. + """ + strstart = '' + endprog = '' + lnum = parenlev = continued = 0 + contstr, needcont = '', 0 + contline = None + indents = [0] + + # 'stashed' and 'async_*' are used for async/await parsing + stashed = None + async_def = False + async_def_indent = 0 + async_def_nl = False + + while 1: # loop over lines in stream + try: + line = readline() + except StopIteration: + line = '' + lnum = lnum + 1 + pos, max = 0, len(line) + + if contstr: # continued string + if not line: + raise TokenError('EOF in multi-line string', strstart) + endmatch = endprog.match(line) + if endmatch: + pos = end = endmatch.end(0) + yield (STRING, contstr + line[:end], strstart, (lnum, end), + contline + line) + contstr, needcont = '', 0 + contline = None + elif needcont and line[-2:] != '\\\n' and line[-3:] != '\\\r\n': + yield (ERRORTOKEN, contstr + line, strstart, (lnum, len(line)), + contline) + contstr = '' + contline = None + continue + else: + contstr = contstr + line + contline = contline + line + continue + + elif parenlev == 0 and not continued: # new statement + if not line: + break + column = 0 + while pos < max: # measure leading whitespace + if line[pos] == ' ': + column = column + 1 + elif line[pos] == '\t': + column = (column // tabsize + 1) * tabsize + elif line[pos] == '\f': + column = 0 + else: + break + pos = pos + 1 + if pos == max: + break + + if stashed: + yield stashed + stashed = None + + if line[pos] in '#\r\n': # skip comments or blank lines + if line[pos] == '#': + comment_token = line[pos:].rstrip('\r\n') + nl_pos = pos + len(comment_token) + yield (COMMENT, comment_token, (lnum, pos), + (lnum, pos + len(comment_token)), line) + yield (NL, line[nl_pos:], (lnum, nl_pos), (lnum, len(line)), line) + else: + yield ((NL, COMMENT)[line[pos] == '#'], line[pos:], (lnum, pos), + (lnum, len(line)), line) + continue + + if column > indents[-1]: # count indents or dedents + indents.append(column) + yield (INDENT, line[:pos], (lnum, 0), (lnum, pos), line) + while column < indents[-1]: + if column not in indents: + raise IndentationError( + 'unindent does not match any outer indentation level', + ('', lnum, pos, line)) + indents = indents[:-1] + + if async_def and async_def_indent >= indents[-1]: + async_def = False + async_def_nl = False + async_def_indent = 0 + + yield (DEDENT, '', (lnum, pos), (lnum, pos), line) + + if async_def and async_def_nl and async_def_indent >= indents[-1]: + async_def = False + async_def_nl = False + async_def_indent = 0 + + else: # continued statement + if not line: + raise TokenError('EOF in multi-line statement', (lnum, 0)) + continued = 0 + + while pos < max: + pseudomatch = pseudoprog.match(line, pos) + if pseudomatch: # scan for tokens + start, end = pseudomatch.span(1) + spos, epos, pos = (lnum, start), (lnum, end), end + token, initial = line[start:end], line[start] + + if initial in string.digits or \ + (initial == '.' and token != '.'): # ordinary number + yield (NUMBER, token, spos, epos, line) + elif initial in '\r\n': + newline = NEWLINE + if parenlev > 0: + newline = NL + elif async_def: + async_def_nl = True + if stashed: + yield stashed + stashed = None + yield (newline, token, spos, epos, line) + + elif initial == '#': + assert not token.endswith('\n') + if stashed: + yield stashed + stashed = None + yield (COMMENT, token, spos, epos, line) + elif token in triple_quoted: + endprog = endprogs[token] + endmatch = endprog.match(line, pos) + if endmatch: # all on one line + pos = endmatch.end(0) + token = line[start:pos] + if stashed: + yield stashed + stashed = None + yield (STRING, token, spos, (lnum, pos), line) + else: + strstart = (lnum, start) # multiple lines + contstr = line[start:] + contline = line + break + elif initial in single_quoted or \ + token[:2] in single_quoted or \ + token[:3] in single_quoted: + if token[-1] == '\n': # continued string + strstart = (lnum, start) # noqa: F841 + endprog = ( + endprogs[initial] or endprogs[token[1]] or endprogs[token[2]]) + contstr, needcont = line[start:], 1 + contline = line + break + else: # ordinary string + if stashed: + yield stashed + stashed = None + yield (STRING, token, spos, epos, line) + elif initial.isidentifier(): # ordinary name + if token in ('async', 'await'): + if async_def: + yield (ASYNC if token == 'async' else AWAIT, token, spos, epos, + line) + continue + + tok = (NAME, token, spos, epos, line) + if token == 'async' and not stashed: + stashed = tok + continue + + if token in ('def', 'for'): + if (stashed and stashed[0] == NAME and stashed[1] == 'async'): + + if token == 'def': + async_def = True + async_def_indent = indents[-1] + + yield (ASYNC, stashed[1], stashed[2], stashed[3], stashed[4]) + stashed = None + + if stashed: + yield stashed + stashed = None + + yield tok + elif initial == '\\': # continued stmt + # This yield is new; needed for better idempotency: + if stashed: + yield stashed + stashed = None + yield (NL, token, spos, (lnum, pos), line) + continued = 1 + else: + if initial in '([{': + parenlev = parenlev + 1 + elif initial in ')]}': + parenlev = parenlev - 1 + if stashed: + yield stashed + stashed = None + yield (OP, token, spos, epos, line) + else: + yield (ERRORTOKEN, line[pos], (lnum, pos), (lnum, pos + 1), line) + pos = pos + 1 + + if stashed: + yield stashed + stashed = None + + for indent in indents[1:]: # pop remaining indent levels + yield (DEDENT, '', (lnum, 0), (lnum, 0), '') + yield (ENDMARKER, '', (lnum, 0), (lnum, 0), '') + + +if __name__ == '__main__': # testing + import sys + if len(sys.argv) > 1: + tokenize(open(sys.argv[1]).readline) + else: + tokenize(sys.stdin.readline) diff --git a/third_party/yapf_third_party/_ylib2to3/pygram.py b/third_party/yapf_third_party/_ylib2to3/pygram.py new file mode 100644 index 000000000..4267c3610 --- /dev/null +++ b/third_party/yapf_third_party/_ylib2to3/pygram.py @@ -0,0 +1,40 @@ +# Copyright 2006 Google, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. +"""Export the Python grammar and symbols.""" + +# Python imports +import os + +# Local imports +from .pgen2 import driver + +# The grammar file +_GRAMMAR_FILE = os.path.join(os.path.dirname(__file__), 'Grammar.txt') +_PATTERN_GRAMMAR_FILE = os.path.join( + os.path.dirname(__file__), 'PatternGrammar.txt') + + +class Symbols(object): + + def __init__(self, grammar): + """Initializer. + + Creates an attribute for each grammar symbol (nonterminal), + whose value is the symbol's type (an int >= 256). + """ + for name, symbol in grammar.symbol2number.items(): + setattr(self, name, symbol) + + +python_grammar = driver.load_grammar(_GRAMMAR_FILE) + +python_symbols = Symbols(python_grammar) + +python_grammar_no_print_statement = python_grammar.copy() +del python_grammar_no_print_statement.keywords['print'] + +python_grammar_no_print_and_exec_statement = python_grammar_no_print_statement.copy() # yapf: disable # noqa: E501 +del python_grammar_no_print_and_exec_statement.keywords['exec'] + +pattern_grammar = driver.load_grammar(_PATTERN_GRAMMAR_FILE) +pattern_symbols = Symbols(pattern_grammar) diff --git a/third_party/yapf_third_party/_ylib2to3/pytree.py b/third_party/yapf_third_party/_ylib2to3/pytree.py new file mode 100644 index 000000000..0fcdf4b2c --- /dev/null +++ b/third_party/yapf_third_party/_ylib2to3/pytree.py @@ -0,0 +1,861 @@ +# Copyright 2006 Google, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. +""" +Python parse tree definitions. + +This is a very concrete parse tree; we need to keep every token and +even the comments and whitespace between tokens. + +There's also a pattern matching implementation here. +""" + +__author__ = 'Guido van Rossum ' + +import sys +from io import StringIO +from typing import List +from typing import Optional +from typing import Text +from typing import Tuple +from typing import Union + +HUGE = 0x7FFFFFFF # maximum repeat count, default max + +_type_reprs = {} + + +def type_repr(type_num): + global _type_reprs + if not _type_reprs: + from .pygram import python_symbols + + # printing tokens is possible but not as useful + # from .pgen2 import token // token.__dict__.items(): + for name, val in python_symbols.__dict__.items(): + if type(val) == int: + _type_reprs[val] = name + return _type_reprs.setdefault(type_num, type_num) + + +NL = Union['Node', 'Leaf'] +Context = Tuple[Text, Tuple[int, int]] +RawNode = Tuple[int, Optional[Text], Optional[Context], Optional[List[NL]]] + + +class Base(object): + """ + Abstract base class for Node and Leaf. + + This provides some default functionality and boilerplate using the + template pattern. + + A node may be a subnode of at most one parent. + """ + + # Default values for instance variables + type = None # int: token number (< 256) or symbol number (>= 256) + parent = None # Parent node pointer, or None + children = () # Tuple of subnodes + was_changed = False + was_checked = False + + def __new__(cls, *args, **kwds): + """Constructor that prevents Base from being instantiated.""" + assert cls is not Base, 'Cannot instantiate Base' + return object.__new__(cls) + + def __eq__(self, other): + """ + Compare two nodes for equality. + + This calls the method _eq(). + """ + if self.__class__ is not other.__class__: + return NotImplemented + return self._eq(other) + + __hash__ = None # For Py3 compatibility. + + def _eq(self, other): + """ + Compare two nodes for equality. + + This is called by __eq__ and __ne__. It is only called if the two nodes + have the same type. This must be implemented by the concrete subclass. + Nodes should be considered equal if they have the same structure, + ignoring the prefix string and other context information. + """ + raise NotImplementedError + + def clone(self): + """ + Return a cloned (deep) copy of self. + + This must be implemented by the concrete subclass. + """ + raise NotImplementedError + + def post_order(self): + """ + Return a post-order iterator for the tree. + + This must be implemented by the concrete subclass. + """ + raise NotImplementedError + + def pre_order(self): + """ + Return a pre-order iterator for the tree. + + This must be implemented by the concrete subclass. + """ + raise NotImplementedError + + def replace(self, new): + """Replace this node with a new one in the parent.""" + assert self.parent is not None, str(self) + assert new is not None + if not isinstance(new, list): + new = [new] + l_children = [] + found = False + for ch in self.parent.children: + if ch is self: + assert not found, (self.parent.children, self, new) + if new is not None: + l_children.extend(new) + found = True + else: + l_children.append(ch) + assert found, (self.children, self, new) + self.parent.changed() + self.parent.children = l_children + for x in new: + x.parent = self.parent + self.parent = None + + def get_lineno(self): + """Return the line number which generated the invocant node.""" + node = self + while not isinstance(node, Leaf): + if not node.children: + return + node = node.children[0] + return node.lineno + + def changed(self): + if self.parent: + self.parent.changed() + self.was_changed = True + + def remove(self): + """ + Remove the node from the tree. Returns the position of the node in its + parent's children before it was removed. + """ + if self.parent: + for i, node in enumerate(self.parent.children): + if node is self: + self.parent.changed() + del self.parent.children[i] + self.parent = None + return i + + @property + def next_sibling(self): + """ + The node immediately following the invocant in their parent's children + list. If the invocant does not have a next sibling, it is None + """ + if self.parent is None: + return None + + # Can't use index(); we need to test by identity + for i, child in enumerate(self.parent.children): + if child is self: + try: + return self.parent.children[i + 1] + except IndexError: + return None + + @property + def prev_sibling(self): + """ + The node immediately preceding the invocant in their parent's children + list. If the invocant does not have a previous sibling, it is None. + """ + if self.parent is None: + return None + + # Can't use index(); we need to test by identity + for i, child in enumerate(self.parent.children): + if child is self: + if i == 0: + return None + return self.parent.children[i - 1] + + def leaves(self): + for child in self.children: + yield from child.leaves() + + def depth(self): + if self.parent is None: + return 0 + return 1 + self.parent.depth() + + def get_suffix(self): + """ + Return the string immediately following the invocant node. This is + effectively equivalent to node.next_sibling.prefix + """ + next_sib = self.next_sibling + if next_sib is None: + return '' + return next_sib.prefix + + if sys.version_info < (3, 0): + + def __str__(self): + return str(self).encode('ascii') + + +class Node(Base): + """Concrete implementation for interior nodes.""" + + def __init__(self, + type, + children, + context=None, + prefix=None, + fixers_applied=None): + """ + Initializer. + + Takes a type constant (a symbol number >= 256), a sequence of + child nodes, and an optional context keyword argument. + + As a side effect, the parent pointers of the children are updated. + """ + assert type >= 256, type + self.type = type + self.children = list(children) + for ch in self.children: + assert ch.parent is None, repr(ch) + ch.parent = self + if prefix is not None: + self.prefix = prefix + if fixers_applied: + self.fixers_applied = fixers_applied[:] + else: + self.fixers_applied = None + + def __repr__(self): + """Return a canonical string representation.""" + return '%s(%s, %r)' % (self.__class__.__name__, type_repr( + self.type), self.children) + + def __unicode__(self): + """ + Return a pretty string representation. + + This reproduces the input source exactly. + """ + return ''.join(map(str, self.children)) + + if sys.version_info > (3, 0): + __str__ = __unicode__ + + def _eq(self, other): + """Compare two nodes for equality.""" + return (self.type, self.children) == (other.type, other.children) + + def clone(self): + """Return a cloned (deep) copy of self.""" + return Node( + self.type, [ch.clone() for ch in self.children], + fixers_applied=self.fixers_applied) + + def post_order(self): + """Return a post-order iterator for the tree.""" + for child in self.children: + yield from child.post_order() + yield self + + def pre_order(self): + """Return a pre-order iterator for the tree.""" + yield self + for child in self.children: + yield from child.pre_order() + + @property + def prefix(self): + """ + The whitespace and comments preceding this node in the input. + """ + if not self.children: + return '' + return self.children[0].prefix + + @prefix.setter + def prefix(self, prefix): + if self.children: + self.children[0].prefix = prefix + + def set_child(self, i, child): + """ + Equivalent to 'node.children[i] = child'. This method also sets the + child's parent attribute appropriately. + """ + child.parent = self + self.children[i].parent = None + self.children[i] = child + self.changed() + + def insert_child(self, i, child): + """ + Equivalent to 'node.children.insert(i, child)'. This method also sets + the child's parent attribute appropriately. + """ + child.parent = self + self.children.insert(i, child) + self.changed() + + def append_child(self, child): + """ + Equivalent to 'node.children.append(child)'. This method also sets the + child's parent attribute appropriately. + """ + child.parent = self + self.children.append(child) + self.changed() + + +class Leaf(Base): + """Concrete implementation for leaf nodes.""" + + # Default values for instance variables + _prefix = '' # Whitespace and comments preceding this token in the input + lineno = 0 # Line where this token starts in the input + column = 0 # Column where this token tarts in the input + + def __init__(self, type, value, context=None, prefix=None, fixers_applied=[]): + """ + Initializer. + + Takes a type constant (a token number < 256), a string value, and an + optional context keyword argument. + """ + assert 0 <= type < 256, type + if context is not None: + self._prefix, (self.lineno, self.column) = context + self.type = type + self.value = value + if prefix is not None: + self._prefix = prefix + self.fixers_applied = fixers_applied[:] + + def __repr__(self): + """Return a canonical string representation.""" + return '%s(%r, %r)' % (self.__class__.__name__, self.type, self.value) + + def __unicode__(self): + """ + Return a pretty string representation. + + This reproduces the input source exactly. + """ + return self.prefix + str(self.value) + + if sys.version_info > (3, 0): + __str__ = __unicode__ + + def _eq(self, other): + """Compare two nodes for equality.""" + return (self.type, self.value) == (other.type, other.value) + + def clone(self): + """Return a cloned (deep) copy of self.""" + return Leaf( + self.type, + self.value, (self.prefix, (self.lineno, self.column)), + fixers_applied=self.fixers_applied) + + def leaves(self): + yield self + + def post_order(self): + """Return a post-order iterator for the tree.""" + yield self + + def pre_order(self): + """Return a pre-order iterator for the tree.""" + yield self + + @property + def prefix(self): + """ + The whitespace and comments preceding this token in the input. + """ + return self._prefix + + @prefix.setter + def prefix(self, prefix): + self.changed() + self._prefix = prefix + + +def convert(gr, raw_node): + """ + Convert raw node information to a Node or Leaf instance. + + This is passed to the parser driver which calls it whenever a reduction of a + grammar rule produces a new complete node, so that the tree is build + strictly bottom-up. + """ + type, value, context, children = raw_node + if children or type in gr.number2symbol: + # If there's exactly one child, return that child instead of + # creating a new node. + if len(children) == 1: + return children[0] + return Node(type, children, context=context) + else: + return Leaf(type, value, context=context) + + +class BasePattern(object): + """ + A pattern is a tree matching pattern. + + It looks for a specific node type (token or symbol), and + optionally for a specific content. + + This is an abstract base class. There are three concrete + subclasses: + + - LeafPattern matches a single leaf node; + - NodePattern matches a single node (usually non-leaf); + - WildcardPattern matches a sequence of nodes of variable length. + """ + + # Defaults for instance variables + type = None # Node type (token if < 256, symbol if >= 256) + content = None # Optional content matching pattern + name = None # Optional name used to store match in results dict + + def __new__(cls, *args, **kwds): + """Constructor that prevents BasePattern from being instantiated.""" + assert cls is not BasePattern, 'Cannot instantiate BasePattern' + return object.__new__(cls) + + def __repr__(self): + args = [type_repr(self.type), self.content, self.name] + while args and args[-1] is None: + del args[-1] + return '%s(%s)' % (self.__class__.__name__, ', '.join(map(repr, args))) + + def optimize(self): + """ + A subclass can define this as a hook for optimizations. + + Returns either self or another node with the same effect. + """ + return self + + def match(self, node, results=None): + """ + Does this pattern exactly match a node? + + Returns True if it matches, False if not. + + If results is not None, it must be a dict which will be + updated with the nodes matching named subpatterns. + + Default implementation for non-wildcard patterns. + """ + if self.type is not None and node.type != self.type: + return False + if self.content is not None: + r = None + if results is not None: + r = {} + if not self._submatch(node, r): + return False + if r: + results.update(r) + if results is not None and self.name: + results[self.name] = node + return True + + def match_seq(self, nodes, results=None): + """ + Does this pattern exactly match a sequence of nodes? + + Default implementation for non-wildcard patterns. + """ + if len(nodes) != 1: + return False + return self.match(nodes[0], results) + + def generate_matches(self, nodes): + """ + Generator yielding all matches for this pattern. + + Default implementation for non-wildcard patterns. + """ + r = {} + if nodes and self.match(nodes[0], r): + yield 1, r + + +class LeafPattern(BasePattern): + + def __init__(self, type=None, content=None, name=None): + """ + Initializer. Takes optional type, content, and name. + + The type, if given must be a token type (< 256). If not given, + this matches any *leaf* node; the content may still be required. + + The content, if given, must be a string. + + If a name is given, the matching node is stored in the results + dict under that key. + """ + if type is not None: + assert 0 <= type < 256, type + if content is not None: + assert isinstance(content, str), repr(content) + self.type = type + self.content = content + self.name = name + + def match(self, node, results=None): + """Override match() to insist on a leaf node.""" + if not isinstance(node, Leaf): + return False + return BasePattern.match(self, node, results) + + def _submatch(self, node, results=None): + """ + Match the pattern's content to the node's children. + + This assumes the node type matches and self.content is not None. + + Returns True if it matches, False if not. + + If results is not None, it must be a dict which will be + updated with the nodes matching named subpatterns. + + When returning False, the results dict may still be updated. + """ + return self.content == node.value + + +class NodePattern(BasePattern): + + wildcards = False + + def __init__(self, type=None, content=None, name=None): + """ + Initializer. Takes optional type, content, and name. + + The type, if given, must be a symbol type (>= 256). If the + type is None this matches *any* single node (leaf or not), + except if content is not None, in which it only matches + non-leaf nodes that also match the content pattern. + + The content, if not None, must be a sequence of Patterns that + must match the node's children exactly. If the content is + given, the type must not be None. + + If a name is given, the matching node is stored in the results + dict under that key. + """ + if type is not None: + assert type >= 256, type + if content is not None: + assert not isinstance(content, str), repr(content) + content = list(content) + for i, item in enumerate(content): + assert isinstance(item, BasePattern), (i, item) + if isinstance(item, WildcardPattern): + self.wildcards = True + self.type = type + self.content = content + self.name = name + + def _submatch(self, node, results=None): + """ + Match the pattern's content to the node's children. + + This assumes the node type matches and self.content is not None. + + Returns True if it matches, False if not. + + If results is not None, it must be a dict which will be + updated with the nodes matching named subpatterns. + + When returning False, the results dict may still be updated. + """ + if self.wildcards: + for c, r in generate_matches(self.content, node.children): + if c == len(node.children): + if results is not None: + results.update(r) + return True + return False + if len(self.content) != len(node.children): + return False + for subpattern, child in zip(self.content, node.children): + if not subpattern.match(child, results): + return False + return True + + +class WildcardPattern(BasePattern): + """ + A wildcard pattern can match zero or more nodes. + + This has all the flexibility needed to implement patterns like: + + .* .+ .? .{m,n} + (a b c | d e | f) + (...)* (...)+ (...)? (...){m,n} + + except it always uses non-greedy matching. + """ + + def __init__(self, content=None, min=0, max=HUGE, name=None): + """ + Initializer. + + Args: + content: optional sequence of subsequences of patterns; + if absent, matches one node; + if present, each subsequence is an alternative [*] + min: optional minimum number of times to match, default 0 + max: optional maximum number of times to match, default HUGE + name: optional name assigned to this match + + [*] Thus, if content is [[a, b, c], [d, e], [f, g, h]] this is + equivalent to (a b c | d e | f g h); if content is None, + this is equivalent to '.' in regular expression terms. + The min and max parameters work as follows: + min=0, max=maxint: .* + min=1, max=maxint: .+ + min=0, max=1: .? + min=1, max=1: . + If content is not None, replace the dot with the parenthesized + list of alternatives, e.g. (a b c | d e | f g h)* + """ + assert 0 <= min <= max <= HUGE, (min, max) + if content is not None: + content = tuple(map(tuple, content)) # Protect against alterations + # Check sanity of alternatives + assert len(content), repr(content) # Can't have zero alternatives + for alt in content: + assert len(alt), repr(alt) # Can have empty alternatives + self.content = content + self.min = min + self.max = max + self.name = name + + def optimize(self): + """Optimize certain stacked wildcard patterns.""" + subpattern = None + if (self.content is not None and len(self.content) == 1 and + len(self.content[0]) == 1): + subpattern = self.content[0][0] + if self.min == 1 and self.max == 1: + if self.content is None: + return NodePattern(name=self.name) + if subpattern is not None and self.name == subpattern.name: + return subpattern.optimize() + if (self.min <= 1 and isinstance(subpattern, WildcardPattern) and + subpattern.min <= 1 and self.name == subpattern.name): + return WildcardPattern(subpattern.content, self.min * subpattern.min, + self.max * subpattern.max, subpattern.name) + return self + + def match(self, node, results=None): + """Does this pattern exactly match a node?""" + return self.match_seq([node], results) + + def match_seq(self, nodes, results=None): + """Does this pattern exactly match a sequence of nodes?""" + for c, r in self.generate_matches(nodes): + if c == len(nodes): + if results is not None: + results.update(r) + if self.name: + results[self.name] = list(nodes) + return True + return False + + def generate_matches(self, nodes): + """ + Generator yielding matches for a sequence of nodes. + + Args: + nodes: sequence of nodes + + Yields: + (count, results) tuples where: + count: the match comprises nodes[:count]; + results: dict containing named submatches. + """ + if self.content is None: + # Shortcut for special case (see __init__.__doc__) + for count in range(self.min, 1 + min(len(nodes), self.max)): + r = {} + if self.name: + r[self.name] = nodes[:count] + yield count, r + elif self.name == 'bare_name': + yield self._bare_name_matches(nodes) + else: + # The reason for this is that hitting the recursion limit usually + # results in some ugly messages about how RuntimeErrors are being + # ignored. We only have to do this on CPython, though, because other + # implementations don't have this nasty bug in the first place. + if hasattr(sys, 'getrefcount'): + save_stderr = sys.stderr + sys.stderr = StringIO() + try: + for count, r in self._recursive_matches(nodes, 0): + if self.name: + r[self.name] = nodes[:count] + yield count, r + except RuntimeError: + # We fall back to the iterative pattern matching scheme if the recursive + # scheme hits the recursion limit. + for count, r in self._iterative_matches(nodes): + if self.name: + r[self.name] = nodes[:count] + yield count, r + finally: + if hasattr(sys, 'getrefcount'): + sys.stderr = save_stderr + + def _iterative_matches(self, nodes): + """Helper to iteratively yield the matches.""" + nodelen = len(nodes) + if 0 >= self.min: + yield 0, {} + + results = [] + # generate matches that use just one alt from self.content + for alt in self.content: + for c, r in generate_matches(alt, nodes): + yield c, r + results.append((c, r)) + + # for each match, iterate down the nodes + while results: + new_results = [] + for c0, r0 in results: + # stop if the entire set of nodes has been matched + if c0 < nodelen and c0 <= self.max: + for alt in self.content: + for c1, r1 in generate_matches(alt, nodes[c0:]): + if c1 > 0: + r = {} + r.update(r0) + r.update(r1) + yield c0 + c1, r + new_results.append((c0 + c1, r)) + results = new_results + + def _bare_name_matches(self, nodes): + """Special optimized matcher for bare_name.""" + count = 0 + r = {} + done = False + max = len(nodes) + while not done and count < max: + done = True + for leaf in self.content: + if leaf[0].match(nodes[count], r): + count += 1 + done = False + break + r[self.name] = nodes[:count] + return count, r + + def _recursive_matches(self, nodes, count): + """Helper to recursively yield the matches.""" + assert self.content is not None + if count >= self.min: + yield 0, {} + if count < self.max: + for alt in self.content: + for c0, r0 in generate_matches(alt, nodes): + for c1, r1 in self._recursive_matches(nodes[c0:], count + 1): + r = {} + r.update(r0) + r.update(r1) + yield c0 + c1, r + + +class NegatedPattern(BasePattern): + + def __init__(self, content=None): + """ + Initializer. + + The argument is either a pattern or None. If it is None, this + only matches an empty sequence (effectively '$' in regex + lingo). If it is not None, this matches whenever the argument + pattern doesn't have any matches. + """ + if content is not None: + assert isinstance(content, BasePattern), repr(content) + self.content = content + + def match(self, node): + # We never match a node in its entirety + return False + + def match_seq(self, nodes): + # We only match an empty sequence of nodes in its entirety + return len(nodes) == 0 + + def generate_matches(self, nodes): + if self.content is None: + # Return a match if there is an empty sequence + if len(nodes) == 0: + yield 0, {} + else: + # Return a match if the argument pattern has no matches + for c, r in self.content.generate_matches(nodes): + return + yield 0, {} + + +def generate_matches(patterns, nodes): + """ + Generator yielding matches for a sequence of patterns and nodes. + + Args: + patterns: a sequence of patterns + nodes: a sequence of nodes + + Yields: + (count, results) tuples where: + count: the entire sequence of patterns matches nodes[:count]; + results: dict containing named submatches. + """ + if not patterns: + yield 0, {} + else: + p, rest = patterns[0], patterns[1:] + for c0, r0 in p.generate_matches(nodes): + if not rest: + yield c0, r0 + else: + for c1, r1 in generate_matches(rest, nodes[c0:]): + r = {} + r.update(r0) + r.update(r1) + yield c0 + c1, r diff --git a/third_party/yapf_diff/LICENSE b/third_party/yapf_third_party/yapf_diff/LICENSE similarity index 100% rename from third_party/yapf_diff/LICENSE rename to third_party/yapf_third_party/yapf_diff/LICENSE diff --git a/third_party/yapf_third_party/yapf_diff/__init__.py b/third_party/yapf_third_party/yapf_diff/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/third_party/yapf_diff/yapf_diff.py b/third_party/yapf_third_party/yapf_diff/yapf_diff.py similarity index 100% rename from third_party/yapf_diff/yapf_diff.py rename to third_party/yapf_third_party/yapf_diff/yapf_diff.py diff --git a/yapf/__init__.py b/yapf/__init__.py index ce183e9d0..7ef89a93f 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -33,12 +33,14 @@ import os import sys +from importlib_metadata import metadata + from yapf.yapflib import errors from yapf.yapflib import file_resources from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = '0.33.0' +__version__ = metadata('yapf')['Version'] def _raw_input(): diff --git a/yapf/pytree/blank_line_calculator.py b/yapf/pytree/blank_line_calculator.py index 7bccb0978..32faaa2f4 100644 --- a/yapf/pytree/blank_line_calculator.py +++ b/yapf/pytree/blank_line_calculator.py @@ -22,7 +22,7 @@ newlines: The number of newlines required before the node. """ -from lib2to3.pgen2 import token as grammar_token +from yapf_third_party._ylib2to3.pgen2 import token as grammar_token from yapf.pytree import pytree_utils from yapf.pytree import pytree_visitor diff --git a/yapf/pytree/comment_splicer.py b/yapf/pytree/comment_splicer.py index ae5ffe66f..a9180f37c 100644 --- a/yapf/pytree/comment_splicer.py +++ b/yapf/pytree/comment_splicer.py @@ -21,9 +21,9 @@ SpliceComments(): the main function exported by this module. """ -from lib2to3 import pygram -from lib2to3 import pytree -from lib2to3.pgen2 import token +from yapf_third_party._ylib2to3 import pygram +from yapf_third_party._ylib2to3 import pytree +from yapf_third_party._ylib2to3.pgen2 import token from yapf.pytree import pytree_utils diff --git a/yapf/pytree/continuation_splicer.py b/yapf/pytree/continuation_splicer.py index b86188cb5..a8aef6606 100644 --- a/yapf/pytree/continuation_splicer.py +++ b/yapf/pytree/continuation_splicer.py @@ -19,7 +19,7 @@ SpliceContinuations(): the main function exported by this module. """ -from lib2to3 import pytree +from yapf_third_party._ylib2to3 import pytree from yapf.yapflib import format_token diff --git a/yapf/pytree/pytree_unwrapper.py b/yapf/pytree/pytree_unwrapper.py index ba1e0c423..4b84cd54c 100644 --- a/yapf/pytree/pytree_unwrapper.py +++ b/yapf/pytree/pytree_unwrapper.py @@ -28,8 +28,8 @@ # The word "token" is overloaded within this module, so for clarity rename # the imported pgen2.token module. -from lib2to3 import pytree -from lib2to3.pgen2 import token as grammar_token +from yapf_third_party._ylib2to3 import pytree +from yapf_third_party._ylib2to3.pgen2 import token as grammar_token from yapf.pytree import pytree_utils from yapf.pytree import pytree_visitor @@ -125,6 +125,8 @@ def _StartNewLine(self): 'try_stmt', 'expect_clause', 'with_stmt', + 'match_stmt', + 'case_block', 'funcdef', 'classdef', }) @@ -144,11 +146,13 @@ def Visit_simple_stmt(self, node): single_stmt_suite = ( node.parent and pytree_utils.NodeName(node.parent) in self._STMT_TYPES) is_comment_stmt = pytree_utils.IsCommentStatement(node) - if single_stmt_suite and not is_comment_stmt: + is_inside_match = node.parent and pytree_utils.NodeName( + node.parent) == 'match_stmt' + if (single_stmt_suite and not is_comment_stmt) or is_inside_match: self._cur_depth += 1 self._StartNewLine() self.DefaultNodeVisit(node) - if single_stmt_suite and not is_comment_stmt: + if (single_stmt_suite and not is_comment_stmt) or is_inside_match: self._cur_depth -= 1 def _VisitCompoundStatement(self, node, substatement_names): @@ -253,6 +257,20 @@ def Visit_decorated(self, node): # pylint: disable=invalid-name def Visit_with_stmt(self, node): # pylint: disable=invalid-name self._VisitCompoundStatement(node, self._WITH_STMT_ELEMS) + _MATCH_STMT_ELEMS = frozenset({'match', 'case'}) + + def Visit_match_stmt(self, node): # pylint: disable=invalid-name + self._VisitCompoundStatement(node, self._MATCH_STMT_ELEMS) + + # case_block refers to the grammar element name in Grammar.txt + _CASE_BLOCK_ELEMS = frozenset({'case'}) + + def Visit_case_block(self, node): + self._cur_depth += 1 + self._StartNewLine() + self._VisitCompoundStatement(node, self._CASE_BLOCK_ELEMS) + self._cur_depth -= 1 + def Visit_suite(self, node): # pylint: disable=invalid-name # A 'suite' starts a new indentation level in Python. self._cur_depth += 1 diff --git a/yapf/pytree/pytree_utils.py b/yapf/pytree/pytree_utils.py index 8b3c4065c..e7aa6f59c 100644 --- a/yapf/pytree/pytree_utils.py +++ b/yapf/pytree/pytree_utils.py @@ -26,11 +26,12 @@ import ast import os -from lib2to3 import pygram -from lib2to3 import pytree -from lib2to3.pgen2 import driver -from lib2to3.pgen2 import parse -from lib2to3.pgen2 import token + +from yapf_third_party._ylib2to3 import pygram +from yapf_third_party._ylib2to3 import pytree +from yapf_third_party._ylib2to3.pgen2 import driver +from yapf_third_party._ylib2to3.pgen2 import parse +from yapf_third_party._ylib2to3.pgen2 import token # TODO(eliben): We may want to get rid of this filtering at some point once we # have a better understanding of what information we need from the tree. Then, diff --git a/yapf/pytree/pytree_visitor.py b/yapf/pytree/pytree_visitor.py index 4f6c605ee..ec2cdb7e8 100644 --- a/yapf/pytree/pytree_visitor.py +++ b/yapf/pytree/pytree_visitor.py @@ -25,7 +25,8 @@ """ import sys -from lib2to3 import pytree + +from yapf_third_party._ylib2to3 import pytree from yapf.pytree import pytree_utils diff --git a/yapf/pytree/split_penalty.py b/yapf/pytree/split_penalty.py index ccb3880d4..03b36384a 100644 --- a/yapf/pytree/split_penalty.py +++ b/yapf/pytree/split_penalty.py @@ -14,8 +14,9 @@ """Computation of split penalties before/between tokens.""" import re -from lib2to3 import pytree -from lib2to3.pgen2 import token as grammar_token + +from yapf_third_party._ylib2to3 import pytree +from yapf_third_party._ylib2to3.pgen2 import token as grammar_token from yapf.pytree import pytree_utils from yapf.pytree import pytree_visitor diff --git a/yapf/pytree/subtype_assigner.py b/yapf/pytree/subtype_assigner.py index 97b0e501e..05d88b0fc 100644 --- a/yapf/pytree/subtype_assigner.py +++ b/yapf/pytree/subtype_assigner.py @@ -24,9 +24,9 @@ subtypes. """ -from lib2to3 import pytree -from lib2to3.pgen2 import token as grammar_token -from lib2to3.pygram import python_symbols as syms +from yapf_third_party._ylib2to3 import pytree +from yapf_third_party._ylib2to3.pgen2 import token as grammar_token +from yapf_third_party._ylib2to3.pygram import python_symbols as syms from yapf.pytree import pytree_utils from yapf.pytree import pytree_visitor diff --git a/yapf/yapflib/errors.py b/yapf/yapflib/errors.py index 99e88d9c0..3a0102368 100644 --- a/yapf/yapflib/errors.py +++ b/yapf/yapflib/errors.py @@ -13,7 +13,7 @@ # limitations under the License. """YAPF error objects.""" -from lib2to3.pgen2 import tokenize +from yapf_third_party._ylib2to3.pgen2 import tokenize def FormatErrorMsg(e): diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 31be6f6c5..977a2568f 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -23,7 +23,6 @@ import re import sys from configparser import ConfigParser -from io import StringIO from tokenize import detect_encoding from yapf.yapflib import errors diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 2468b1f9a..0c8643f20 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -1096,8 +1096,10 @@ def _ContainerFitsOnStartLine(self, opening): self.stack[-1].indent) <= self.column_limit -_COMPOUND_STMTS = frozenset( - {'for', 'while', 'if', 'elif', 'with', 'except', 'def', 'class'}) +_COMPOUND_STMTS = frozenset({ + 'for', 'while', 'if', 'elif', 'with', 'except', 'def', 'class', 'match', + 'case' +}) def _IsCompoundStatement(token): diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index c572391e3..141c2650e 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -16,7 +16,9 @@ import keyword import re from functools import lru_cache -from lib2to3.pgen2 import token + +from yapf_third_party._ylib2to3.pgen2 import token +from yapf_third_party._ylib2to3.pytree import type_repr from yapf.pytree import pytree_utils from yapf.yapflib import style @@ -278,7 +280,11 @@ def is_continuation(self): @property @lru_cache() def is_keyword(self): - return keyword.iskeyword(self.value) + return keyword.iskeyword( + self.value) or (self.value == 'match' and + type_repr(self.node.parent.type) == 'match_stmt') or ( + self.value == 'case' and + type_repr(self.node.parent.type) == 'case_block') @property def is_name(self): diff --git a/yapf/yapflib/identify_container.py b/yapf/yapflib/identify_container.py index d027cc5d4..43ba4b9ed 100644 --- a/yapf/yapflib/identify_container.py +++ b/yapf/yapflib/identify_container.py @@ -19,7 +19,7 @@ IdentifyContainers(): the main function exported by this module. """ -from lib2to3.pgen2 import token as grammar_token +from yapf_third_party._ylib2to3.pgen2 import token as grammar_token from yapf.pytree import pytree_utils from yapf.pytree import pytree_visitor diff --git a/yapf/yapflib/logical_line.py b/yapf/yapflib/logical_line.py index 780db8a2a..4433276f7 100644 --- a/yapf/yapflib/logical_line.py +++ b/yapf/yapflib/logical_line.py @@ -19,7 +19,7 @@ perform the wrapping required to comply with the style guide. """ -from lib2to3.fixer_util import syms as python_symbols +from yapf_third_party._ylib2to3.fixer_util import syms as python_symbols from yapf.pytree import pytree_utils from yapf.pytree import split_penalty diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index b7c883e5f..a74b44f6b 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -22,8 +22,9 @@ import collections import heapq import re -from lib2to3 import pytree -from lib2to3.pgen2 import token + +from yapf_third_party._ylib2to3 import pytree +from yapf_third_party._ylib2to3.pgen2 import token from yapf.pytree import pytree_utils from yapf.yapflib import format_decision_state diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index be5467a38..cac62be52 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -35,7 +35,6 @@ import codecs import difflib import re -import sys from yapf.pyparser import pyparser from yapf.pytree import blank_line_calculator diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index 5703e5a8b..59c167c13 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -14,8 +14,9 @@ """Tests for yapf.format_token.""" import unittest -from lib2to3 import pytree -from lib2to3.pgen2 import token + +from yapf_third_party._ylib2to3 import pytree +from yapf_third_party._ylib2to3.pgen2 import token from yapf.yapflib import format_token diff --git a/yapftests/logical_line_test.py b/yapftests/logical_line_test.py index 9188b32fc..bcb2b6133 100644 --- a/yapftests/logical_line_test.py +++ b/yapftests/logical_line_test.py @@ -15,8 +15,9 @@ import textwrap import unittest -from lib2to3 import pytree -from lib2to3.pgen2 import token + +from yapf_third_party._ylib2to3 import pytree +from yapf_third_party._ylib2to3.pgen2 import token from yapf.pytree import split_penalty from yapf.yapflib import format_token diff --git a/yapftests/pytree_utils_test.py b/yapftests/pytree_utils_test.py index b228fcb46..a0be50d03 100644 --- a/yapftests/pytree_utils_test.py +++ b/yapftests/pytree_utils_test.py @@ -14,9 +14,10 @@ """Tests for yapf.pytree_utils.""" import unittest -from lib2to3 import pygram -from lib2to3 import pytree -from lib2to3.pgen2 import token + +from yapf_third_party._ylib2to3 import pygram +from yapf_third_party._ylib2to3 import pytree +from yapf_third_party._ylib2to3.pgen2 import token from yapf.pytree import pytree_utils diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 2edbc3175..034c45d6c 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -23,6 +23,7 @@ from yapftests import yapf_test_helper PY38 = sys.version_info[0] >= 3 and sys.version_info[1] >= 8 +PY310 = sys.version_info[0] >= 3 and sys.version_info[1] >= 10 class BasicReformatterTest(yapf_test_helper.YAPFTest): @@ -3177,6 +3178,42 @@ def testWalrus(self): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected, reformatter.Reformat(llines)) + @unittest.skipUnless(PY310, 'Requires Python 3.10') + def testStructuredPatternMatching(self): + unformatted_code = textwrap.dedent("""\ + match command.split(): + case[action ]: + ... # interpret single-verb action + case[action, obj]: + ... # interpret action, obj + """) + expected = textwrap.dedent("""\ + match command.split(): + case [action]: + ... # interpret single-verb action + case [action, obj]: + ... # interpret action, obj + """) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected, reformatter.Reformat(llines)) + + @unittest.skipUnless(PY310, 'Requires Python 3.10') + def testParenthesizedContextManagers(self): + unformatted_code = textwrap.dedent("""\ + with (cert_authority.cert_pem.tempfile() as ca_temp_path, patch.object(os, 'environ', os.environ | {'REQUESTS_CA_BUNDLE': ca_temp_path}),): + httpserver_url = httpserver.url_for('/resource.jar') + """) # noqa: E501 + expected = textwrap.dedent("""\ + with ( + cert_authority.cert_pem.tempfile() as ca_temp_path, + patch.object(os, 'environ', + os.environ | {'REQUESTS_CA_BUNDLE': ca_temp_path}), + ): + httpserver_url = httpserver.url_for('/resource.jar') + """) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected, reformatter.Reformat(llines)) + if __name__ == '__main__': unittest.main() diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index c08cf5a28..5f9a2189f 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -16,7 +16,8 @@ import sys import textwrap import unittest -from lib2to3 import pytree + +from yapf_third_party._ylib2to3 import pytree from yapf.pytree import pytree_utils from yapf.pytree import pytree_visitor diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 731c1d98b..12db72383 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -230,7 +230,7 @@ def testErrorUnknownStyleOption(self): def testPyprojectTomlNoYapfSection(self): try: - import tomli + import tomli # noqa: F401 except ImportError: return @@ -242,7 +242,7 @@ def testPyprojectTomlNoYapfSection(self): def testPyprojectTomlParseYapfSection(self): try: - import tomli + import tomli # noqa: F401 except ImportError: return diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 7c241bdda..8a31623e1 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -24,7 +24,8 @@ import textwrap import unittest from io import StringIO -from lib2to3.pgen2 import tokenize + +from yapf_third_party._ylib2to3.pgen2 import tokenize from yapf.yapflib import errors from yapf.yapflib import style From 0eedb16a0cfa136f715401503fc2672f44e79736 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sat, 10 Jun 2023 01:06:29 -0500 Subject: [PATCH 623/719] Add ylib2to3 fork comment --- CHANGELOG | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index ec69b5ce6..9e777b154 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,9 @@ - Support for Python 3.11 - Add the `--print-modified` flag to print out file names of modified files when running in in-place mode. +### Changes +- Replace the outdated and no-longer-supported lib2to3 with a fork of blib2to3, + Black's version of lib2to3. ### Removed - Support for Python <3.7 @@ -47,7 +50,7 @@ ## [0.31.0] 2021-03-14 ### Added -- Renamed 'master' brannch to 'main'. +- Renamed 'master' branch to 'main'. - Add 'BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES' to support setting a custom number of blank lines between top-level imports and variable definitions. From de026a535944d05f566798ce00502ced0cfd1f2c Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 13 Jun 2023 02:21:33 -0500 Subject: [PATCH 624/719] Add tests from resolved issues Resolves #233 Resolves #402 Resolves #412 Resolves #830 Resolves #856 Resolves #894 Resolves #1045 Resolves #1058 Resolves #1060 Resolves #1064 Resolves #1085 Resolves #1092 --- yapftests/reformatter_python3_test.py | 402 +++++++++++++++++--------- 1 file changed, 270 insertions(+), 132 deletions(-) diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index 221859a58..17247cd08 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -34,14 +34,14 @@ def testTypedNames(self): unformatted_code = textwrap.dedent("""\ def x(aaaaaaaaaaaaaaa:int,bbbbbbbbbbbbbbbb:str,ccccccccccccccc:dict,eeeeeeeeeeeeee:set={1, 2, 3})->bool: pass - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def x(aaaaaaaaaaaaaaa: int, bbbbbbbbbbbbbbbb: str, ccccccccccccccc: dict, eeeeeeeeeeeeee: set = {1, 2, 3}) -> bool: pass - """) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -49,12 +49,12 @@ def testTypedNameWithLongNamedArg(self): unformatted_code = textwrap.dedent("""\ def func(arg=long_function_call_that_pushes_the_line_over_eighty_characters()) -> ReturnType: pass - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def func(arg=long_function_call_that_pushes_the_line_over_eighty_characters() ) -> ReturnType: pass - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -62,11 +62,11 @@ def testKeywordOnlyArgSpecifier(self): unformatted_code = textwrap.dedent("""\ def foo(a, *, kw): return a+kw - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def foo(a, *, kw): return a + kw - """) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -74,11 +74,11 @@ def testAnnotations(self): unformatted_code = textwrap.dedent("""\ def foo(a: list, b: "bar") -> dict: return a+b - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def foo(a: list, b: "bar") -> dict: return a + b - """) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -104,17 +104,17 @@ async def main(): start = time.time() if (await get_html()): pass - """) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines, verify=False)) def testNoSpacesAroundPowerOperator(self): unformatted_code = textwrap.dedent("""\ a**b - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ a ** b - """) + """) # noqa try: style.SetGlobalStyle( @@ -130,10 +130,10 @@ def testNoSpacesAroundPowerOperator(self): def testSpacesAroundDefaultOrNamedAssign(self): unformatted_code = textwrap.dedent("""\ f(a=5) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ f(a = 5) - """) + """) # noqa try: style.SetGlobalStyle( @@ -155,7 +155,7 @@ def foo(x: int=42): def foo2(x: 'int' =42): pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def foo(x: int = 42): pass @@ -163,24 +163,24 @@ def foo(x: int = 42): def foo2(x: 'int' = 42): pass - """) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMatrixMultiplication(self): unformatted_code = textwrap.dedent("""\ a=b@c - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ a = b @ c - """) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoneKeyword(self): - code = """\ -None.__ne__() -""" + code = textwrap.dedent("""\ + None.__ne__() + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -194,7 +194,7 @@ async def bar(): async def foo(): pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ import asyncio @@ -206,7 +206,7 @@ async def bar(): async def foo(): pass - """) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -216,7 +216,7 @@ async def outer(): async def inner(): pass - """) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -226,13 +226,13 @@ def _ReduceAbstractContainers( self, *args: Optional[automation_converter.PyiCollectionAbc]) -> List[ automation_converter.PyiCollectionAbc]: pass - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def _ReduceAbstractContainers( self, *args: Optional[automation_converter.PyiCollectionAbc] ) -> List[automation_converter.PyiCollectionAbc]: pass - """) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -242,66 +242,66 @@ async def start_websocket(): async with session.ws_connect( r"ws://a_really_long_long_long_long_long_long_url") as ws: pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ async def start_websocket(): async with session.ws_connect( r"ws://a_really_long_long_long_long_long_long_url") as ws: pass - """) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingArguments(self): - unformatted_code = """\ -async def open_file(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None): - pass - -async def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): - pass - -def open_file(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None): - pass - -def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): - pass -""" # noqa - expected_formatted_code = """\ -async def open_file( - file, - mode='r', - buffering=-1, - encoding=None, - errors=None, - newline=None, - closefd=True, - opener=None -): - pass - - -async def run_sync_in_worker_thread( - sync_fn, *args, cancellable=False, limiter=None -): - pass - - -def open_file( - file, - mode='r', - buffering=-1, - encoding=None, - errors=None, - newline=None, - closefd=True, - opener=None -): - pass - - -def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): - pass -""" + unformatted_code = textwrap.dedent("""\ + async def open_file(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None): + pass + + async def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): + pass + + def open_file(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None): + pass + + def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): + pass + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + async def open_file( + file, + mode='r', + buffering=-1, + encoding=None, + errors=None, + newline=None, + closefd=True, + opener=None + ): + pass + + + async def run_sync_in_worker_thread( + sync_fn, *args, cancellable=False, limiter=None + ): + pass + + + def open_file( + file, + mode='r', + buffering=-1, + encoding=None, + errors=None, + newline=None, + closefd=True, + opener=None + ): + pass + + + def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): + pass + """) # noqa try: style.SetGlobalStyle( @@ -320,90 +320,90 @@ def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): style.SetGlobalStyle(style.CreatePEP8Style()) def testDictUnpacking(self): - unformatted_code = """\ -class Foo: - def foo(self): - foofoofoofoofoofoofoofoo('foofoofoofoofoo', { - - 'foo': 'foo', - - **foofoofoo - }) -""" - expected_formatted_code = """\ -class Foo: - - def foo(self): - foofoofoofoofoofoofoofoo('foofoofoofoofoo', { - 'foo': 'foo', - **foofoofoo - }) -""" + unformatted_code = textwrap.dedent("""\ + class Foo: + def foo(self): + foofoofoofoofoofoofoofoo('foofoofoofoofoo', { + + 'foo': 'foo', + + **foofoofoo + }) + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + class Foo: + + def foo(self): + foofoofoofoofoofoofoofoo('foofoofoofoofoo', { + 'foo': 'foo', + **foofoofoo + }) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMultilineFormatString(self): - code = """\ -# yapf: disable -(f''' - ''') -# yapf: enable -""" # https://github.com/google/yapf/issues/513 + code = textwrap.dedent("""\ + # yapf: disable + (f''' + ''') + # yapf: enable + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testEllipses(self): - code = """\ -def dirichlet(x12345678901234567890123456789012345678901234567890=...) -> None: - return -""" # https://github.com/google/yapf/issues/533 + code = textwrap.dedent("""\ + def dirichlet(x12345678901234567890123456789012345678901234567890=...) -> None: + return + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionTypedReturnNextLine(self): - code = """\ -def _GenerateStatsEntries( - process_id: Text, - timestamp: Optional[ffffffff.FFFFFFFFFFF] = None -) -> Sequence[ssssssssssss.SSSSSSSSSSSSSSS]: - pass -""" + code = textwrap.dedent("""\ + def _GenerateStatsEntries( + process_id: Text, + timestamp: Optional[ffffffff.FFFFFFFFFFF] = None + ) -> Sequence[ssssssssssss.SSSSSSSSSSSSSSS]: + pass + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionTypedReturnSameLine(self): - code = """\ -def rrrrrrrrrrrrrrrrrrrrrr( - ccccccccccccccccccccccc: Tuple[Text, Text]) -> List[Tuple[Text, Text]]: - pass -""" + code = textwrap.dedent("""\ + def rrrrrrrrrrrrrrrrrrrrrr( + ccccccccccccccccccccccc: Tuple[Text, Text]) -> List[Tuple[Text, Text]]: + pass + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testAsyncForElseNotIndentedInsideBody(self): code = textwrap.dedent("""\ - async def fn(): - async for message in websocket: - for i in range(10): - pass + async def fn(): + async for message in websocket: + for i in range(10): + pass + else: + pass else: pass - else: - pass - """) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testForElseInAsyncNotMixedWithAsyncFor(self): code = textwrap.dedent("""\ - async def fn(): - for i in range(10): - pass - else: - pass - """) + async def fn(): + for i in range(10): + pass + else: + pass + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -412,7 +412,7 @@ def testParameterListIndentationConflicts(self): def raw_message( # pylint: disable=too-many-arguments self, text, user_id=1000, chat_type='private', forward_date=None, forward_from=None): pass - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def raw_message( # pylint: disable=too-many-arguments self, @@ -422,10 +422,148 @@ def raw_message( # pylint: disable=too-many-arguments forward_date=None, forward_from=None): pass - """) + """) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) + + def testTypeHintedYieldExpression(self): + # https://github.com/google/yapf/issues/1092 + code = textwrap.dedent("""\ + def my_coroutine(): + x: int = yield + """) # noqa + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) + + def testSyntaxMatch(self): + # https://github.com/google/yapf/issues/1045 + # https://github.com/google/yapf/issues/1085 + unformatted_code = textwrap.dedent("""\ + a=3 + b=0 + match a : + case 0 : + b=1 + case _ : + b=2 + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + a = 3 + b = 0 + match a: + case 0: + b = 1 + case _: + b = 2 + """) # noqa + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) + + def testParenthsizedContextManager(self): + # https://github.com/google/yapf/issues/1064 + unformatted_code = textwrap.dedent("""\ + def test_copy_dimension(self): + with (Dataset() as target_ds, + Dataset() as source_ds): + do_something + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + def test_copy_dimension(self): + with (Dataset() as target_ds, Dataset() as source_ds): + do_something + """) # noqa + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) + + def testUnpackedTuple(self): + # https://github.com/google/yapf/issues/830 + # https://github.com/google/yapf/issues/1060 + unformatted_code = textwrap.dedent("""\ + def a(): + t = (2,3) + for i in range(5): + yield i,*t + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + def a(): + t = (2, 3) + for i in range(5): + yield i, *t + """) # noqa + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) + + def testTypedTuple(self): + # https://github.com/google/yapf/issues/412 + # https://github.com/google/yapf/issues/1058 + code = textwrap.dedent("""\ + t: tuple = 1, 2 + args = tuple(x for x in [2], ) + """) # noqa + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) + + def testWalrusOperator(self): + # https://github.com/google/yapf/issues/894 + unformatted_code = textwrap.dedent("""\ + import os + a=[1,2,3,4] + if (n:=len(a))>2: + print() + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + import os + + a = [1, 2, 3, 4] + if (n := len(a)) > 2: + print() + """) # noqa + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) + + def testCondAssign(self): + # https://github.com/google/yapf/issues/856 + unformatted_code = textwrap.dedent("""\ + def json(self) -> JSONTask: + result: JSONTask = { + "id": self.id, + "text": self.text, + "status": self.status, + "last_mod": self.last_mod_time + } + for i in "parent_id", "deadline", "reminder": + if x := getattr(self , i): + result[i] = x # type: ignore + return result + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + def json(self) -> JSONTask: + result: JSONTask = { + "id": self.id, + "text": self.text, + "status": self.status, + "last_mod": self.last_mod_time + } + for i in "parent_id", "deadline", "reminder": + if x := getattr(self, i): + result[i] = x # type: ignore + return result + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) + def testCopyDictionary(self): + # https://github.com/google/yapf/issues/233 + # https://github.com/google/yapf/issues/402 + code = textwrap.dedent("""\ + a_dict = {'key': 'value'} + a_dict_copy = {**a_dict} + print('a_dict:', a_dict) + print('a_dict_copy:', a_dict_copy) + """) # noqa + llines = yapf_test_helper.ParseAndUnwrap(code) + self.assertCodeEqual(code, reformatter.Reformat(llines)) + if __name__ == '__main__': unittest.main() From d44294cdc735da84384b9507937b50bf9b49a007 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 13 Jun 2023 02:37:41 -0500 Subject: [PATCH 625/719] Bump version to 0.44.0 --- CHANGELOG | 4 ++-- HACKING.rst | 2 +- README.rst | 2 +- setup.py | 2 +- yapf/__init__.py | 3 +-- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9e777b154..cc963092d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.40.0] UNRELEASED +## [0.40.0] 2023-06-13 ### Added - Support for Python 3.11 - Add the `--print-modified` flag to print out file names of modified files when @@ -11,7 +11,7 @@ - Replace the outdated and no-longer-supported lib2to3 with a fork of blib2to3, Black's version of lib2to3. ### Removed -- Support for Python <3.7 +- Support for Python versions < 3.7 are no longer supported. ## [0.33.0] 2023-04-18 ### Added diff --git a/HACKING.rst b/HACKING.rst index 297101a85..3e2046942 100644 --- a/HACKING.rst +++ b/HACKING.rst @@ -15,7 +15,7 @@ Releasing a new version * Run tests: python setup.py test [don't forget to run with at least Python 3.7 and 3.11] -* Bump version in yapf/__init__.py +* Bump version in setup.py. * Build source distribution: python setup.py sdist diff --git a/README.rst b/README.rst index 25e8c10d8..8d4e530ec 100644 --- a/README.rst +++ b/README.rst @@ -119,7 +119,7 @@ Options:: permanent --no-local-style don't search for local style definition -p, --parallel run YAPF in parallel when formatting multiple - files. Requires concurrent.futures in Python 2.X + files. -m, --print-modified print out file names of modified files -vv, --verbose print out file names while processing diff --git a/setup.py b/setup.py index a294ccce3..7884cc963 100644 --- a/setup.py +++ b/setup.py @@ -42,7 +42,7 @@ def run(self): with codecs.open('README.rst', 'r', 'utf-8') as fd: setup( name='yapf', - version='0.33.0', + version='0.40.0', description='A formatter for Python code.', url='https://github.com/google/yapf', long_description=fd.read(), diff --git a/yapf/__init__.py b/yapf/__init__.py index 7ef89a93f..dd0feff29 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -365,8 +365,7 @@ def _BuildParser(): '-p', '--parallel', action='store_true', - help=('run YAPF in parallel when formatting multiple files. Requires ' - 'concurrent.futures in Python 2.X')) + help=('run YAPF in parallel when formatting multiple files.')) parser.add_argument( '-m', '--print-modified', From 43ee73d350e56be97f1216906a5fcc5d135f8c99 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Tue, 13 Jun 2023 21:44:49 +0200 Subject: [PATCH 626/719] pre-commit: Make CI keep pre-commit actions up to date (#1097) --- .github/workflows/pre-commit-autoupdate.yml | 63 +++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 .github/workflows/pre-commit-autoupdate.yml diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml new file mode 100644 index 000000000..a0d9533dc --- /dev/null +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -0,0 +1,63 @@ +# Copyright (c) 2023 Sebastian Pipping +# Licensed under the Apache License Version 2.0 + +name: Keep pre-commit hooks up to date + +on: + schedule: + - cron: '0 16 * * 5' # Every Friday 4pm + workflow_dispatch: + +# NOTE: This will drop all permissions from GITHUB_TOKEN except metadata read, +# and then (re)add the ones listed below: +permissions: + contents: write + pull-requests: write + +jobs: + pre_commit_autoupdate: + name: Detect outdated pre-commit hooks + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + + - name: Set up Python 3.11 + uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # v4.5.0 + with: + python-version: 3.11 + + - name: Install pre-commit + run: |- + pip install \ + --disable-pip-version-check \ + --no-warn-script-location \ + --user \ + pre-commit + echo "PATH=${HOME}/.local/bin:${PATH}" >> "${GITHUB_ENV}" + + - name: Check for outdated hooks + run: |- + pre-commit autoupdate + git diff -- .pre-commit-config.yaml + + - name: Create pull request from changes (if any) + id: create-pull-request + uses: peter-evans/create-pull-request@5b4a9f6a9e2af26e5f02351490b90d01eb8ec1e5 # v5.0.0 + with: + author: 'pre-commit ' + base: main + body: |- + For your consideration. + + :warning: Please **CLOSE AND RE-OPEN** this pull request so that [further workflow runs get triggered](https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#triggering-further-workflow-runs) for this pull request. + branch: precommit-autoupdate + commit-message: "pre-commit: Autoupdate" + delete-branch: true + draft: true + labels: enhancement + title: "pre-commit: Autoupdate" + + - name: Log pull request URL + if: "${{ steps.create-pull-request.outputs.pull-request-url }}" + run: | + echo "Pull request URL is: ${{ steps.create-pull-request.outputs.pull-request-url }}" From 94318bb539fcc5960304a9a15cd07724df5e1e3c Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 13 Jun 2023 15:48:10 -0500 Subject: [PATCH 627/719] Convert README file to MarkDown --- README.md | 1038 ++++++++++++++++++++++++++++++++++++++++++++++++++++ README.rst | 1023 --------------------------------------------------- 2 files changed, 1038 insertions(+), 1023 deletions(-) create mode 100644 README.md delete mode 100644 README.rst diff --git a/README.md b/README.md new file mode 100644 index 000000000..74b6a4225 --- /dev/null +++ b/README.md @@ -0,0 +1,1038 @@ +# YAPF + +

+PyPI Version +Build Status +Actions Status +Coverage Status +

+ + +---- + +- TOC +{:toc} + +---- + + +## Introduction + +YAPF is a Python formatter based off of [`clang-format`](https://clang.llvm.org/docs/ClangFormat.html) +(developed by Daniel Jasper). In essence, the algorithm takes the code and +calculates the best formatting that conforms to the configured style. It takes +away a lot of the drudgery of maintaining your code. + +The ultimate goal is that the code YAPF produces is as good as the code that a +programmer would write if they were following the style guide. + +> **Note** +> YAPF is not an official Google product (experimental or otherwise), it is +> just code that happens to be owned by Google. + + +## Installation + +To install YAPF from PyPI: + +```bash +$ pip install yapf +``` + +YAPF is still considered in "alpha" stage, and the released version may change +often; therefore, the best way to keep up-to-date with the latest development +is to clone this repository. + +Note that if you intend to use YAPF as a command-line tool rather than as a +library, installation is not necessary. YAPF supports being run as a directory +by the Python interpreter. If you cloned/unzipped YAPF into `DIR`, it's +possible to run: + +```bash +$ PYTHONPATH=DIR python DIR/yapf [options] ... +``` + + +## Required Python versions + +YAPF supports Python 3.7+. + +> **Note** +> YAPF requires the code it formats to be valid Python for the version YAPF +> itself runs under. + + +## Usage + +```console +usage: yapf [-h] [-v] [-d | -i | -q] [-r | -l START-END] [-e PATTERN] + [--style STYLE] [--style-help] [--no-local-style] [-p] [-m] [-vv] + [files ...] + +Formatter for Python code. + +positional arguments: + files reads from stdin when no files are specified. + +optional arguments: + -h, --help show this help message and exit + -v, --version show program's version number and exit + -d, --diff print the diff for the fixed source + -i, --in-place make changes to files in place + -q, --quiet output nothing and set return value + -r, --recursive run recursively over directories + -l START-END, --lines START-END + range of lines to reformat, one-based + -e PATTERN, --exclude PATTERN + patterns for files to exclude from formatting + --style STYLE specify formatting style: either a style name (for + example "pep8" or "google"), or the name of a file + with style settings. The default is pep8 unless a + .style.yapf or setup.cfg or pyproject.toml file + located in the same directory as the source or one of + its parent directories (for stdin, the current + directory is used). + --style-help show style settings and exit; this output can be saved + to .style.yapf to make your settings permanent + --no-local-style don't search for local style definition + -p, --parallel run YAPF in parallel when formatting multiple files. + -m, --print-modified print out file names of modified files + -vv, --verbose print out file names while processing +``` + +### Return Codes + +Normally YAPF returns zero on successful program termination and non-zero +otherwise. + +If `--diff` is supplied, YAPF returns zero when no changes were necessary, +non-zero otherwise (including program error). You can use this in a CI workflow +to test that code has been YAPF-formatted. + +### Excluding files from formatting (.yapfignore or pyproject.toml) + +In addition to exclude patterns provided on commandline, YAPF looks for +additional patterns specified in a file named `.yapfignore` or `pyproject.toml` +located in the working directory from which YAPF is invoked. + +`.yapfignore`'s syntax is similar to UNIX's filename pattern matching: + +``` +* matches everything +? matches any single character +[seq] matches any character in seq +[!seq] matches any character not in seq +``` + +Note that no entry should begin with `./`. + +If you use `pyproject.toml`, exclude patterns are specified by `ignore_patterns` key +in `[tool.yapfignore]` section. For example: + +```ini +[tool.yapfignore] +ignore_patterns = [ + "temp/**/*.py", + "temp2/*.py" +] +``` + + +Formatting style +================ + +The formatting style used by YAPF is configurable and there are many "knobs" +that can be used to tune how YAPF does formatting. See the `style.py` module +for the full list. + +To control the style, run YAPF with the `--style` argument. It accepts one of +the predefined styles (e.g., `pep8` or `google`), a path to a configuration +file that specifies the desired style, or a dictionary of key/value pairs. + +The config file is a simple listing of (case-insensitive) `key = value` pairs +with a `[style]` heading. For example: + +```ini +[style] +based_on_style = pep8 +spaces_before_comment = 4 +split_before_logical_operator = true +``` + +The `based_on_style` setting determines which of the predefined styles this +custom style is based on (think of it like subclassing). Four +styles are predefined: + +- `pep8` (default) +- `google` (based off of the [Google Python Style Guide](https://github.com/google/styleguide/blob/gh-pages/pyguide.md)) +- `yapf` (for use with Google open source projects) +- `facebook` + +See `_STYLE_NAME_TO_FACTORY` in [`style.py`](https://github.com/google/yapf/blob/main/yapf/yapflib/style.py) for details. + +It's also possible to do the same on the command line with a dictionary. For +example: + +```bash +--style='{based_on_style: pep8, indent_width: 2}' +``` + +This will take the `pep8` base style and modify it to have two space +indentations. + +YAPF will search for the formatting style in the following manner: + +1. Specified on the command line +2. In the `[style]` section of a `.style.yapf` file in either the current + directory or one of its parent directories. +3. In the `[yapf]` section of a `setup.cfg` file in either the current + directory or one of its parent directories. +4. In the `[tool.yapf]` section of a `pyproject.toml` file in either the current + directory or one of its parent directories. +5. In the `[style]` section of a `~/.config/yapf/style` file in your home + directory. + +If none of those files are found, the default style PEP8 is used. + + +Example +======= + +An example of the type of formatting that YAPF can do, it will take this ugly +code: + +```python +x = { 'a':37,'b':42, + +'c':927} + +y = 'hello ''world' +z = 'hello '+'world' +a = 'hello {}'.format('world') +class foo ( object ): + def f (self ): + return 37*-+2 + def g(self, x,y=42): + return y +def f ( a ) : + return 37+-+a[42-x : y**3] +``` + +and reformat it into: + +```python +x = {'a': 37, 'b': 42, 'c': 927} + +y = 'hello ' 'world' +z = 'hello ' + 'world' +a = 'hello {}'.format('world') + + +class foo(object): + def f(self): + return 37 * -+2 + + def g(self, x, y=42): + return y + + +def f(a): + return 37 + -+a[42 - x:y**3] +``` + + +## Example as a module + +The two main APIs for calling YAPF are `FormatCode` and `FormatFile`, these +share several arguments which are described below: + +```python +>>> from yapf.yapflib.yapf_api import FormatCode # reformat a string of code + +>>> formatted_code, changed = FormatCode("f ( a = 1, b = 2 )") +>>> formatted_code +'f(a=1, b=2)\n' +>>> changed +True +``` + +A `style_config` argument: Either a style name or a path to a file that +contains formatting style settings. If None is specified, use the default style +as set in `style.DEFAULT_STYLE_FACTORY`. + +```python +>>> FormatCode("def g():\n return True", style_config='pep8')[0] +'def g():\n return True\n' +``` + +A `lines` argument: A list of tuples of lines (ints), [start, end], that we +want to format. The lines are 1-based indexed. It can be used by third-party +code (e.g., IDEs) when reformatting a snippet of code rather than a whole file. + +```python +>>> FormatCode("def g( ):\n a=1\n b = 2\n return a==b", lines=[(1, 1), (2, 3)])[0] +'def g():\n a = 1\n b = 2\n return a==b\n' +``` + +A `print_diff` (bool): Instead of returning the reformatted source, return a +diff that turns the formatted source into reformatted source. + +```diff +>>> print(FormatCode("a==b", filename="foo.py", print_diff=True)[0]) +--- foo.py (original) ++++ foo.py (reformatted) +@@ -1 +1 @@ +-a==b ++a == b +``` + +Note: the `filename` argument for `FormatCode` is what is inserted into the +diff, the default is ``. + +`FormatFile` returns reformatted code from the passed file along with its encoding: + +```python +>>> from yapf.yapflib.yapf_api import FormatFile # reformat a file + +>>> print(open("foo.py").read()) # contents of file +a==b + +>>> reformatted_code, encoding, changed = FormatFile("foo.py") +>>> formatted_code +'a == b\n' +>>> encoding +'utf-8' +>>> changed +True +``` + +The `in_place` argument saves the reformatted code back to the file: + +```python +>>> FormatFile("foo.py", in_place=True)[:2] +(None, 'utf-8') + +>>> print(open("foo.py").read()) # contents of file (now fixed) +a == b +``` + + +## Formatting diffs + +Options: + +``` +usage: yapf-diff [-h] [-i] [-p NUM] [--regex PATTERN] [--iregex PATTERN][-v] + [--style STYLE] [--binary BINARY] + +This script reads input from a unified diff and reformats all the changed +lines. This is useful to reformat all the lines touched by a specific patch. +Example usage for git/svn users: + + git diff -U0 --no-color --relative HEAD^ | yapf-diff -i + svn diff --diff-cmd=diff -x-U0 | yapf-diff -p0 -i + +It should be noted that the filename contained in the diff is used +unmodified to determine the source file to update. Users calling this script +directly should be careful to ensure that the path in the diff is correct +relative to the current working directory. + +optional arguments: + -h, --help show this help message and exit + -i, --in-place apply edits to files instead of displaying a diff + -p NUM, --prefix NUM strip the smallest prefix containing P slashes + --regex PATTERN custom pattern selecting file paths to reformat + (case sensitive, overrides -iregex) + --iregex PATTERN custom pattern selecting file paths to reformat + (case insensitive, overridden by -regex) + -v, --verbose be more verbose, ineffective without -i + --style STYLE specify formatting style: either a style name (for + example "pep8" or "google"), or the name of a file + with style settings. The default is pep8 unless a + .style.yapf or setup.cfg or pyproject.toml file + located in the same directory as the source or one of + its parent directories (for stdin, the current + directory is used). + --binary BINARY location of binary to use for YAPF +``` + + +## Knobs + +`ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT` + + Align closing bracket with visual indentation. + +`ALLOW_MULTILINE_LAMBDAS` + + Allow lambdas to be formatted on more than one line. + +`ALLOW_MULTILINE_DICTIONARY_KEYS` + + Allow dictionary keys to exist on multiple lines. For example: + + ```python + x = { + ('this is the first element of a tuple', + 'this is the second element of a tuple'): + value, + } + ``` + +`ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS` + + Allow splitting before a default / named assignment in an argument list. + +`ALLOW_SPLIT_BEFORE_DICT_VALUE` + + Allow splits before the dictionary value. + +`ARITHMETIC_PRECEDENCE_INDICATION` + + Let spacing indicate operator precedence. For example: + + ```python + a = 1 * 2 + 3 / 4 + b = 1 / 2 - 3 * 4 + c = (1 + 2) * (3 - 4) + d = (1 - 2) / (3 + 4) + e = 1 * 2 - 3 + f = 1 + 2 + 3 + 4 + ``` + + will be formatted as follows to indicate precedence: + + ```python + a = 1*2 + 3/4 + b = 1/2 - 3*4 + c = (1+2) * (3-4) + d = (1-2) / (3+4) + e = 1*2 - 3 + f = 1 + 2 + 3 + 4 + ``` + +`BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF` + + Insert a blank line before a `def` or `class` immediately nested within + another `def` or `class`. For example: + + ```python + class Foo: + # <------ this blank line + def method(): + pass + ``` + +`BLANK_LINE_BEFORE_MODULE_DOCSTRING` + + Insert a blank line before a module docstring. + +`BLANK_LINE_BEFORE_CLASS_DOCSTRING` + + Insert a blank line before a class-level docstring. + +`BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION` + + Sets the number of desired blank lines surrounding top-level function and + class definitions. For example: + + ```python + class Foo: + pass + # <------ having two blank lines here + # <------ is the default setting + class Bar: + pass + ``` + +`BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES` + + Sets the number of desired blank lines between top-level imports and + variable definitions. Useful for compatibility with tools like isort. + +`COALESCE_BRACKETS` + + Do not split consecutive brackets. Only relevant when + `DEDENT_CLOSING_BRACKETS` or `INDENT_CLOSING_BRACKETS` is set. For example: + + ```python + call_func_that_takes_a_dict( + { + 'key1': 'value1', + 'key2': 'value2', + } + ) + ``` + + would reformat to: + + ```python + call_func_that_takes_a_dict({ + 'key1': 'value1', + 'key2': 'value2', + }) + ``` + + +`COLUMN_LIMIT` + + The column limit (or max line-length) + +`CONTINUATION_ALIGN_STYLE` + + The style for continuation alignment. Possible values are: + + - `SPACE`: Use spaces for continuation alignment. This is default + behavior. + - `FIXED`: Use fixed number (CONTINUATION_INDENT_WIDTH) of columns + (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs or + CONTINUATION_INDENT_WIDTH spaces) for continuation alignment. + - `VALIGN-RIGHT`: Vertically align continuation lines to multiple of + INDENT_WIDTH columns. Slightly right (one tab or a few spaces) if cannot + vertically align continuation lines with indent characters. + +`CONTINUATION_INDENT_WIDTH` + + Indent width used for line continuations. + +`DEDENT_CLOSING_BRACKETS` + + Put closing brackets on a separate line, dedented, if the bracketed + expression can't fit in a single line. Applies to all kinds of brackets, + including function definitions and calls. For example: + + ```python + config = { + 'key1': 'value1', + 'key2': 'value2', + } # <--- this bracket is dedented and on a separate line + + time_series = self.remote_client.query_entity_counters( + entity='dev3246.region1', + key='dns.query_latency_tcp', + transform=Transformation.AVERAGE(window=timedelta(seconds=60)), + start_ts=now()-timedelta(days=3), + end_ts=now(), + ) # <--- this bracket is dedented and on a separate line + ``` + +`DISABLE_ENDING_COMMA_HEURISTIC` + + Disable the heuristic which places each list element on a separate line if + the list is comma-terminated. + +`EACH_DICT_ENTRY_ON_SEPARATE_LINE` + + Place each dictionary entry onto its own line. + +`FORCE_MULTILINE_DICT` + + Respect `EACH_DICT_ENTRY_ON_SEPARATE_LINE` even if the line is shorter than + `COLUMN_LIMIT`. + +`I18N_COMMENT` + + The regex for an internationalization comment. The presence of this comment + stops reformatting of that line, because the comments are required to be + next to the string they translate. + +`I18N_FUNCTION_CALL` + + The internationalization function call names. The presence of this function + stops reformatting on that line, because the string it has cannot be moved + away from the i18n comment. + +`INDENT_DICTIONARY_VALUE` + + Indent the dictionary value if it cannot fit on the same line as the + dictionary key. For example: + + ```python + config = { + 'key1': + 'value1', + 'key2': value1 + + value2, + } + ``` + +`INDENT_WIDTH` + + The number of columns to use for indentation. + +`INDENT_BLANK_LINES` + + Set to `True` to prefer indented blank lines rather than empty + +`INDENT_CLOSING_BRACKETS` + + Put closing brackets on a separate line, indented, if the bracketed + expression can't fit in a single line. Applies to all kinds of brackets, + including function definitions and calls. For example: + + ```python + config = { + 'key1': 'value1', + 'key2': 'value2', + } # <--- this bracket is indented and on a separate line + + time_series = self.remote_client.query_entity_counters( + entity='dev3246.region1', + key='dns.query_latency_tcp', + transform=Transformation.AVERAGE(window=timedelta(seconds=60)), + start_ts=now()-timedelta(days=3), + end_ts=now(), + ) # <--- this bracket is indented and on a separate line + ``` + +`JOIN_MULTIPLE_LINES` + + Join short lines into one line. E.g., single line `if` statements. + +`NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS` + + Do not include spaces around selected binary operators. For example: + + ```python + 1 + 2 * 3 - 4 / 5 + ``` + + will be formatted as follows when configured with `*`, `/`: + + ```python + 1 + 2*3 - 4/5 + ``` + +`SPACES_AROUND_POWER_OPERATOR` + + Set to `True` to prefer using spaces around `**`. + +`SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN` + + Set to `True` to prefer spaces around the assignment operator for default + or keyword arguments. + +`SPACES_AROUND_DICT_DELIMITERS` + + Adds a space after the opening '{' and before the ending '}' dict delimiters. + + ```python + {1: 2} + ``` + + will be formatted as: + + ```python + { 1: 2 } + ``` + +`SPACES_AROUND_LIST_DELIMITERS` + + Adds a space after the opening '[' and before the ending ']' list delimiters. + + ```python + [1, 2] + ``` + + will be formatted as: + + ```python + [ 1, 2 ] + ``` + +`SPACES_AROUND_SUBSCRIPT_COLON` + + Use spaces around the subscript / slice operator. For example: + + ```python + my_list[1 : 10 : 2] + ``` + +`SPACES_AROUND_TUPLE_DELIMITERS` + + Adds a space after the opening '(' and before the ending ')' tuple delimiters. + + ```python + (1, 2, 3) + ``` + + will be formatted as: + + ```python + ( 1, 2, 3 ) + ``` + +`SPACES_BEFORE_COMMENT` + + The number of spaces required before a trailing comment. + This can be a single value (representing the number of spaces + before each trailing comment) or list of values (representing + alignment column values; trailing comments within a block will + be aligned to the first column value that is greater than the maximum + line length within the block). + + > **Note:** Lists of values may need to be quoted in some contexts + > (eg. shells or editor config files). + + For example, with `spaces_before_comment=5`: + + ```python + 1 + 1 # Adding values + ``` + + will be formatted as: + + ```python + 1 + 1 # Adding values <-- 5 spaces between the end of the statement and comment + ``` + + with `spaces_before_comment="15, 20"`: + + ```python + 1 + 1 # Adding values + two + two # More adding + + longer_statement # This is a longer statement + short # This is a shorter statement + + a_very_long_statement_that_extends_beyond_the_final_column # Comment + short # This is a shorter statement + ``` + + will be formatted as: + + ```python + 1 + 1 # Adding values <-- end of line comments in block aligned to col 15 + two + two # More adding + + longer_statement # This is a longer statement <-- end of line comments in block aligned to col 20 + short # This is a shorter statement + + a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length + short # This is a shorter statement + ``` + +`SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET` + + Insert a space between the ending comma and closing bracket of a list, etc. + +`SPACE_INSIDE_BRACKETS` + + Use spaces inside brackets, braces, and parentheses. For example: + + ``` + method_call( 1 ) + my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] + my_set = { 1, 2, 3 } + ``` + +`SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED` + + Split before arguments if the argument list is terminated by a comma. + +`SPLIT_ALL_COMMA_SEPARATED_VALUES` + + If a comma separated list (`dict`, `list`, `tuple`, or function `def`) is + on a line that is too long, split such that each element is on a separate + line. + +`SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES` + + Variation on `SPLIT_ALL_COMMA_SEPARATED_VALUES` in which, if a + subexpression with a comma fits in its starting line, then the + subexpression is not split. This avoids splits like the one for + `b` in this code: + + ```python + abcdef( + aReallyLongThing: int, + b: [Int, + Int]) + ``` + + with the new knob this is split as: + + ```python + abcdef( + aReallyLongThing: int, + b: [Int, Int]) + ``` + +`SPLIT_BEFORE_BITWISE_OPERATOR` + + Set to `True` to prefer splitting before `&`, `|` or `^` rather than after. + +`SPLIT_BEFORE_ARITHMETIC_OPERATOR` + + Set to `True` to prefer splitting before `+`, `-`, `*`, `/`, `//`, or `@` + rather than after. + +`SPLIT_BEFORE_CLOSING_BRACKET` + + Split before the closing bracket if a `list` or `dict` literal doesn't fit + on a single line. + +`SPLIT_BEFORE_DICT_SET_GENERATOR` + + Split before a dictionary or set generator (`comp_for`). For example, note + the split before the `for`: + + ```python + foo = { + variable: 'Hello world, have a nice day!' + for variable in bar if variable != 42 + } + ``` + +`SPLIT_BEFORE_DOT` + + Split before the `.` if we need to split a longer expression: + + ```python + foo = ('This is a really long string: {}, {}, {}, {}'.format(a, b, c, d)) + ``` + + would reformat to something like: + + ```python + foo = ('This is a really long string: {}, {}, {}, {}' + .format(a, b, c, d)) + ``` + +`SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN` + + Split after the opening paren which surrounds an expression if it doesn't + fit on a single line. + +`SPLIT_BEFORE_FIRST_ARGUMENT` + + If an argument / parameter list is going to be split, then split before the + first argument. + +`SPLIT_BEFORE_LOGICAL_OPERATOR` + + Set to `True` to prefer splitting before `and` or `or` rather than after. + +`SPLIT_BEFORE_NAMED_ASSIGNS` + + Split named assignments onto individual lines. + +`SPLIT_COMPLEX_COMPREHENSION` + + For list comprehensions and generator expressions with multiple clauses + (e.g multiple `for` calls, `if` filter expressions) and which need to be + reflowed, split each clause onto its own line. For example: + + ```python + result = [ + a_var + b_var for a_var in xrange(1000) for b_var in xrange(1000) + if a_var % b_var] + ``` + + would reformat to something like: + + ```python + result = [ + a_var + b_var + for a_var in xrange(1000) + for b_var in xrange(1000) + if a_var % b_var] + ``` + +`SPLIT_PENALTY_AFTER_OPENING_BRACKET` + + The penalty for splitting right after the opening bracket. + +`SPLIT_PENALTY_AFTER_UNARY_OPERATOR` + + The penalty for splitting the line after a unary operator. + +`SPLIT_PENALTY_ARITHMETIC_OPERATOR` + + The penalty of splitting the line around the `+`, `-`, `*`, `/`, `//`, `%`, + and `@` operators. + +`SPLIT_PENALTY_BEFORE_IF_EXPR` + + The penalty for splitting right before an `if` expression. + +`SPLIT_PENALTY_BITWISE_OPERATOR` + + The penalty of splitting the line around the `&`, `|`, and `^` operators. + +`SPLIT_PENALTY_COMPREHENSION` + + The penalty for splitting a list comprehension or generator expression. + +`SPLIT_PENALTY_EXCESS_CHARACTER` + + The penalty for characters over the column limit. + +`SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT` + + The penalty incurred by adding a line split to the logical line. The more + line splits added the higher the penalty. + +`SPLIT_PENALTY_IMPORT_NAMES` + + The penalty of splitting a list of `import as` names. For example: + + ```python + from a_very_long_or_indented_module_name_yada_yad import (long_argument_1, + long_argument_2, + long_argument_3) + ``` + + would reformat to something like: + + ```python + from a_very_long_or_indented_module_name_yada_yad import ( + long_argument_1, long_argument_2, long_argument_3) + ``` + +`SPLIT_PENALTY_LOGICAL_OPERATOR` + + The penalty of splitting the line around the `and` and `or` operators. + +`USE_TABS` + + Use the Tab character for indentation. + + +## (Potentially) Frequently Asked Questions + +### Why does YAPF destroy my awesome formatting? + +YAPF tries very hard to get the formatting correct. But for some code, it won't +be as good as hand-formatting. In particular, large data literals may become +horribly disfigured under YAPF. + +The reasons for this are manyfold. In short, YAPF is simply a tool to help +with development. It will format things to coincide with the style guide, but +that may not equate with readability. + +What can be done to alleviate this situation is to indicate regions YAPF should +ignore when reformatting something: + +```python +# yapf: disable +FOO = { + # ... some very large, complex data literal. +} + +BAR = [ + # ... another large data literal. +] +# yapf: enable +``` + +You can also disable formatting for a single literal like this: + +```python +BAZ = { + (1, 2, 3, 4), + (5, 6, 7, 8), + (9, 10, 11, 12), +} # yapf: disable +``` + +To preserve the nice dedented closing brackets, use the +`dedent_closing_brackets` in your style. Note that in this case all +brackets, including function definitions and calls, are going to use +that style. This provides consistency across the formatted codebase. + +### Why Not Improve Existing Tools? + +We wanted to use clang-format's reformatting algorithm. It's very powerful and +designed to come up with the best formatting possible. Existing tools were +created with different goals in mind, and would require extensive modifications +to convert to using clang-format's algorithm. + +### Can I Use YAPF In My Program? + +Please do! YAPF was designed to be used as a library as well as a command line +tool. This means that a tool or IDE plugin is free to use YAPF. + +### I still get non Pep8 compliant code! Why? + +YAPF tries very hard to be fully PEP 8 compliant. However, it is paramount +to not risk altering the semantics of your code. Thus, YAPF tries to be as +safe as possible and does not change the token stream +(e.g., by adding parentheses). +All these cases however, can be easily fixed manually. For instance, + +```python +from my_package import my_function_1, my_function_2, my_function_3, my_function_4, my_function_5 + +FOO = my_variable_1 + my_variable_2 + my_variable_3 + my_variable_4 + my_variable_5 + my_variable_6 + my_variable_7 + my_variable_8 + +won't be split, but you can easily get it right by just adding parentheses: + +```python +from my_package import (my_function_1, my_function_2, my_function_3, + my_function_4, my_function_5) + +FOO = (my_variable_1 + my_variable_2 + my_variable_3 + my_variable_4 + + my_variable_5 + my_variable_6 + my_variable_7 + my_variable_8) +``` + + +## Gory Details + +### Algorithm Design + +The main data structure in YAPF is the `LogicalLine` object. It holds a list +of `FormatToken`\s, that we would want to place on a single line if there +were no column limit. An exception being a comment in the middle of an +expression statement will force the line to be formatted on more than one line. +The formatter works on one `LogicalLine` object at a time. + +An `LogicalLine` typically won't affect the formatting of lines before or +after it. There is a part of the algorithm that may join two or more +`LogicalLine`\s into one line. For instance, an if-then statement with a +short body can be placed on a single line: + +```python +if a == 42: continue +``` + +YAPF's formatting algorithm creates a weighted tree that acts as the solution +space for the algorithm. Each node in the tree represents the result of a +formatting decision --- i.e., whether to split or not to split before a token. +Each formatting decision has a cost associated with it. Therefore, the cost is +realized on the edge between two nodes. (In reality, the weighted tree doesn't +have separate edge objects, so the cost resides on the nodes themselves.) + +For example, take the following Python code snippet. For the sake of this +example, assume that line (1) violates the column limit restriction and needs to +be reformatted. + +```python +def xxxxxxxxxxx(aaaaaaaaaaaa, bbbbbbbbb, cccccccc, dddddddd, eeeeee): # 1 + pass # 2 +``` + +For line (1), the algorithm will build a tree where each node (a +`FormattingDecisionState` object) is the state of the line at that token given +the decision to split before the token or not. Note: the `FormatDecisionState` +objects are copied by value so each node in the graph is unique and a change in +one doesn't affect other nodes. + +Heuristics are used to determine the costs of splitting or not splitting. +Because a node holds the state of the tree up to a token's insertion, it can +easily determine if a splitting decision will violate one of the style +requirements. For instance, the heuristic is able to apply an extra penalty to +the edge when not splitting between the previous token and the one being added. + +There are some instances where we will never want to split the line, because +doing so will always be detrimental (i.e., it will require a backslash-newline, +which is very rarely desirable). For line (1), we will never want to split the +first three tokens: `def`, `xxxxxxxxxxx`, and `(`. Nor will we want to +split between the `)` and the `:` at the end. These regions are said to be +"unbreakable." This is reflected in the tree by there not being a "split" +decision (left hand branch) within the unbreakable region. + +Now that we have the tree, we determine what the "best" formatting is by finding +the path through the tree with the lowest cost. + +And that's it! diff --git a/README.rst b/README.rst deleted file mode 100644 index 8d4e530ec..000000000 --- a/README.rst +++ /dev/null @@ -1,1023 +0,0 @@ -==== -YAPF -==== - -.. image:: https://badge.fury.io/py/yapf.svg - :target: https://badge.fury.io/py/yapf - :alt: PyPI version - -.. image:: https://github.com/google/yapf/actions/workflows/ci.yml/badge.svg - :target: https://github.com/google/yapf/actions/workflows/ci.yml - :alt: Build status - -.. image:: https://github.com/google/yapf/actions/workflows/pre-commit.yml/badge.svg - :target: https://github.com/google/yapf/actions/workflows/pre-commit.yml - :alt: Run pre-commit - -.. image:: https://coveralls.io/repos/google/yapf/badge.svg?branch=main - :target: https://coveralls.io/r/google/yapf?branch=main - :alt: Coverage status - - -Introduction -============ - -Most of the current formatters for Python --- e.g., autopep8, and pep8ify --- -are made to remove lint errors from code. This has some obvious limitations. -For instance, code that conforms to the PEP 8 guidelines may not be -reformatted. But it doesn't mean that the code looks good. - -YAPF takes a different approach. It's based off of `'clang-format' `_, developed by Daniel Jasper. In essence, -the algorithm takes the code and reformats it to the best formatting that -conforms to the style guide, even if the original code didn't violate the -style guide. The idea is also similar to the `'gofmt' `_ tool for the Go programming language: end all holy wars about -formatting - if the whole codebase of a project is simply piped through YAPF -whenever modifications are made, the style remains consistent throughout the -project and there's no point arguing about style in every code review. - -The ultimate goal is that the code YAPF produces is as good as the code that a -programmer would write if they were following the style guide. It takes away -some of the drudgery of maintaining your code. - -.. footer:: - - YAPF is not an official Google product (experimental or otherwise), it is - just code that happens to be owned by Google. - -.. contents:: - - -Installation -============ - -To install YAPF from PyPI: - -.. code-block:: shell - - $ pip install yapf - -YAPF is still considered in "alpha" stage, and the released version may change -often; therefore, the best way to keep up-to-date with the latest development -is to clone this repository. - -Note that if you intend to use YAPF as a command-line tool rather than as a -library, installation is not necessary. YAPF supports being run as a directory -by the Python interpreter. If you cloned/unzipped YAPF into ``DIR``, it's -possible to run: - -.. code-block:: shell - - $ PYTHONPATH=DIR python DIR/yapf [options] ... - - -Python versions -=============== - -YAPF supports Python 3.7+. - -YAPF requires the code it formats to be valid Python for the version YAPF itself -runs under. So if formatting 3.7 Python run YAPF under 3.7 - - -Usage -===== - -Options:: - - usage: yapf [-h] [-v] [-d | -i | -q] [-r | -l START-END] [-e PATTERN] - [--style STYLE] [--style-help] [--no-local-style] [-p] - [-vv] - [files ...] - - Formatter for Python code. - - positional arguments: - files reads from stdin when no files are specified. - - optional arguments: - -h, --help show this help message and exit - -v, --version show program's version number and exit - -d, --diff print the diff for the fixed source - -i, --in-place make changes to files in place - -q, --quiet output nothing and set return value - -r, --recursive run recursively over directories - -l START-END, --lines START-END - range of lines to reformat, one-based - -e PATTERN, --exclude PATTERN - patterns for files to exclude from formatting - --style STYLE specify formatting style: either a style name (for - example "pep8" or "google"), or the name of a file - with style settings. The default is pep8 unless a - .style.yapf or setup.cfg or pyproject.toml file - located in the same directory as the source or one - of its parent directories (for stdin, the current - directory is used). - --style-help show style settings and exit; this output can be - saved to .style.yapf to make your settings - permanent - --no-local-style don't search for local style definition - -p, --parallel run YAPF in parallel when formatting multiple - files. - -m, --print-modified print out file names of modified files - -vv, --verbose print out file names while processing - - ------------- -Return Codes ------------- - -Normally YAPF returns zero on successful program termination and non-zero otherwise. - -If ``--diff`` is supplied, YAPF returns zero when no changes were necessary, non-zero -otherwise (including program error). You can use this in a CI workflow to test that code -has been YAPF-formatted. - ---------------------------------------------------------------- -Excluding files from formatting (.yapfignore or pyproject.toml) ---------------------------------------------------------------- - -In addition to exclude patterns provided on commandline, YAPF looks for additional -patterns specified in a file named ``.yapfignore`` or ``pyproject.toml`` located in the -working directory from which YAPF is invoked. - -``.yapfignore``'s syntax is similar to UNIX's filename pattern matching:: - - * matches everything - ? matches any single character - [seq] matches any character in seq - [!seq] matches any character not in seq - -Note that no entry should begin with `./`. - -If you use ``pyproject.toml``, exclude patterns are specified by ``ignore_patterns`` key -in ``[tool.yapfignore]`` section. For example: - -.. code-block:: ini - - [tool.yapfignore] - ignore_patterns = [ - "temp/**/*.py", - "temp2/*.py" - ] - -Formatting style -================ - -The formatting style used by YAPF is configurable and there are many "knobs" -that can be used to tune how YAPF does formatting. See the ``style.py`` module -for the full list. - -To control the style, run YAPF with the ``--style`` argument. It accepts one of -the predefined styles (e.g., ``pep8`` or ``google``), a path to a configuration -file that specifies the desired style, or a dictionary of key/value pairs. - -The config file is a simple listing of (case-insensitive) ``key = value`` pairs -with a ``[style]`` heading. For example: - -.. code-block:: ini - - [style] - based_on_style = pep8 - spaces_before_comment = 4 - split_before_logical_operator = true - -The ``based_on_style`` setting determines which of the predefined styles this -custom style is based on (think of it like subclassing). Four -styles are predefined: - -- ``pep8`` (default) -- ``google`` (based off of the `Google Python Style Guide`_) -- ``yapf`` (for use with Google open source projects) -- ``facebook`` - -.. _`Google Python Style Guide`: https://github.com/google/styleguide/blob/gh-pages/pyguide.md - -See ``_STYLE_NAME_TO_FACTORY`` in style.py_ for details. - -.. _style.py: https://github.com/google/yapf/blob/main/yapf/yapflib/style.py - -It's also possible to do the same on the command line with a dictionary. For -example: - -.. code-block:: shell - - --style='{based_on_style: pep8, indent_width: 2}' - -This will take the ``pep8`` base style and modify it to have two space -indentations. - -YAPF will search for the formatting style in the following manner: - -1. Specified on the command line -2. In the ``[style]`` section of a ``.style.yapf`` file in either the current - directory or one of its parent directories. -3. In the ``[yapf]`` section of a ``setup.cfg`` file in either the current - directory or one of its parent directories. -4. In the ``[tool.yapf]`` section of a ``pyproject.toml`` file in either the current - directory or one of its parent directories. -5. In the ``[style]`` section of a ``~/.config/yapf/style`` file in your home - directory. - -If none of those files are found, the default style is used (PEP8). - - -Example -======= - -An example of the type of formatting that YAPF can do, it will take this ugly -code: - -.. code-block:: python - - x = { 'a':37,'b':42, - - 'c':927} - - y = 'hello ''world' - z = 'hello '+'world' - a = 'hello {}'.format('world') - class foo ( object ): - def f (self ): - return 37*-+2 - def g(self, x,y=42): - return y - def f ( a ) : - return 37+-+a[42-x : y**3] - -and reformat it into: - -.. code-block:: python - - x = {'a': 37, 'b': 42, 'c': 927} - - y = 'hello ' 'world' - z = 'hello ' + 'world' - a = 'hello {}'.format('world') - - - class foo(object): - def f(self): - return 37 * -+2 - - def g(self, x, y=42): - return y - - - def f(a): - return 37 + -+a[42 - x:y**3] - - -Example as a module -=================== - -The two main APIs for calling YAPF are ``FormatCode`` and ``FormatFile``, these -share several arguments which are described below: - -.. code-block:: python - - >>> from yapf.yapflib.yapf_api import FormatCode # reformat a string of code - - >>> formatted_code, changed = FormatCode("f ( a = 1, b = 2 )") - >>> formatted_code - 'f(a=1, b=2)\n' - >>> changed - True - -A ``style_config`` argument: Either a style name or a path to a file that contains -formatting style settings. If None is specified, use the default style -as set in ``style.DEFAULT_STYLE_FACTORY``. - -.. code-block:: python - - >>> FormatCode("def g():\n return True", style_config='pep8')[0] - 'def g():\n return True\n' - -A ``lines`` argument: A list of tuples of lines (ints), [start, end], -that we want to format. The lines are 1-based indexed. It can be used by -third-party code (e.g., IDEs) when reformatting a snippet of code rather -than a whole file. - -.. code-block:: python - - >>> FormatCode("def g( ):\n a=1\n b = 2\n return a==b", lines=[(1, 1), (2, 3)])[0] - 'def g():\n a = 1\n b = 2\n return a==b\n' - -A ``print_diff`` (bool): Instead of returning the reformatted source, return a -diff that turns the formatted source into reformatted source. - -.. code-block:: python - - >>> print(FormatCode("a==b", filename="foo.py", print_diff=True)[0]) - --- foo.py (original) - +++ foo.py (reformatted) - @@ -1 +1 @@ - -a==b - +a == b - -Note: the ``filename`` argument for ``FormatCode`` is what is inserted into -the diff, the default is ````. - -``FormatFile`` returns reformatted code from the passed file along with its encoding: - -.. code-block:: python - - >>> from yapf.yapflib.yapf_api import FormatFile # reformat a file - - >>> print(open("foo.py").read()) # contents of file - a==b - - >>> reformatted_code, encoding, changed = FormatFile("foo.py") - >>> formatted_code - 'a == b\n' - >>> encoding - 'utf-8' - >>> changed - True - -The ``in_place`` argument saves the reformatted code back to the file: - -.. code-block:: python - - >>> FormatFile("foo.py", in_place=True)[:2] - (None, 'utf-8') - - >>> print(open("foo.py").read()) # contents of file (now fixed) - a == b - -Formatting diffs -================ - -Options:: - - usage: yapf-diff [-h] [-i] [-p NUM] [--regex PATTERN] [--iregex PATTERN][-v] - [--style STYLE] [--binary BINARY] - - This script reads input from a unified diff and reformats all the changed - lines. This is useful to reformat all the lines touched by a specific patch. - Example usage for git/svn users: - - git diff -U0 --no-color --relative HEAD^ | yapf-diff -i - svn diff --diff-cmd=diff -x-U0 | yapf-diff -p0 -i - - It should be noted that the filename contained in the diff is used - unmodified to determine the source file to update. Users calling this script - directly should be careful to ensure that the path in the diff is correct - relative to the current working directory. - - optional arguments: - -h, --help show this help message and exit - -i, --in-place apply edits to files instead of displaying a diff - -p NUM, --prefix NUM strip the smallest prefix containing P slashes - --regex PATTERN custom pattern selecting file paths to reformat - (case sensitive, overrides -iregex) - --iregex PATTERN custom pattern selecting file paths to reformat - (case insensitive, overridden by -regex) - -v, --verbose be more verbose, ineffective without -i - --style STYLE specify formatting style: either a style name (for - example "pep8" or "google"), or the name of a file - with style settings. The default is pep8 unless a - .style.yapf or setup.cfg or pyproject.toml file - located in the same directory as the source or one of - its parent directories (for stdin, the current - directory is used). - --binary BINARY location of binary to use for YAPF - -Knobs -===== - -``ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT`` - Align closing bracket with visual indentation. - -``ALLOW_MULTILINE_LAMBDAS`` - Allow lambdas to be formatted on more than one line. - -``ALLOW_MULTILINE_DICTIONARY_KEYS`` - Allow dictionary keys to exist on multiple lines. For example: - - .. code-block:: python - - x = { - ('this is the first element of a tuple', - 'this is the second element of a tuple'): - value, - } - -``ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS`` - Allow splitting before a default / named assignment in an argument list. - -``ALLOW_SPLIT_BEFORE_DICT_VALUE`` - Allow splits before the dictionary value. - -``ARITHMETIC_PRECEDENCE_INDICATION`` - Let spacing indicate operator precedence. For example: - - .. code-block:: python - - a = 1 * 2 + 3 / 4 - b = 1 / 2 - 3 * 4 - c = (1 + 2) * (3 - 4) - d = (1 - 2) / (3 + 4) - e = 1 * 2 - 3 - f = 1 + 2 + 3 + 4 - - will be formatted as follows to indicate precedence: - - .. code-block:: python - - a = 1*2 + 3/4 - b = 1/2 - 3*4 - c = (1+2) * (3-4) - d = (1-2) / (3+4) - e = 1*2 - 3 - f = 1 + 2 + 3 + 4 - -``BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF`` - Insert a blank line before a ``def`` or ``class`` immediately nested within - another ``def`` or ``class``. For example: - - .. code-block:: python - - class Foo: - # <------ this blank line - def method(): - pass - -``BLANK_LINE_BEFORE_MODULE_DOCSTRING`` - Insert a blank line before a module docstring. - -``BLANK_LINE_BEFORE_CLASS_DOCSTRING`` - Insert a blank line before a class-level docstring. - -``BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION`` - Sets the number of desired blank lines surrounding top-level function and - class definitions. For example: - - .. code-block:: python - - class Foo: - pass - # <------ having two blank lines here - # <------ is the default setting - class Bar: - pass - -``BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES`` - Sets the number of desired blank lines between top-level imports and - variable definitions. Useful for compatibility with tools like isort. - -``COALESCE_BRACKETS`` - Do not split consecutive brackets. Only relevant when - ``DEDENT_CLOSING_BRACKETS`` or ``INDENT_CLOSING_BRACKETS`` - is set. For example: - - .. code-block:: python - - call_func_that_takes_a_dict( - { - 'key1': 'value1', - 'key2': 'value2', - } - ) - - would reformat to: - - .. code-block:: python - - call_func_that_takes_a_dict({ - 'key1': 'value1', - 'key2': 'value2', - }) - - -``COLUMN_LIMIT`` - The column limit (or max line-length) - -``CONTINUATION_ALIGN_STYLE`` - The style for continuation alignment. Possible values are: - - - ``SPACE``: Use spaces for continuation alignment. This is default - behavior. - - ``FIXED``: Use fixed number (CONTINUATION_INDENT_WIDTH) of columns - (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs or CONTINUATION_INDENT_WIDTH - spaces) for continuation alignment. - - ``VALIGN-RIGHT``: Vertically align continuation lines to multiple of - INDENT_WIDTH columns. Slightly right (one tab or a few spaces) if cannot - vertically align continuation lines with indent characters. - -``CONTINUATION_INDENT_WIDTH`` - Indent width used for line continuations. - -``DEDENT_CLOSING_BRACKETS`` - Put closing brackets on a separate line, dedented, if the bracketed - expression can't fit in a single line. Applies to all kinds of brackets, - including function definitions and calls. For example: - - .. code-block:: python - - config = { - 'key1': 'value1', - 'key2': 'value2', - } # <--- this bracket is dedented and on a separate line - - time_series = self.remote_client.query_entity_counters( - entity='dev3246.region1', - key='dns.query_latency_tcp', - transform=Transformation.AVERAGE(window=timedelta(seconds=60)), - start_ts=now()-timedelta(days=3), - end_ts=now(), - ) # <--- this bracket is dedented and on a separate line - -``DISABLE_ENDING_COMMA_HEURISTIC`` - Disable the heuristic which places each list element on a separate line if - the list is comma-terminated. - -``EACH_DICT_ENTRY_ON_SEPARATE_LINE`` - Place each dictionary entry onto its own line. - -``FORCE_MULTILINE_DICT`` - Respect EACH_DICT_ENTRY_ON_SEPARATE_LINE even if the line is shorter than - COLUMN_LIMIT. - -``I18N_COMMENT`` - The regex for an internationalization comment. The presence of this comment - stops reformatting of that line, because the comments are required to be - next to the string they translate. - -``I18N_FUNCTION_CALL`` - The internationalization function call names. The presence of this function - stops reformatting on that line, because the string it has cannot be moved - away from the i18n comment. - -``INDENT_DICTIONARY_VALUE`` - Indent the dictionary value if it cannot fit on the same line as the - dictionary key. For example: - - .. code-block:: python - - config = { - 'key1': - 'value1', - 'key2': value1 + - value2, - } - -``INDENT_WIDTH`` - The number of columns to use for indentation. - -``INDENT_BLANK_LINES`` - Set to ``True`` to prefer indented blank lines rather than empty - -``INDENT_CLOSING_BRACKETS`` - Put closing brackets on a separate line, indented, if the bracketed - expression can't fit in a single line. Applies to all kinds of brackets, - including function definitions and calls. For example: - - .. code-block:: python - - config = { - 'key1': 'value1', - 'key2': 'value2', - } # <--- this bracket is indented and on a separate line - - time_series = self.remote_client.query_entity_counters( - entity='dev3246.region1', - key='dns.query_latency_tcp', - transform=Transformation.AVERAGE(window=timedelta(seconds=60)), - start_ts=now()-timedelta(days=3), - end_ts=now(), - ) # <--- this bracket is indented and on a separate line - -``JOIN_MULTIPLE_LINES`` - Join short lines into one line. E.g., single line ``if`` statements. - -``NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS`` - Do not include spaces around selected binary operators. For example: - - .. code-block:: python - - 1 + 2 * 3 - 4 / 5 - - will be formatted as follows when configured with ``*``, ``/``: - - .. code-block:: python - - 1 + 2*3 - 4/5 - -``SPACES_AROUND_POWER_OPERATOR`` - Set to ``True`` to prefer using spaces around ``**``. - -``SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN`` - Set to ``True`` to prefer spaces around the assignment operator for default - or keyword arguments. - -``SPACES_AROUND_DICT_DELIMITERS`` - Adds a space after the opening '{' and before the ending '}' dict delimiters. - - .. code-block:: python - - {1: 2} - - will be formatted as: - - .. code-block:: python - - { 1: 2 } - -``SPACES_AROUND_LIST_DELIMITERS`` - Adds a space after the opening '[' and before the ending ']' list delimiters. - - .. code-block:: python - - [1, 2] - - will be formatted as: - - .. code-block:: python - - [ 1, 2 ] - -``SPACES_AROUND_SUBSCRIPT_COLON`` - Use spaces around the subscript / slice operator. For example: - - .. code-block:: python - - my_list[1 : 10 : 2] - -``SPACES_AROUND_TUPLE_DELIMITERS`` - Adds a space after the opening '(' and before the ending ')' tuple delimiters. - - .. code-block:: python - - (1, 2, 3) - - will be formatted as: - - .. code-block:: python - - ( 1, 2, 3 ) - -``SPACES_BEFORE_COMMENT`` - The number of spaces required before a trailing comment. - This can be a single value (representing the number of spaces - before each trailing comment) or list of values (representing - alignment column values; trailing comments within a block will - be aligned to the first column value that is greater than the maximum - line length within the block). - - **Note:** Lists of values may need to be quoted in some contexts - (eg. shells or editor config files). - - For example: - - With ``spaces_before_comment=5``: - - .. code-block:: python - - 1 + 1 # Adding values - - will be formatted as: - - .. code-block:: python - - 1 + 1 # Adding values <-- 5 spaces between the end of the statement and comment - - With ``spaces_before_comment="15, 20"``: - - .. code-block:: python - - 1 + 1 # Adding values - two + two # More adding - - longer_statement # This is a longer statement - short # This is a shorter statement - - a_very_long_statement_that_extends_beyond_the_final_column # Comment - short # This is a shorter statement - - will be formatted as: - - .. code-block:: python - - 1 + 1 # Adding values <-- end of line comments in block aligned to col 15 - two + two # More adding - - longer_statement # This is a longer statement <-- end of line comments in block aligned to col 20 - short # This is a shorter statement - - a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length - short # This is a shorter statement - -``SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET`` - Insert a space between the ending comma and closing bracket of a list, etc. - -``SPACE_INSIDE_BRACKETS`` - Use spaces inside brackets, braces, and parentheses. For example: - - .. code-block:: python - - method_call( 1 ) - my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] - my_set = { 1, 2, 3 } - -``SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED`` - Split before arguments if the argument list is terminated by a comma. - -``SPLIT_ALL_COMMA_SEPARATED_VALUES`` - If a comma separated list (``dict``, ``list``, ``tuple``, or function - ``def``) is on a line that is too long, split such that each element - is on a separate line. - -``SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES`` - Variation on ``SPLIT_ALL_COMMA_SEPARATED_VALUES`` in which, if a - subexpression with a comma fits in its starting line, then the - subexpression is not split. This avoids splits like the one for - ``b`` in this code: - - .. code-block:: python - - abcdef( - aReallyLongThing: int, - b: [Int, - Int]) - - With the new knob this is split as: - - .. code-block:: python - - abcdef( - aReallyLongThing: int, - b: [Int, Int]) - -``SPLIT_BEFORE_BITWISE_OPERATOR`` - Set to ``True`` to prefer splitting before ``&``, ``|`` or ``^`` rather - than after. - -``SPLIT_BEFORE_ARITHMETIC_OPERATOR`` - Set to ``True`` to prefer splitting before ``+``, ``-``, ``*``, ``/``, ``//``, - or ``@`` rather than after. - -``SPLIT_BEFORE_CLOSING_BRACKET`` - Split before the closing bracket if a ``list`` or ``dict`` literal doesn't - fit on a single line. - -``SPLIT_BEFORE_DICT_SET_GENERATOR`` - Split before a dictionary or set generator (comp_for). For example, note - the split before the ``for``: - - .. code-block:: python - - foo = { - variable: 'Hello world, have a nice day!' - for variable in bar if variable != 42 - } - -``SPLIT_BEFORE_DOT`` - Split before the ``.`` if we need to split a longer expression: - - .. code-block:: python - - foo = ('This is a really long string: {}, {}, {}, {}'.format(a, b, c, d)) - - would reformat to something like: - - .. code-block:: python - - foo = ('This is a really long string: {}, {}, {}, {}' - .format(a, b, c, d)) - -``SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN`` - Split after the opening paren which surrounds an expression if it doesn't - fit on a single line. - -``SPLIT_BEFORE_FIRST_ARGUMENT`` - If an argument / parameter list is going to be split, then split before the - first argument. - -``SPLIT_BEFORE_LOGICAL_OPERATOR`` - Set to ``True`` to prefer splitting before ``and`` or ``or`` rather than - after. - -``SPLIT_BEFORE_NAMED_ASSIGNS`` - Split named assignments onto individual lines. - -``SPLIT_COMPLEX_COMPREHENSION`` - For list comprehensions and generator expressions with multiple clauses - (e.g multiple ``for`` calls, ``if`` filter expressions) and which need to - be reflowed, split each clause onto its own line. For example: - - .. code-block:: python - - result = [ - a_var + b_var for a_var in xrange(1000) for b_var in xrange(1000) - if a_var % b_var] - - would reformat to something like: - - .. code-block:: python - - result = [ - a_var + b_var - for a_var in xrange(1000) - for b_var in xrange(1000) - if a_var % b_var] - -``SPLIT_PENALTY_AFTER_OPENING_BRACKET`` - The penalty for splitting right after the opening bracket. - -``SPLIT_PENALTY_AFTER_UNARY_OPERATOR`` - The penalty for splitting the line after a unary operator. - -``SPLIT_PENALTY_ARITHMETIC_OPERATOR`` - The penalty of splitting the line around the ``+``, ``-``, ``*``, ``/``, - ``//``, ``%``, and ``@`` operators. - -``SPLIT_PENALTY_BEFORE_IF_EXPR`` - The penalty for splitting right before an ``if`` expression. - -``SPLIT_PENALTY_BITWISE_OPERATOR`` - The penalty of splitting the line around the ``&``, ``|``, and ``^`` - operators. - -``SPLIT_PENALTY_COMPREHENSION`` - The penalty for splitting a list comprehension or generator expression. - -``SPLIT_PENALTY_EXCESS_CHARACTER`` - The penalty for characters over the column limit. - -``SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT`` - The penalty incurred by adding a line split to the logical line. The more - line splits added the higher the penalty. - -``SPLIT_PENALTY_IMPORT_NAMES`` - The penalty of splitting a list of ``import as`` names. For example: - - .. code-block:: python - - from a_very_long_or_indented_module_name_yada_yad import (long_argument_1, - long_argument_2, - long_argument_3) - - would reformat to something like: - - .. code-block:: python - - from a_very_long_or_indented_module_name_yada_yad import ( - long_argument_1, long_argument_2, long_argument_3) - -``SPLIT_PENALTY_LOGICAL_OPERATOR`` - The penalty of splitting the line around the ``and`` and ``or`` operators. - -``USE_TABS`` - Use the Tab character for indentation. - -(Potentially) Frequently Asked Questions -======================================== - --------------------------------------------- -Why does YAPF destroy my awesome formatting? --------------------------------------------- - -YAPF tries very hard to get the formatting correct. But for some code, it won't -be as good as hand-formatting. In particular, large data literals may become -horribly disfigured under YAPF. - -The reasons for this are manyfold. In short, YAPF is simply a tool to help -with development. It will format things to coincide with the style guide, but -that may not equate with readability. - -What can be done to alleviate this situation is to indicate regions YAPF should -ignore when reformatting something: - -.. code-block:: python - - # yapf: disable - FOO = { - # ... some very large, complex data literal. - } - - BAR = [ - # ... another large data literal. - ] - # yapf: enable - -You can also disable formatting for a single literal like this: - -.. code-block:: python - - BAZ = { - (1, 2, 3, 4), - (5, 6, 7, 8), - (9, 10, 11, 12), - } # yapf: disable - -To preserve the nice dedented closing brackets, use the -``dedent_closing_brackets`` in your style. Note that in this case all -brackets, including function definitions and calls, are going to use -that style. This provides consistency across the formatted codebase. - -------------------------------- -Why Not Improve Existing Tools? -------------------------------- - -We wanted to use clang-format's reformatting algorithm. It's very powerful and -designed to come up with the best formatting possible. Existing tools were -created with different goals in mind, and would require extensive modifications -to convert to using clang-format's algorithm. - ------------------------------ -Can I Use YAPF In My Program? ------------------------------ - -Please do! YAPF was designed to be used as a library as well as a command line -tool. This means that a tool or IDE plugin is free to use YAPF. - ------------------------------------------ -I still get non Pep8 compliant code! Why? ------------------------------------------ - -YAPF tries very hard to be fully PEP 8 compliant. However, it is paramount -to not risk altering the semantics of your code. Thus, YAPF tries to be as -safe as possible and does not change the token stream -(e.g., by adding parentheses). -All these cases however, can be easily fixed manually. For instance, - -.. code-block:: python - - from my_package import my_function_1, my_function_2, my_function_3, my_function_4, my_function_5 - - FOO = my_variable_1 + my_variable_2 + my_variable_3 + my_variable_4 + my_variable_5 + my_variable_6 + my_variable_7 + my_variable_8 - -won't be split, but you can easily get it right by just adding parentheses: - -.. code-block:: python - - from my_package import (my_function_1, my_function_2, my_function_3, - my_function_4, my_function_5) - - FOO = (my_variable_1 + my_variable_2 + my_variable_3 + my_variable_4 + - my_variable_5 + my_variable_6 + my_variable_7 + my_variable_8) - -Gory Details -============ - ----------------- -Algorithm Design ----------------- - -The main data structure in YAPF is the ``LogicalLine`` object. It holds a list -of ``FormatToken``\s, that we would want to place on a single line if there -were no column limit. An exception being a comment in the middle of an -expression statement will force the line to be formatted on more than one line. -The formatter works on one ``LogicalLine`` object at a time. - -An ``LogicalLine`` typically won't affect the formatting of lines before or -after it. There is a part of the algorithm that may join two or more -``LogicalLine``\s into one line. For instance, an if-then statement with a -short body can be placed on a single line: - -.. code-block:: python - - if a == 42: continue - -YAPF's formatting algorithm creates a weighted tree that acts as the solution -space for the algorithm. Each node in the tree represents the result of a -formatting decision --- i.e., whether to split or not to split before a token. -Each formatting decision has a cost associated with it. Therefore, the cost is -realized on the edge between two nodes. (In reality, the weighted tree doesn't -have separate edge objects, so the cost resides on the nodes themselves.) - -For example, take the following Python code snippet. For the sake of this -example, assume that line (1) violates the column limit restriction and needs to -be reformatted. - -.. code-block:: python - - def xxxxxxxxxxx(aaaaaaaaaaaa, bbbbbbbbb, cccccccc, dddddddd, eeeeee): # 1 - pass # 2 - -For line (1), the algorithm will build a tree where each node (a -``FormattingDecisionState`` object) is the state of the line at that token given -the decision to split before the token or not. Note: the ``FormatDecisionState`` -objects are copied by value so each node in the graph is unique and a change in -one doesn't affect other nodes. - -Heuristics are used to determine the costs of splitting or not splitting. -Because a node holds the state of the tree up to a token's insertion, it can -easily determine if a splitting decision will violate one of the style -requirements. For instance, the heuristic is able to apply an extra penalty to -the edge when not splitting between the previous token and the one being added. - -There are some instances where we will never want to split the line, because -doing so will always be detrimental (i.e., it will require a backslash-newline, -which is very rarely desirable). For line (1), we will never want to split the -first three tokens: ``def``, ``xxxxxxxxxxx``, and ``(``. Nor will we want to -split between the ``)`` and the ``:`` at the end. These regions are said to be -"unbreakable." This is reflected in the tree by there not being a "split" -decision (left hand branch) within the unbreakable region. - -Now that we have the tree, we determine what the "best" formatting is by finding -the path through the tree with the lowest cost. - -And that's it! From 31dd8ac46d9c839d73ee385a37d79880df1f4ea7 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 13 Jun 2023 18:00:54 -0500 Subject: [PATCH 628/719] Fix code block indentations --- README.md | 385 +++++++++++++++++++++++++++--------------------------- 1 file changed, 192 insertions(+), 193 deletions(-) diff --git a/README.md b/README.md index 74b6a4225..96dfc1337 100644 --- a/README.md +++ b/README.md @@ -321,7 +321,7 @@ a == b Options: -``` +```console usage: yapf-diff [-h] [-i] [-p NUM] [--regex PATTERN] [--iregex PATTERN][-v] [--style STYLE] [--binary BINARY] @@ -371,13 +371,13 @@ optional arguments: Allow dictionary keys to exist on multiple lines. For example: - ```python - x = { - ('this is the first element of a tuple', - 'this is the second element of a tuple'): - value, - } - ``` + ```python + x = { + ('this is the first element of a tuple', + 'this is the second element of a tuple'): + value, + } + ``` `ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS` @@ -391,37 +391,37 @@ optional arguments: Let spacing indicate operator precedence. For example: - ```python - a = 1 * 2 + 3 / 4 - b = 1 / 2 - 3 * 4 - c = (1 + 2) * (3 - 4) - d = (1 - 2) / (3 + 4) - e = 1 * 2 - 3 - f = 1 + 2 + 3 + 4 - ``` + ```python + a = 1 * 2 + 3 / 4 + b = 1 / 2 - 3 * 4 + c = (1 + 2) * (3 - 4) + d = (1 - 2) / (3 + 4) + e = 1 * 2 - 3 + f = 1 + 2 + 3 + 4 + ``` will be formatted as follows to indicate precedence: - ```python - a = 1*2 + 3/4 - b = 1/2 - 3*4 - c = (1+2) * (3-4) - d = (1-2) / (3+4) - e = 1*2 - 3 - f = 1 + 2 + 3 + 4 - ``` + ```python + a = 1*2 + 3/4 + b = 1/2 - 3*4 + c = (1+2) * (3-4) + d = (1-2) / (3+4) + e = 1*2 - 3 + f = 1 + 2 + 3 + 4 + ``` `BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF` Insert a blank line before a `def` or `class` immediately nested within another `def` or `class`. For example: - ```python - class Foo: - # <------ this blank line - def method(): - pass - ``` + ```python + class Foo: + # <------ this blank line + def method(): + pass + ``` `BLANK_LINE_BEFORE_MODULE_DOCSTRING` @@ -436,14 +436,14 @@ optional arguments: Sets the number of desired blank lines surrounding top-level function and class definitions. For example: - ```python - class Foo: - pass - # <------ having two blank lines here - # <------ is the default setting - class Bar: - pass - ``` + ```python + class Foo: + pass + # <------ having two blank lines here + # <------ is the default setting + class Bar: + pass + ``` `BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES` @@ -455,24 +455,23 @@ optional arguments: Do not split consecutive brackets. Only relevant when `DEDENT_CLOSING_BRACKETS` or `INDENT_CLOSING_BRACKETS` is set. For example: - ```python - call_func_that_takes_a_dict( - { - 'key1': 'value1', - 'key2': 'value2', - } - ) - ``` - + ```python + call_func_that_takes_a_dict( + { + 'key1': 'value1', + 'key2': 'value2', + } + ) + ``` + would reformat to: - ```python - call_func_that_takes_a_dict({ - 'key1': 'value1', - 'key2': 'value2', - }) - ``` - + ```python + call_func_that_takes_a_dict({ + 'key1': 'value1', + 'key2': 'value2', + }) + ``` `COLUMN_LIMIT` @@ -501,20 +500,20 @@ optional arguments: expression can't fit in a single line. Applies to all kinds of brackets, including function definitions and calls. For example: - ```python - config = { - 'key1': 'value1', - 'key2': 'value2', - } # <--- this bracket is dedented and on a separate line - - time_series = self.remote_client.query_entity_counters( - entity='dev3246.region1', - key='dns.query_latency_tcp', - transform=Transformation.AVERAGE(window=timedelta(seconds=60)), - start_ts=now()-timedelta(days=3), - end_ts=now(), - ) # <--- this bracket is dedented and on a separate line - ``` + ```python + config = { + 'key1': 'value1', + 'key2': 'value2', + } # <--- this bracket is dedented and on a separate line + + time_series = self.remote_client.query_entity_counters( + entity='dev3246.region1', + key='dns.query_latency_tcp', + transform=Transformation.AVERAGE(window=timedelta(seconds=60)), + start_ts=now()-timedelta(days=3), + end_ts=now(), + ) # <--- this bracket is dedented and on a separate line + ``` `DISABLE_ENDING_COMMA_HEURISTIC` @@ -547,14 +546,14 @@ optional arguments: Indent the dictionary value if it cannot fit on the same line as the dictionary key. For example: - ```python - config = { - 'key1': - 'value1', - 'key2': value1 + - value2, - } - ``` + ```python + config = { + 'key1': + 'value1', + 'key2': value1 + + value2, + } + ``` `INDENT_WIDTH` @@ -570,20 +569,20 @@ optional arguments: expression can't fit in a single line. Applies to all kinds of brackets, including function definitions and calls. For example: - ```python - config = { - 'key1': 'value1', - 'key2': 'value2', - } # <--- this bracket is indented and on a separate line - - time_series = self.remote_client.query_entity_counters( - entity='dev3246.region1', - key='dns.query_latency_tcp', - transform=Transformation.AVERAGE(window=timedelta(seconds=60)), - start_ts=now()-timedelta(days=3), - end_ts=now(), - ) # <--- this bracket is indented and on a separate line - ``` + ```python + config = { + 'key1': 'value1', + 'key2': 'value2', + } # <--- this bracket is indented and on a separate line + + time_series = self.remote_client.query_entity_counters( + entity='dev3246.region1', + key='dns.query_latency_tcp', + transform=Transformation.AVERAGE(window=timedelta(seconds=60)), + start_ts=now()-timedelta(days=3), + end_ts=now(), + ) # <--- this bracket is indented and on a separate line + ``` `JOIN_MULTIPLE_LINES` @@ -593,15 +592,15 @@ optional arguments: Do not include spaces around selected binary operators. For example: - ```python - 1 + 2 * 3 - 4 / 5 - ``` + ```python + 1 + 2 * 3 - 4 / 5 + ``` will be formatted as follows when configured with `*`, `/`: - ```python - 1 + 2*3 - 4/5 - ``` + ```python + 1 + 2*3 - 4/5 + ``` `SPACES_AROUND_POWER_OPERATOR` @@ -616,51 +615,51 @@ optional arguments: Adds a space after the opening '{' and before the ending '}' dict delimiters. - ```python - {1: 2} - ``` + ```python + {1: 2} + ``` will be formatted as: - ```python - { 1: 2 } - ``` + ```python + { 1: 2 } + ``` `SPACES_AROUND_LIST_DELIMITERS` Adds a space after the opening '[' and before the ending ']' list delimiters. - ```python - [1, 2] - ``` + ```python + [1, 2] + ``` will be formatted as: - ```python - [ 1, 2 ] - ``` + ```python + [ 1, 2 ] + ``` `SPACES_AROUND_SUBSCRIPT_COLON` Use spaces around the subscript / slice operator. For example: - ```python - my_list[1 : 10 : 2] - ``` + ```python + my_list[1 : 10 : 2] + ``` `SPACES_AROUND_TUPLE_DELIMITERS` Adds a space after the opening '(' and before the ending ')' tuple delimiters. - ```python - (1, 2, 3) - ``` + ```python + (1, 2, 3) + ``` will be formatted as: - ```python - ( 1, 2, 3 ) - ``` + ```python + ( 1, 2, 3 ) + ``` `SPACES_BEFORE_COMMENT` @@ -676,41 +675,41 @@ optional arguments: For example, with `spaces_before_comment=5`: - ```python - 1 + 1 # Adding values - ``` + ```python + 1 + 1 # Adding values + ``` will be formatted as: - ```python - 1 + 1 # Adding values <-- 5 spaces between the end of the statement and comment - ``` + ```python + 1 + 1 # Adding values <-- 5 spaces between the end of the statement and comment + ``` with `spaces_before_comment="15, 20"`: - ```python - 1 + 1 # Adding values - two + two # More adding - - longer_statement # This is a longer statement - short # This is a shorter statement - - a_very_long_statement_that_extends_beyond_the_final_column # Comment - short # This is a shorter statement - ``` + ```python + 1 + 1 # Adding values + two + two # More adding + + longer_statement # This is a longer statement + short # This is a shorter statement + + a_very_long_statement_that_extends_beyond_the_final_column # Comment + short # This is a shorter statement + ``` will be formatted as: - ```python - 1 + 1 # Adding values <-- end of line comments in block aligned to col 15 - two + two # More adding - - longer_statement # This is a longer statement <-- end of line comments in block aligned to col 20 - short # This is a shorter statement - - a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length - short # This is a shorter statement - ``` + ```python + 1 + 1 # Adding values <-- end of line comments in block aligned to col 15 + two + two # More adding + + longer_statement # This is a longer statement <-- end of line comments in block aligned to col 20 + short # This is a shorter statement + + a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length + short # This is a shorter statement + ``` `SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET` @@ -720,11 +719,11 @@ optional arguments: Use spaces inside brackets, braces, and parentheses. For example: - ``` - method_call( 1 ) - my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] - my_set = { 1, 2, 3 } - ``` + ``` + method_call( 1 ) + my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] + my_set = { 1, 2, 3 } + ``` `SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED` @@ -743,20 +742,20 @@ optional arguments: subexpression is not split. This avoids splits like the one for `b` in this code: - ```python - abcdef( - aReallyLongThing: int, - b: [Int, - Int]) - ``` + ```python + abcdef( + aReallyLongThing: int, + b: [Int, + Int]) + ``` with the new knob this is split as: - ```python - abcdef( - aReallyLongThing: int, - b: [Int, Int]) - ``` + ```python + abcdef( + aReallyLongThing: int, + b: [Int, Int]) + ``` `SPLIT_BEFORE_BITWISE_OPERATOR` @@ -777,27 +776,27 @@ optional arguments: Split before a dictionary or set generator (`comp_for`). For example, note the split before the `for`: - ```python - foo = { - variable: 'Hello world, have a nice day!' - for variable in bar if variable != 42 - } - ``` + ```python + foo = { + variable: 'Hello world, have a nice day!' + for variable in bar if variable != 42 + } + ``` `SPLIT_BEFORE_DOT` Split before the `.` if we need to split a longer expression: - ```python - foo = ('This is a really long string: {}, {}, {}, {}'.format(a, b, c, d)) - ``` + ```python + foo = ('This is a really long string: {}, {}, {}, {}'.format(a, b, c, d)) + ``` would reformat to something like: - ```python - foo = ('This is a really long string: {}, {}, {}, {}' - .format(a, b, c, d)) - ``` + ```python + foo = ('This is a really long string: {}, {}, {}, {}' + .format(a, b, c, d)) + ``` `SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN` @@ -823,21 +822,21 @@ optional arguments: (e.g multiple `for` calls, `if` filter expressions) and which need to be reflowed, split each clause onto its own line. For example: - ```python - result = [ - a_var + b_var for a_var in xrange(1000) for b_var in xrange(1000) - if a_var % b_var] - ``` + ```python + result = [ + a_var + b_var for a_var in xrange(1000) for b_var in xrange(1000) + if a_var % b_var] + ``` would reformat to something like: - ```python - result = [ - a_var + b_var - for a_var in xrange(1000) - for b_var in xrange(1000) - if a_var % b_var] - ``` + ```python + result = [ + a_var + b_var + for a_var in xrange(1000) + for b_var in xrange(1000) + if a_var % b_var] + ``` `SPLIT_PENALTY_AFTER_OPENING_BRACKET` @@ -877,18 +876,18 @@ optional arguments: The penalty of splitting a list of `import as` names. For example: - ```python - from a_very_long_or_indented_module_name_yada_yad import (long_argument_1, - long_argument_2, - long_argument_3) - ``` + ```python + from a_very_long_or_indented_module_name_yada_yad import (long_argument_1, + long_argument_2, + long_argument_3) + ``` would reformat to something like: - ```python - from a_very_long_or_indented_module_name_yada_yad import ( - long_argument_1, long_argument_2, long_argument_3) - ``` + ```python + from a_very_long_or_indented_module_name_yada_yad import ( + long_argument_1, long_argument_2, long_argument_3) + ``` `SPLIT_PENALTY_LOGICAL_OPERATOR` From 60d23f8180c1c61fdc9341cbfce1195bd296d169 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 13 Jun 2023 18:11:53 -0500 Subject: [PATCH 629/719] Fix code block indentations--second attempt --- README.md | 132 +++++++++++++++++++++++++++--------------------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index 96dfc1337..ddf14a441 100644 --- a/README.md +++ b/README.md @@ -371,13 +371,13 @@ optional arguments: Allow dictionary keys to exist on multiple lines. For example: - ```python +```python x = { ('this is the first element of a tuple', 'this is the second element of a tuple'): value, } - ``` +``` `ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS` @@ -391,37 +391,37 @@ optional arguments: Let spacing indicate operator precedence. For example: - ```python +```python a = 1 * 2 + 3 / 4 b = 1 / 2 - 3 * 4 c = (1 + 2) * (3 - 4) d = (1 - 2) / (3 + 4) e = 1 * 2 - 3 f = 1 + 2 + 3 + 4 - ``` +``` will be formatted as follows to indicate precedence: - ```python +```python a = 1*2 + 3/4 b = 1/2 - 3*4 c = (1+2) * (3-4) d = (1-2) / (3+4) e = 1*2 - 3 f = 1 + 2 + 3 + 4 - ``` +``` `BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF` Insert a blank line before a `def` or `class` immediately nested within another `def` or `class`. For example: - ```python +```python class Foo: # <------ this blank line def method(): pass - ``` +``` `BLANK_LINE_BEFORE_MODULE_DOCSTRING` @@ -436,14 +436,14 @@ optional arguments: Sets the number of desired blank lines surrounding top-level function and class definitions. For example: - ```python +```python class Foo: pass # <------ having two blank lines here # <------ is the default setting class Bar: pass - ``` +``` `BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES` @@ -455,23 +455,23 @@ optional arguments: Do not split consecutive brackets. Only relevant when `DEDENT_CLOSING_BRACKETS` or `INDENT_CLOSING_BRACKETS` is set. For example: - ```python +```python call_func_that_takes_a_dict( { 'key1': 'value1', 'key2': 'value2', } ) - ``` +``` would reformat to: - ```python +```python call_func_that_takes_a_dict({ 'key1': 'value1', 'key2': 'value2', }) - ``` +``` `COLUMN_LIMIT` @@ -500,7 +500,7 @@ optional arguments: expression can't fit in a single line. Applies to all kinds of brackets, including function definitions and calls. For example: - ```python +```python config = { 'key1': 'value1', 'key2': 'value2', @@ -513,7 +513,7 @@ optional arguments: start_ts=now()-timedelta(days=3), end_ts=now(), ) # <--- this bracket is dedented and on a separate line - ``` +``` `DISABLE_ENDING_COMMA_HEURISTIC` @@ -546,14 +546,14 @@ optional arguments: Indent the dictionary value if it cannot fit on the same line as the dictionary key. For example: - ```python +```python config = { 'key1': 'value1', 'key2': value1 + value2, } - ``` +``` `INDENT_WIDTH` @@ -569,7 +569,7 @@ optional arguments: expression can't fit in a single line. Applies to all kinds of brackets, including function definitions and calls. For example: - ```python +```python config = { 'key1': 'value1', 'key2': 'value2', @@ -582,7 +582,7 @@ optional arguments: start_ts=now()-timedelta(days=3), end_ts=now(), ) # <--- this bracket is indented and on a separate line - ``` +``` `JOIN_MULTIPLE_LINES` @@ -592,15 +592,15 @@ optional arguments: Do not include spaces around selected binary operators. For example: - ```python +```python 1 + 2 * 3 - 4 / 5 - ``` +``` will be formatted as follows when configured with `*`, `/`: - ```python +```python 1 + 2*3 - 4/5 - ``` +``` `SPACES_AROUND_POWER_OPERATOR` @@ -615,51 +615,51 @@ optional arguments: Adds a space after the opening '{' and before the ending '}' dict delimiters. - ```python +```python {1: 2} - ``` +``` will be formatted as: - ```python +```python { 1: 2 } - ``` +``` `SPACES_AROUND_LIST_DELIMITERS` Adds a space after the opening '[' and before the ending ']' list delimiters. - ```python +```python [1, 2] - ``` +``` will be formatted as: - ```python +```python [ 1, 2 ] - ``` +``` `SPACES_AROUND_SUBSCRIPT_COLON` Use spaces around the subscript / slice operator. For example: - ```python +```python my_list[1 : 10 : 2] - ``` +``` `SPACES_AROUND_TUPLE_DELIMITERS` Adds a space after the opening '(' and before the ending ')' tuple delimiters. - ```python +```python (1, 2, 3) - ``` +``` will be formatted as: - ```python +```python ( 1, 2, 3 ) - ``` +``` `SPACES_BEFORE_COMMENT` @@ -675,19 +675,19 @@ optional arguments: For example, with `spaces_before_comment=5`: - ```python +```python 1 + 1 # Adding values - ``` +``` will be formatted as: - ```python +```python 1 + 1 # Adding values <-- 5 spaces between the end of the statement and comment - ``` +``` with `spaces_before_comment="15, 20"`: - ```python +```python 1 + 1 # Adding values two + two # More adding @@ -696,11 +696,11 @@ optional arguments: a_very_long_statement_that_extends_beyond_the_final_column # Comment short # This is a shorter statement - ``` +``` will be formatted as: - ```python +```python 1 + 1 # Adding values <-- end of line comments in block aligned to col 15 two + two # More adding @@ -709,7 +709,7 @@ optional arguments: a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length short # This is a shorter statement - ``` +``` `SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET` @@ -719,11 +719,11 @@ optional arguments: Use spaces inside brackets, braces, and parentheses. For example: - ``` +``` method_call( 1 ) my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] my_set = { 1, 2, 3 } - ``` +``` `SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED` @@ -742,20 +742,20 @@ optional arguments: subexpression is not split. This avoids splits like the one for `b` in this code: - ```python +```python abcdef( aReallyLongThing: int, b: [Int, Int]) - ``` +``` with the new knob this is split as: - ```python +```python abcdef( aReallyLongThing: int, b: [Int, Int]) - ``` +``` `SPLIT_BEFORE_BITWISE_OPERATOR` @@ -776,27 +776,27 @@ optional arguments: Split before a dictionary or set generator (`comp_for`). For example, note the split before the `for`: - ```python +```python foo = { variable: 'Hello world, have a nice day!' for variable in bar if variable != 42 } - ``` +``` `SPLIT_BEFORE_DOT` Split before the `.` if we need to split a longer expression: - ```python +```python foo = ('This is a really long string: {}, {}, {}, {}'.format(a, b, c, d)) - ``` +``` would reformat to something like: - ```python +```python foo = ('This is a really long string: {}, {}, {}, {}' .format(a, b, c, d)) - ``` +``` `SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN` @@ -822,21 +822,21 @@ optional arguments: (e.g multiple `for` calls, `if` filter expressions) and which need to be reflowed, split each clause onto its own line. For example: - ```python +```python result = [ a_var + b_var for a_var in xrange(1000) for b_var in xrange(1000) if a_var % b_var] - ``` +``` would reformat to something like: - ```python +```python result = [ a_var + b_var for a_var in xrange(1000) for b_var in xrange(1000) if a_var % b_var] - ``` +``` `SPLIT_PENALTY_AFTER_OPENING_BRACKET` @@ -876,18 +876,18 @@ optional arguments: The penalty of splitting a list of `import as` names. For example: - ```python +```python from a_very_long_or_indented_module_name_yada_yad import (long_argument_1, long_argument_2, long_argument_3) - ``` +``` would reformat to something like: - ```python +```python from a_very_long_or_indented_module_name_yada_yad import ( long_argument_1, long_argument_2, long_argument_3) - ``` +``` `SPLIT_PENALTY_LOGICAL_OPERATOR` From 27f8a9070c218e4ca13044f35b5ed5fd2c29923e Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 13 Jun 2023 18:17:06 -0500 Subject: [PATCH 630/719] Change README filename --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 7884cc963..4f04d194a 100644 --- a/setup.py +++ b/setup.py @@ -39,7 +39,7 @@ def run(self): sys.exit(0 if results.wasSuccessful() else 1) -with codecs.open('README.rst', 'r', 'utf-8') as fd: +with codecs.open('README.md', 'r', 'utf-8') as fd: setup( name='yapf', version='0.40.0', From 9898e3032534e72f48821e4c74874e845edbb544 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 13 Jun 2023 18:19:20 -0500 Subject: [PATCH 631/719] Fix links to CI images --- README.md | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index ddf14a441..efa1513d8 100644 --- a/README.md +++ b/README.md @@ -2,20 +2,12 @@

PyPI Version -Build Status -Actions Status +Build Status +Actions Status Coverage Status

----- - -- TOC -{:toc} - ----- - - ## Introduction YAPF is a Python formatter based off of [`clang-format`](https://clang.llvm.org/docs/ClangFormat.html) @@ -952,7 +944,7 @@ to convert to using clang-format's algorithm. Please do! YAPF was designed to be used as a library as well as a command line tool. This means that a tool or IDE plugin is free to use YAPF. -### I still get non Pep8 compliant code! Why? +### I still get non-PEP8 compliant code! Why? YAPF tries very hard to be fully PEP 8 compliant. However, it is paramount to not risk altering the semantics of your code. Thus, YAPF tries to be as @@ -964,6 +956,7 @@ All these cases however, can be easily fixed manually. For instance, from my_package import my_function_1, my_function_2, my_function_3, my_function_4, my_function_5 FOO = my_variable_1 + my_variable_2 + my_variable_3 + my_variable_4 + my_variable_5 + my_variable_6 + my_variable_7 + my_variable_8 +``` won't be split, but you can easily get it right by just adding parentheses: From 4fecfd544f1f5cc23b145e67cbbb3c97197c1b26 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 13 Jun 2023 18:21:52 -0500 Subject: [PATCH 632/719] Fix trailing spaces --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index efa1513d8..9a95fc71a 100644 --- a/README.md +++ b/README.md @@ -455,7 +455,7 @@ optional arguments: } ) ``` - + would reformat to: ```python @@ -497,7 +497,7 @@ optional arguments: 'key1': 'value1', 'key2': 'value2', } # <--- this bracket is dedented and on a separate line - + time_series = self.remote_client.query_entity_counters( entity='dev3246.region1', key='dns.query_latency_tcp', @@ -566,7 +566,7 @@ optional arguments: 'key1': 'value1', 'key2': 'value2', } # <--- this bracket is indented and on a separate line - + time_series = self.remote_client.query_entity_counters( entity='dev3246.region1', key='dns.query_latency_tcp', @@ -682,10 +682,10 @@ optional arguments: ```python 1 + 1 # Adding values two + two # More adding - + longer_statement # This is a longer statement short # This is a shorter statement - + a_very_long_statement_that_extends_beyond_the_final_column # Comment short # This is a shorter statement ``` @@ -695,10 +695,10 @@ optional arguments: ```python 1 + 1 # Adding values <-- end of line comments in block aligned to col 15 two + two # More adding - + longer_statement # This is a longer statement <-- end of line comments in block aligned to col 20 short # This is a shorter statement - + a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length short # This is a shorter statement ``` @@ -711,7 +711,7 @@ optional arguments: Use spaces inside brackets, braces, and parentheses. For example: -``` +```python method_call( 1 ) my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] my_set = { 1, 2, 3 } From 3875a6df908e6a8837958eaa9fc2b7028e21a880 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 13 Jun 2023 18:22:53 -0500 Subject: [PATCH 633/719] Move us to 'beta' stage now --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9a95fc71a..7b41e82bf 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ To install YAPF from PyPI: $ pip install yapf ``` -YAPF is still considered in "alpha" stage, and the released version may change +YAPF is still considered in "beta" stage, and the released version may change often; therefore, the best way to keep up-to-date with the latest development is to clone this repository. From 8053a77f22f09ffa6bc3c491874634dbf46602c3 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 13 Jun 2023 18:28:23 -0500 Subject: [PATCH 634/719] Convert to MarkDown --- CONTRIBUTING.rst => CONTRIBUTING.md | 30 ++++++++++++++--------------- MANIFEST.in | 2 +- 2 files changed, 15 insertions(+), 17 deletions(-) rename CONTRIBUTING.rst => CONTRIBUTING.md (69%) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.md similarity index 69% rename from CONTRIBUTING.rst rename to CONTRIBUTING.md index fa6cda064..a15c350fe 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.md @@ -1,12 +1,13 @@ -Want to contribute? Great! First, read this page (including the small print at the end). +# How to Contribute -Before you contribute ---------------------- +Want to contribute? Great! First, read this page (including the small print at +the end). -Before we can use your code, you must sign the `Google Individual Contributor -License Agreement -`_ (CLA), which -you can do online. The CLA is necessary mainly because you own the +## Before you contribute + +Before we can use your code, you must sign the [Google Individual Contributor +License Agreement](https://developers.google.com/open-source/cla/individual?csw=1) +(CLA), which you can do online. The CLA is necessary mainly because you own the copyright to your changes, even after your contribution becomes part of our codebase, so we need your permission to use and distribute your code. We also need to be sure of various other things—for instance that you'll tell us if you @@ -18,26 +19,23 @@ us first through the issue tracker with your idea so that we can help out and possibly guide you. Coordinating up front makes it much easier to avoid frustration later on. -Code reviews ------------- +## Code reviews All submissions, including submissions by project members, require review. We use Github pull requests for this purpose. -YAPF coding style ------------------ +## YAPF coding style -YAPF follows the `Google Python Style Guide -`_ with two exceptions: +YAPF follows the [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html) +with two exceptions: - 2 spaces for indentation rather than 4. -- CamelCase for function and method names rather than snake_case. +- CamelCase for function and method names rather than `snake_case`. The rationale for this is that YAPF was initially developed at Google where these two exceptions are still part of the internal Python style guide. -Small print ------------ +## Small print Contributions made by corporations are covered by a different agreement than the one above, the Software Grant and Corporate Contributor License Agreement. diff --git a/MANIFEST.in b/MANIFEST.in index 5c70a558a..9a8d60241 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ -include HACKING.rst LICENSE AUTHORS CHANGELOG CONTRIBUTING.rst CONTRIBUTORS +include HACKING.rst LICENSE AUTHORS CHANGELOG CONTRIBUTING.md CONTRIBUTORS include .coveragerc .editorconfig .flake8 plugins/README.rst include plugins/vim/autoload/yapf.vim plugins/vim/plugin/yapf.vim pylintrc include .style.yapf tox.ini .travis.yml .vimrc From 6189363d1f21c0684690171afd5ca6c4b7914db8 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 13 Jun 2023 21:11:44 -0500 Subject: [PATCH 635/719] Reformat the knob docs --- README.md | 614 +++++++++++++++++++++++++++--------------------------- 1 file changed, 307 insertions(+), 307 deletions(-) diff --git a/README.md b/README.md index 7b41e82bf..bd03fd284 100644 --- a/README.md +++ b/README.md @@ -351,543 +351,543 @@ optional arguments: ## Knobs -`ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT` +#### `ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT` - Align closing bracket with visual indentation. +> Align closing bracket with visual indentation. -`ALLOW_MULTILINE_LAMBDAS` +#### `ALLOW_MULTILINE_LAMBDAS` - Allow lambdas to be formatted on more than one line. +> Allow lambdas to be formatted on more than one line. -`ALLOW_MULTILINE_DICTIONARY_KEYS` +#### `ALLOW_MULTILINE_DICTIONARY_KEYS` - Allow dictionary keys to exist on multiple lines. For example: +> Allow dictionary keys to exist on multiple lines. For example: ```python - x = { - ('this is the first element of a tuple', - 'this is the second element of a tuple'): - value, - } + x = { + ('this is the first element of a tuple', + 'this is the second element of a tuple'): + value, + } ``` -`ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS` +#### `ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS` - Allow splitting before a default / named assignment in an argument list. +> Allow splitting before a default / named assignment in an argument list. -`ALLOW_SPLIT_BEFORE_DICT_VALUE` +#### `ALLOW_SPLIT_BEFORE_DICT_VALUE` - Allow splits before the dictionary value. +> Allow splits before the dictionary value. -`ARITHMETIC_PRECEDENCE_INDICATION` +#### `ARITHMETIC_PRECEDENCE_INDICATION` - Let spacing indicate operator precedence. For example: +> Let spacing indicate operator precedence. For example: ```python - a = 1 * 2 + 3 / 4 - b = 1 / 2 - 3 * 4 - c = (1 + 2) * (3 - 4) - d = (1 - 2) / (3 + 4) - e = 1 * 2 - 3 - f = 1 + 2 + 3 + 4 + a = 1 * 2 + 3 / 4 + b = 1 / 2 - 3 * 4 + c = (1 + 2) * (3 - 4) + d = (1 - 2) / (3 + 4) + e = 1 * 2 - 3 + f = 1 + 2 + 3 + 4 ``` - will be formatted as follows to indicate precedence: +> will be formatted as follows to indicate precedence: ```python - a = 1*2 + 3/4 - b = 1/2 - 3*4 - c = (1+2) * (3-4) - d = (1-2) / (3+4) - e = 1*2 - 3 - f = 1 + 2 + 3 + 4 + a = 1*2 + 3/4 + b = 1/2 - 3*4 + c = (1+2) * (3-4) + d = (1-2) / (3+4) + e = 1*2 - 3 + f = 1 + 2 + 3 + 4 ``` -`BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF` +#### `BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION` - Insert a blank line before a `def` or `class` immediately nested within - another `def` or `class`. For example: +> Sets the number of desired blank lines surrounding top-level function and +> class definitions. For example: ```python - class Foo: - # <------ this blank line - def method(): - pass + class Foo: + pass + # <------ having two blank lines here + # <------ is the default setting + class Bar: + pass ``` -`BLANK_LINE_BEFORE_MODULE_DOCSTRING` +#### `BLANK_LINE_BEFORE_CLASS_DOCSTRING` - Insert a blank line before a module docstring. +> Insert a blank line before a class-level docstring. -`BLANK_LINE_BEFORE_CLASS_DOCSTRING` +#### `BLANK_LINE_BEFORE_MODULE_DOCSTRING` - Insert a blank line before a class-level docstring. +> Insert a blank line before a module docstring. -`BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION` +#### `BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF` - Sets the number of desired blank lines surrounding top-level function and - class definitions. For example: +> Insert a blank line before a `def` or `class` immediately nested within +> another `def` or `class`. For example: ```python - class Foo: - pass - # <------ having two blank lines here - # <------ is the default setting - class Bar: + class Foo: + # <------ this blank line + def method(): pass ``` -`BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES` +#### `BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES` - Sets the number of desired blank lines between top-level imports and - variable definitions. Useful for compatibility with tools like isort. +> Sets the number of desired blank lines between top-level imports and +> variable definitions. Useful for compatibility with tools like isort. -`COALESCE_BRACKETS` +#### `COALESCE_BRACKETS` - Do not split consecutive brackets. Only relevant when - `DEDENT_CLOSING_BRACKETS` or `INDENT_CLOSING_BRACKETS` is set. For example: +> Do not split consecutive brackets. Only relevant when +> `DEDENT_CLOSING_BRACKETS` or `INDENT_CLOSING_BRACKETS` is set. For example: ```python - call_func_that_takes_a_dict( - { - 'key1': 'value1', - 'key2': 'value2', - } - ) + call_func_that_takes_a_dict( + { + 'key1': 'value1', + 'key2': 'value2', + } + ) ``` - would reformat to: +> would reformat to: ```python - call_func_that_takes_a_dict({ - 'key1': 'value1', - 'key2': 'value2', - }) + call_func_that_takes_a_dict({ + 'key1': 'value1', + 'key2': 'value2', + }) ``` -`COLUMN_LIMIT` +#### `COLUMN_LIMIT` - The column limit (or max line-length) +> The column limit (or max line-length) -`CONTINUATION_ALIGN_STYLE` +#### `CONTINUATION_ALIGN_STYLE` - The style for continuation alignment. Possible values are: +> The style for continuation alignment. Possible values are: - - `SPACE`: Use spaces for continuation alignment. This is default - behavior. - - `FIXED`: Use fixed number (CONTINUATION_INDENT_WIDTH) of columns - (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs or - CONTINUATION_INDENT_WIDTH spaces) for continuation alignment. - - `VALIGN-RIGHT`: Vertically align continuation lines to multiple of - INDENT_WIDTH columns. Slightly right (one tab or a few spaces) if cannot - vertically align continuation lines with indent characters. +> - `SPACE`: Use spaces for continuation alignment. This is default +> behavior. +> - `FIXED`: Use fixed number (`CONTINUATION_INDENT_WIDTH`) of columns +> (i.e. `CONTINUATION_INDENT_WIDTH`/`INDENT_WIDTH` tabs or +> `CONTINUATION_INDENT_WIDTH` spaces) for continuation alignment. +> - `VALIGN-RIGHT`: Vertically align continuation lines to multiple of +> `INDENT_WIDTH` columns. Slightly right (one tab or a few spaces) if cannot +> vertically align continuation lines with indent characters. -`CONTINUATION_INDENT_WIDTH` +#### `CONTINUATION_INDENT_WIDTH` - Indent width used for line continuations. +> Indent width used for line continuations. -`DEDENT_CLOSING_BRACKETS` +#### `DEDENT_CLOSING_BRACKETS` - Put closing brackets on a separate line, dedented, if the bracketed - expression can't fit in a single line. Applies to all kinds of brackets, - including function definitions and calls. For example: +> Put closing brackets on a separate line, dedented, if the bracketed +> expression can't fit in a single line. Applies to all kinds of brackets, +> including function definitions and calls. For example: ```python - config = { - 'key1': 'value1', - 'key2': 'value2', - } # <--- this bracket is dedented and on a separate line - - time_series = self.remote_client.query_entity_counters( - entity='dev3246.region1', - key='dns.query_latency_tcp', - transform=Transformation.AVERAGE(window=timedelta(seconds=60)), - start_ts=now()-timedelta(days=3), - end_ts=now(), - ) # <--- this bracket is dedented and on a separate line + config = { + 'key1': 'value1', + 'key2': 'value2', + } # <--- this bracket is dedented and on a separate line + + time_series = self.remote_client.query_entity_counters( + entity='dev3246.region1', + key='dns.query_latency_tcp', + transform=Transformation.AVERAGE(window=timedelta(seconds=60)), + start_ts=now()-timedelta(days=3), + end_ts=now(), + ) # <--- this bracket is dedented and on a separate line ``` -`DISABLE_ENDING_COMMA_HEURISTIC` - - Disable the heuristic which places each list element on a separate line if - the list is comma-terminated. - -`EACH_DICT_ENTRY_ON_SEPARATE_LINE` +#### `DISABLE_ENDING_COMMA_HEURISTIC` - Place each dictionary entry onto its own line. +> Disable the heuristic which places each list element on a separate line if +> the list is comma-terminated. -`FORCE_MULTILINE_DICT` +#### `EACH_DICT_ENTRY_ON_SEPARATE_LINE` - Respect `EACH_DICT_ENTRY_ON_SEPARATE_LINE` even if the line is shorter than - `COLUMN_LIMIT`. +> Place each dictionary entry onto its own line. -`I18N_COMMENT` +#### `FORCE_MULTILINE_DICT` - The regex for an internationalization comment. The presence of this comment - stops reformatting of that line, because the comments are required to be - next to the string they translate. +> Respect `EACH_DICT_ENTRY_ON_SEPARATE_LINE` even if the line is shorter than +> `COLUMN_LIMIT`. -`I18N_FUNCTION_CALL` +#### `I18N_COMMENT` - The internationalization function call names. The presence of this function - stops reformatting on that line, because the string it has cannot be moved - away from the i18n comment. +> The regex for an internationalization comment. The presence of this comment +> stops reformatting of that line, because the comments are required to be +> next to the string they translate. -`INDENT_DICTIONARY_VALUE` +#### `I18N_FUNCTION_CALL` - Indent the dictionary value if it cannot fit on the same line as the - dictionary key. For example: +> The internationalization function call names. The presence of this function +> stops reformatting on that line, because the string it has cannot be moved +> away from the i18n comment. -```python - config = { - 'key1': - 'value1', - 'key2': value1 + - value2, - } -``` +#### `INDENT_BLANK_LINES` -`INDENT_WIDTH` +> Set to `True` to prefer indented blank lines rather than empty - The number of columns to use for indentation. +#### `INDENT_CLOSING_BRACKETS` -`INDENT_BLANK_LINES` +> Put closing brackets on a separate line, indented, if the bracketed +> expression can't fit in a single line. Applies to all kinds of brackets, +> including function definitions and calls. For example: - Set to `True` to prefer indented blank lines rather than empty +```python + config = { + 'key1': 'value1', + 'key2': 'value2', + } # <--- this bracket is indented and on a separate line + + time_series = self.remote_client.query_entity_counters( + entity='dev3246.region1', + key='dns.query_latency_tcp', + transform=Transformation.AVERAGE(window=timedelta(seconds=60)), + start_ts=now()-timedelta(days=3), + end_ts=now(), + ) # <--- this bracket is indented and on a separate line +``` -`INDENT_CLOSING_BRACKETS` +#### `INDENT_DICTIONARY_VALUE` - Put closing brackets on a separate line, indented, if the bracketed - expression can't fit in a single line. Applies to all kinds of brackets, - including function definitions and calls. For example: +> Indent the dictionary value if it cannot fit on the same line as the +> dictionary key. For example: ```python - config = { - 'key1': 'value1', - 'key2': 'value2', - } # <--- this bracket is indented and on a separate line - - time_series = self.remote_client.query_entity_counters( - entity='dev3246.region1', - key='dns.query_latency_tcp', - transform=Transformation.AVERAGE(window=timedelta(seconds=60)), - start_ts=now()-timedelta(days=3), - end_ts=now(), - ) # <--- this bracket is indented and on a separate line + config = { + 'key1': + 'value1', + 'key2': value1 + + value2, + } ``` -`JOIN_MULTIPLE_LINES` +#### `INDENT_WIDTH` + +> The number of columns to use for indentation. + +#### `JOIN_MULTIPLE_LINES` - Join short lines into one line. E.g., single line `if` statements. +> Join short lines into one line. E.g., single line `if` statements. -`NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS` +#### `NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS` - Do not include spaces around selected binary operators. For example: +> Do not include spaces around selected binary operators. For example: ```python - 1 + 2 * 3 - 4 / 5 + 1 + 2 * 3 - 4 / 5 ``` - will be formatted as follows when configured with `*`, `/`: +> will be formatted as follows when configured with `*`, `/`: ```python - 1 + 2*3 - 4/5 + 1 + 2*3 - 4/5 ``` -`SPACES_AROUND_POWER_OPERATOR` +#### `SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET` - Set to `True` to prefer using spaces around `**`. +> Insert a space between the ending comma and closing bracket of a list, etc. -`SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN` +#### `SPACE_INSIDE_BRACKETS` - Set to `True` to prefer spaces around the assignment operator for default - or keyword arguments. + Use spaces inside brackets, braces, and parentheses. For example: -`SPACES_AROUND_DICT_DELIMITERS` +```python + method_call( 1 ) + my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] + my_set = { 1, 2, 3 } +``` + +#### `SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN` + +> Set to `True` to prefer spaces around the assignment operator for default +> or keyword arguments. - Adds a space after the opening '{' and before the ending '}' dict delimiters. +#### `SPACES_AROUND_DICT_DELIMITERS` + +> Adds a space after the opening '{' and before the ending '}' dict delimiters. ```python {1: 2} ``` - will be formatted as: +> will be formatted as: ```python { 1: 2 } ``` -`SPACES_AROUND_LIST_DELIMITERS` +#### `SPACES_AROUND_LIST_DELIMITERS` - Adds a space after the opening '[' and before the ending ']' list delimiters. +> Adds a space after the opening '[' and before the ending ']' list delimiters. ```python - [1, 2] + [1, 2] ``` - will be formatted as: +> will be formatted as: ```python - [ 1, 2 ] + [ 1, 2 ] ``` -`SPACES_AROUND_SUBSCRIPT_COLON` +#### `SPACES_AROUND_POWER_OPERATOR` + +> Set to `True` to prefer using spaces around `**`. + +#### `SPACES_AROUND_SUBSCRIPT_COLON` - Use spaces around the subscript / slice operator. For example: +> Use spaces around the subscript / slice operator. For example: ```python - my_list[1 : 10 : 2] + my_list[1 : 10 : 2] ``` -`SPACES_AROUND_TUPLE_DELIMITERS` +##### `SPACES_AROUND_TUPLE_DELIMITERS` - Adds a space after the opening '(' and before the ending ')' tuple delimiters. +> Adds a space after the opening '(' and before the ending ')' tuple delimiters. ```python - (1, 2, 3) + (1, 2, 3) ``` - will be formatted as: +> will be formatted as: ```python - ( 1, 2, 3 ) + ( 1, 2, 3 ) ``` -`SPACES_BEFORE_COMMENT` +#### `SPACES_BEFORE_COMMENT` - The number of spaces required before a trailing comment. - This can be a single value (representing the number of spaces - before each trailing comment) or list of values (representing - alignment column values; trailing comments within a block will - be aligned to the first column value that is greater than the maximum - line length within the block). +> The number of spaces required before a trailing comment. +> This can be a single value (representing the number of spaces +> before each trailing comment) or list of values (representing +> alignment column values; trailing comments within a block will +> be aligned to the first column value that is greater than the maximum +> line length within the block). - > **Note:** Lists of values may need to be quoted in some contexts - > (eg. shells or editor config files). +> **Note:** Lists of values may need to be quoted in some contexts +> (eg. shells or editor config files). - For example, with `spaces_before_comment=5`: +> For example, with `spaces_before_comment=5`: ```python - 1 + 1 # Adding values + 1 + 1 # Adding values ``` - will be formatted as: +> will be formatted as: ```python - 1 + 1 # Adding values <-- 5 spaces between the end of the statement and comment + 1 + 1 # Adding values <-- 5 spaces between the end of the statement and comment ``` - with `spaces_before_comment="15, 20"`: +> with `spaces_before_comment="15, 20"`: ```python - 1 + 1 # Adding values - two + two # More adding + 1 + 1 # Adding values + two + two # More adding - longer_statement # This is a longer statement - short # This is a shorter statement + longer_statement # This is a longer statement + short # This is a shorter statement - a_very_long_statement_that_extends_beyond_the_final_column # Comment - short # This is a shorter statement + a_very_long_statement_that_extends_beyond_the_final_column # Comment + short # This is a shorter statement ``` - will be formatted as: +> will be formatted as: ```python - 1 + 1 # Adding values <-- end of line comments in block aligned to col 15 - two + two # More adding + 1 + 1 # Adding values <-- end of line comments in block aligned to col 15 + two + two # More adding - longer_statement # This is a longer statement <-- end of line comments in block aligned to col 20 - short # This is a shorter statement + longer_statement # This is a longer statement <-- end of line comments in block aligned to col 20 + short # This is a shorter statement - a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length - short # This is a shorter statement + a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length + short # This is a shorter statement ``` -`SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET` +#### `SPLIT_ALL_COMMA_SEPARATED_VALUES` - Insert a space between the ending comma and closing bracket of a list, etc. +> If a comma separated list (`dict`, `list`, `tuple`, or function `def`) is +> on a line that is too long, split such that each element is on a separate +> line. -`SPACE_INSIDE_BRACKETS` +#### `SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES` - Use spaces inside brackets, braces, and parentheses. For example: +> Variation on `SPLIT_ALL_COMMA_SEPARATED_VALUES` in which, if a +> subexpression with a comma fits in its starting line, then the +> subexpression is not split. This avoids splits like the one for +> `b` in this code: ```python - method_call( 1 ) - my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] - my_set = { 1, 2, 3 } + abcdef( + aReallyLongThing: int, + b: [Int, + Int]) ``` -`SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED` - - Split before arguments if the argument list is terminated by a comma. - -`SPLIT_ALL_COMMA_SEPARATED_VALUES` - - If a comma separated list (`dict`, `list`, `tuple`, or function `def`) is - on a line that is too long, split such that each element is on a separate - line. - -`SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES` - - Variation on `SPLIT_ALL_COMMA_SEPARATED_VALUES` in which, if a - subexpression with a comma fits in its starting line, then the - subexpression is not split. This avoids splits like the one for - `b` in this code: +> with the new knob this is split as: ```python - abcdef( - aReallyLongThing: int, - b: [Int, - Int]) + abcdef( + aReallyLongThing: int, + b: [Int, Int]) ``` - with the new knob this is split as: +#### `SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED` -```python - abcdef( - aReallyLongThing: int, - b: [Int, Int]) -``` +> Split before arguments if the argument list is terminated by a comma. -`SPLIT_BEFORE_BITWISE_OPERATOR` +#### `SPLIT_BEFORE_ARITHMETIC_OPERATOR` - Set to `True` to prefer splitting before `&`, `|` or `^` rather than after. +> Set to `True` to prefer splitting before `+`, `-`, `*`, `/`, `//`, or `@` +> rather than after. -`SPLIT_BEFORE_ARITHMETIC_OPERATOR` +#### `SPLIT_BEFORE_BITWISE_OPERATOR` - Set to `True` to prefer splitting before `+`, `-`, `*`, `/`, `//`, or `@` - rather than after. +> Set to `True` to prefer splitting before `&`, `|` or `^` rather than after. -`SPLIT_BEFORE_CLOSING_BRACKET` +#### `SPLIT_BEFORE_CLOSING_BRACKET` - Split before the closing bracket if a `list` or `dict` literal doesn't fit - on a single line. +> Split before the closing bracket if a `list` or `dict` literal doesn't fit +> on a single line. -`SPLIT_BEFORE_DICT_SET_GENERATOR` +#### `SPLIT_BEFORE_DICT_SET_GENERATOR` - Split before a dictionary or set generator (`comp_for`). For example, note - the split before the `for`: +> Split before a dictionary or set generator (`comp_for`). For example, note +> the split before the `for`: ```python - foo = { - variable: 'Hello world, have a nice day!' - for variable in bar if variable != 42 - } + foo = { + variable: 'Hello world, have a nice day!' + for variable in bar if variable != 42 + } ``` -`SPLIT_BEFORE_DOT` +#### `SPLIT_BEFORE_DOT` - Split before the `.` if we need to split a longer expression: +> Split before the `.` if we need to split a longer expression: ```python - foo = ('This is a really long string: {}, {}, {}, {}'.format(a, b, c, d)) + foo = ('This is a really long string: {}, {}, {}, {}'.format(a, b, c, d)) ``` - would reformat to something like: +> would reformat to something like: ```python - foo = ('This is a really long string: {}, {}, {}, {}' - .format(a, b, c, d)) + foo = ('This is a really long string: {}, {}, {}, {}' + .format(a, b, c, d)) ``` -`SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN` +#### `SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN` - Split after the opening paren which surrounds an expression if it doesn't - fit on a single line. +> Split after the opening paren which surrounds an expression if it doesn't +> fit on a single line. -`SPLIT_BEFORE_FIRST_ARGUMENT` +#### `SPLIT_BEFORE_FIRST_ARGUMENT` - If an argument / parameter list is going to be split, then split before the - first argument. +> If an argument / parameter list is going to be split, then split before the +> first argument. -`SPLIT_BEFORE_LOGICAL_OPERATOR` +#### `SPLIT_BEFORE_LOGICAL_OPERATOR` - Set to `True` to prefer splitting before `and` or `or` rather than after. +> Set to `True` to prefer splitting before `and` or `or` rather than after. -`SPLIT_BEFORE_NAMED_ASSIGNS` +#### `SPLIT_BEFORE_NAMED_ASSIGNS` - Split named assignments onto individual lines. +> Split named assignments onto individual lines. -`SPLIT_COMPLEX_COMPREHENSION` +#### `SPLIT_COMPLEX_COMPREHENSION` - For list comprehensions and generator expressions with multiple clauses - (e.g multiple `for` calls, `if` filter expressions) and which need to be - reflowed, split each clause onto its own line. For example: +> For list comprehensions and generator expressions with multiple clauses +> (e.g multiple `for` calls, `if` filter expressions) and which need to be +> reflowed, split each clause onto its own line. For example: ```python - result = [ - a_var + b_var for a_var in xrange(1000) for b_var in xrange(1000) - if a_var % b_var] + result = [ + a_var + b_var for a_var in xrange(1000) for b_var in xrange(1000) + if a_var % b_var] ``` - would reformat to something like: +> would reformat to something like: ```python - result = [ - a_var + b_var - for a_var in xrange(1000) - for b_var in xrange(1000) - if a_var % b_var] + result = [ + a_var + b_var + for a_var in xrange(1000) + for b_var in xrange(1000) + if a_var % b_var] ``` -`SPLIT_PENALTY_AFTER_OPENING_BRACKET` +#### `SPLIT_PENALTY_AFTER_OPENING_BRACKET` - The penalty for splitting right after the opening bracket. +> The penalty for splitting right after the opening bracket. -`SPLIT_PENALTY_AFTER_UNARY_OPERATOR` +#### `SPLIT_PENALTY_AFTER_UNARY_OPERATOR` - The penalty for splitting the line after a unary operator. +> The penalty for splitting the line after a unary operator. -`SPLIT_PENALTY_ARITHMETIC_OPERATOR` +#### `SPLIT_PENALTY_ARITHMETIC_OPERATOR` - The penalty of splitting the line around the `+`, `-`, `*`, `/`, `//`, `%`, - and `@` operators. +> The penalty of splitting the line around the `+`, `-`, `*`, `/`, `//`, `%`, +> and `@` operators. -`SPLIT_PENALTY_BEFORE_IF_EXPR` +#### `SPLIT_PENALTY_BEFORE_IF_EXPR` - The penalty for splitting right before an `if` expression. +> The penalty for splitting right before an `if` expression. -`SPLIT_PENALTY_BITWISE_OPERATOR` +#### `SPLIT_PENALTY_BITWISE_OPERATOR` - The penalty of splitting the line around the `&`, `|`, and `^` operators. +> The penalty of splitting the line around the `&`, `|`, and `^` operators. -`SPLIT_PENALTY_COMPREHENSION` +#### `SPLIT_PENALTY_COMPREHENSION` - The penalty for splitting a list comprehension or generator expression. +> The penalty for splitting a list comprehension or generator expression. -`SPLIT_PENALTY_EXCESS_CHARACTER` +#### `SPLIT_PENALTY_EXCESS_CHARACTER` - The penalty for characters over the column limit. +> The penalty for characters over the column limit. -`SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT` +#### `SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT` - The penalty incurred by adding a line split to the logical line. The more - line splits added the higher the penalty. +> The penalty incurred by adding a line split to the logical line. The more +> line splits added the higher the penalty. -`SPLIT_PENALTY_IMPORT_NAMES` +#### `SPLIT_PENALTY_IMPORT_NAMES` - The penalty of splitting a list of `import as` names. For example: +> The penalty of splitting a list of `import as` names. For example: ```python - from a_very_long_or_indented_module_name_yada_yad import (long_argument_1, - long_argument_2, - long_argument_3) + from a_very_long_or_indented_module_name_yada_yad import (long_argument_1, + long_argument_2, + long_argument_3) ``` - would reformat to something like: +> would reformat to something like: ```python - from a_very_long_or_indented_module_name_yada_yad import ( - long_argument_1, long_argument_2, long_argument_3) + from a_very_long_or_indented_module_name_yada_yad import ( + long_argument_1, long_argument_2, long_argument_3) ``` -`SPLIT_PENALTY_LOGICAL_OPERATOR` +#### `SPLIT_PENALTY_LOGICAL_OPERATOR` - The penalty of splitting the line around the `and` and `or` operators. +> The penalty of splitting the line around the `and` and `or` operators. -`USE_TABS` +#### `USE_TABS` - Use the Tab character for indentation. +> Use the Tab character for indentation. ## (Potentially) Frequently Asked Questions From b98504f409ff2c0fec875c8bf2450f4d52cf8d04 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 14 Jun 2023 01:57:56 -0500 Subject: [PATCH 636/719] Convert to Markdown --- plugins/README.md | 106 +++++++++++++++++++++++++++++++++++++++++ plugins/README.rst | 115 --------------------------------------------- 2 files changed, 106 insertions(+), 115 deletions(-) create mode 100644 plugins/README.md delete mode 100644 plugins/README.rst diff --git a/plugins/README.md b/plugins/README.md new file mode 100644 index 000000000..d2b1aaa1f --- /dev/null +++ b/plugins/README.md @@ -0,0 +1,106 @@ +# IDE Plugins + +## Emacs + +The `Emacs` plugin is maintained separately. Installation directions can be +found here: https://github.com/paetzke/py-yapf.el + + +## Vim + +The `vim` plugin allows you to reformat a range of code. Copy `plugin` and +`autoload` directories into your `~/.vim` or use `:packadd` in Vim 8. Or use +a plugin manager like Plug or Vundle: + +```vim +" Plug +Plug 'google/yapf', { 'rtp': 'plugins/vim', 'for': 'python' } + +" Vundle +Plugin 'google/yapf', { 'rtp': 'plugins/vim' } +``` + +You can add key bindings in the `.vimrc` file: + +```vim +map :call yapf#YAPF() +imap :call yapf#YAPF() +``` + +Alternatively, you can call the command `YAPF`. If you omit the range, it will +reformat the whole buffer. + +example: + +```vim +:YAPF " formats whole buffer +:'<,'>YAPF " formats lines selected in visual mode +``` + + +## Sublime Text + +The `Sublime Text` plugin is also maintained separately. It is compatible with +both Sublime Text 2 and 3. + +The plugin can be easily installed by using *Sublime Package Control*. Check +the project page of the plugin for more information: https://github.com/jason-kane/PyYapf + + +## git Pre-Commit Hook + +The `git` pre-commit hook automatically formats your Python files before they +are committed to your local repository. Any changes `yapf` makes to the files +will stay unstaged so that you can diff them manually. + +To install, simply download the raw file and copy it into your git hooks +directory: + +```bash +# From the root of your git project. +$ curl -o pre-commit.sh https://raw.githubusercontent.com/google/yapf/main/plugins/pre-commit.sh +$ chmod a+x pre-commit.sh +$ mv pre-commit.sh .git/hooks/pre-commit +``` + + +## Textmate 2 + +Plugin for `Textmate 2` requires `yapf` Python package installed on your +system: + +```bash +$ pip install yapf +``` + +Also, you will need to activate `Python` bundle from `Preferences > Bundles`. + +Finally, create a `~/Library/Application Support/TextMate/Bundles/Python.tmbundle/Commands/YAPF.tmCommand` +file with the following content: + +```xml + + + + + beforeRunningCommand + saveActiveFile + command + #!/bin/bash + +TPY=${TM_PYTHON:-python} + +"$TPY" "/usr/local/bin/yapf" "$TM_FILEPATH" + input + document + name + YAPF + scope + source.python + uuid + 297D5A82-2616-4950-9905-BD2D1C94D2D4 + + +``` + +You will see a new menu item `Bundles > Python > YAPF`. diff --git a/plugins/README.rst b/plugins/README.rst deleted file mode 100644 index b87bb2d76..000000000 --- a/plugins/README.rst +++ /dev/null @@ -1,115 +0,0 @@ -=========== -IDE Plugins -=========== - -Emacs -===== - -The ``Emacs`` plugin is maintained separately. Installation directions can be -found here: https://github.com/paetzke/py-yapf.el - -VIM -=== - -The ``vim`` plugin allows you to reformat a range of code. Copy ``plugin`` and -``autoload`` directories into your ~/.vim or use ``:packadd`` in Vim 8. Or use -a plugin manager like Plug or Vundle: - -.. code-block:: vim - - " Plug - Plug 'google/yapf', { 'rtp': 'plugins/vim', 'for': 'python' } - - " Vundle - Plugin 'google/yapf', { 'rtp': 'plugins/vim' } - - -You can add key bindings in the ``.vimrc`` file: - -.. code-block:: vim - - map :call yapf#YAPF() - imap :call yapf#YAPF() - -Alternatively, you can call the command ``YAPF``. If you omit the range, it -will reformat the whole buffer. - -example: - -.. code-block:: vim - - :YAPF " formats whole buffer - :'<,'>YAPF " formats lines selected in visual mode - -Sublime Text -============ - -The ``Sublime Text`` plugin is also maintained separately. It is compatible -with both Sublime Text 2 and 3. - -The plugin can be easily installed by using *Sublime Package Control*. Check -the project page of the plugin for more information: -https://github.com/jason-kane/PyYapf - -=================== -git Pre-Commit Hook -=================== - -The ``git`` pre-commit hook automatically formats your Python files before they -are committed to your local repository. Any changes ``yapf`` makes to the files -will stay unstaged so that you can diff them manually. - -To install, simply download the raw file and copy it into your git hooks -directory: - -.. code-block:: bash - - # From the root of your git project. - curl -o pre-commit.sh https://raw.githubusercontent.com/google/yapf/main/plugins/pre-commit.sh - chmod a+x pre-commit.sh - mv pre-commit.sh .git/hooks/pre-commit - -========== -Textmate 2 -========== - -Plugin for ``Textmate 2`` requires ``yapf`` Python package installed on your -system: - -.. code-block:: shell - - pip install yapf - -Also, you will need to activate ``Python`` bundle from ``Preferences >> -Bundles``. - -Finally, create a ``~/Library/Application -Support/TextMate/Bundles/Python.tmbundle/Commands/YAPF.tmCommand`` file with -the following content: - -.. code-block:: xml - - - - - - beforeRunningCommand - saveActiveFile - command - #!/bin/bash - - TPY=${TM_PYTHON:-python} - - "$TPY" "/usr/local/bin/yapf" "$TM_FILEPATH" - input - document - name - YAPF - scope - source.python - uuid - 297D5A82-2616-4950-9905-BD2D1C94D2D4 - - - -You will see a new menu item ``Bundles > Python > YAPF``. From bbdd27baa968ae5852962596c4c1ce65a4e75068 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 14 Jun 2023 01:58:21 -0500 Subject: [PATCH 637/719] Change to correct filename --- MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 9a8d60241..378edaade 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ include HACKING.rst LICENSE AUTHORS CHANGELOG CONTRIBUTING.md CONTRIBUTORS -include .coveragerc .editorconfig .flake8 plugins/README.rst +include .coveragerc .editorconfig .flake8 plugins/README.md include plugins/vim/autoload/yapf.vim plugins/vim/plugin/yapf.vim pylintrc include .style.yapf tox.ini .travis.yml .vimrc From ef55c2b8420ac88b00221a220ff0feff07c4e817 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Jun 2023 15:02:46 +0200 Subject: [PATCH 638/719] Actions(deps): Bump actions/checkout from 3.5.2 to 3.5.3 (#1105) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.2 to 3.5.3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/8e5e7e5ab8b370d6c329ec480221332ada57f0ab...c85c95e3d7251135ab7dc9ce3241c5835cc595a9) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/pre-commit-autoupdate.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c4102ff2c..79580d23f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: python-version: ["3.7", "3.8", "3.11"] # no particular need for 3.9 or 3.10 os: [macos-latest, ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.0 with: diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index a0d9533dc..972461822 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -19,7 +19,7 @@ jobs: name: Detect outdated pre-commit hooks runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: Set up Python 3.11 uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # v4.5.0 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 10a7ec31d..acf4d8a04 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -19,7 +19,7 @@ jobs: name: Run pre-commit runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 with: From 2837603ed29d44d028508193f34f7a801e24e1d7 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 20 Jun 2023 00:42:57 -0500 Subject: [PATCH 639/719] Fix for bad v0.40.0 packaging --- CHANGELOG | 4 ++++ setup.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index cc963092d..9122fafd8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,10 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.40.1] 2023-06-20 +### Fixed +- Corrected bad distribution v0.40.0 package. + ## [0.40.0] 2023-06-13 ### Added - Support for Python 3.11 diff --git a/setup.py b/setup.py index 4f04d194a..ee5f620c6 100644 --- a/setup.py +++ b/setup.py @@ -42,7 +42,7 @@ def run(self): with codecs.open('README.md', 'r', 'utf-8') as fd: setup( name='yapf', - version='0.40.0', + version='0.40.1', description='A formatter for Python code.', url='https://github.com/google/yapf', long_description=fd.read(), From 8f9ea1b6772958705881e7f3155a91d4bcd9d3b5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 20 Jun 2023 22:59:45 -0700 Subject: [PATCH 640/719] pre-commit: Autoupdate (#1109) Co-authored-by: pre-commit --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3e78dd66e..324807931 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ repos: - repo: https://github.com/pycqa/isort - rev: 5.11.5 + rev: 5.12.0 hooks: - id: isort name: isort (python) @@ -20,7 +20,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.2.0 + rev: v4.4.0 hooks: - id: trailing-whitespace - id: check-docstring-first From 723406bad4dc6431ad3fcc77dca5bd1e2d3fd61c Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Thu, 22 Jun 2023 08:21:52 +0200 Subject: [PATCH 641/719] setup.py: Require setuptools >=58.5.0 (#1115) .. so that "python3 setup.py sdist" ends up including these four files in the resulting distribution source tarball: - /third_party/yapf_third_party/yapf_diff/LICENSE - /third_party/yapf_third_party/_ylib2to3/Grammar.txt - /third_party/yapf_third_party/_ylib2to3/LICENSE - /third_party/yapf_third_party/_ylib2to3/PatternGrammar.txt --- setup.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.py b/setup.py index ee5f620c6..605b78a37 100644 --- a/setup.py +++ b/setup.py @@ -94,6 +94,9 @@ def run(self): }, include_package_data=True, python_requires='>=3.7', + setup_requires=[ + 'setuptools>=58.5.0', # for include_package_data fix (issue #1107) + ], install_requires=[ 'importlib-metadata>=6.6.0', 'platformdirs>=3.5.1', From bc681bc81f823c2817681732a803c9a1e807e47b Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Thu, 22 Jun 2023 08:22:49 +0200 Subject: [PATCH 642/719] Remove pep8ify as a "current" Python formatter (#1114) https://pypi.org/project/pep8ify/ has not been updated in 9 years and is therefor not a current Python formatted. Perhaps https://pypi.org/project/black/ could be mentioned in its place. --- yapf/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index dd0feff29..a0406e260 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -19,7 +19,7 @@ that line. It then uses a priority queue to figure out what the best formatting is --- i.e., the formatting with the least penalty. -It differs from tools like autopep8 and pep8ify in that it doesn't just look for +It differs from tools like autopep8 in that it doesn't just look for violations of the style guide, but looks at the module as a whole, making formatting decisions based on what's the best format for each line. From 7c17b360790234c03981177e079a02b06d038ab3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Jun 2023 23:23:11 -0700 Subject: [PATCH 643/719] Actions(deps): Bump actions/setup-python from 4.5.0 to 4.6.1 (#1113) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4.5.0 to 4.6.1. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v4.5.0...bd6b4b6205c4dbad673328db7b31b7fab9e241c0) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit-autoupdate.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index 972461822..4b1a4d2bb 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: Set up Python 3.11 - uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # v4.5.0 + uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 with: python-version: 3.11 From 3d174ead952df338da13a51f199ab0d25632ad52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Jun 2023 23:23:44 -0700 Subject: [PATCH 644/719] Actions(deps): Bump peter-evans/create-pull-request from 5.0.0 to 5.0.2 (#1112) Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 5.0.0 to 5.0.2. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/5b4a9f6a9e2af26e5f02351490b90d01eb8ec1e5...153407881ec5c347639a548ade7d8ad1d6740e38) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit-autoupdate.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index 4b1a4d2bb..15621c802 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -42,7 +42,7 @@ jobs: - name: Create pull request from changes (if any) id: create-pull-request - uses: peter-evans/create-pull-request@5b4a9f6a9e2af26e5f02351490b90d01eb8ec1e5 # v5.0.0 + uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38 # v5.0.2 with: author: 'pre-commit ' base: main From c0877c654666d3547afab4c8742f9a6ade18a56a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 22 Jun 2023 02:26:50 -0500 Subject: [PATCH 645/719] Convert to Markdown file --- HACKING.md | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++ HACKING.rst | 32 ------------------------------ 2 files changed, 56 insertions(+), 32 deletions(-) create mode 100644 HACKING.md delete mode 100644 HACKING.rst diff --git a/HACKING.md b/HACKING.md new file mode 100644 index 000000000..7499c8657 --- /dev/null +++ b/HACKING.md @@ -0,0 +1,56 @@ +## Running YAPF on itself + +- To run YAPF on all of YAPF: + +```bash +$ PYTHONPATH=$PWD/yapf python -m yapf -i -r . +``` + +- To run YAPF on just the files changed in the current git branch: + +```bash +$ PYTHONPATH=$PWD/yapf python -m yapf -i $(git diff --name-only @{upstream}) +``` + +## Releasing a new version + +- Run tests with Python 3.7 and 3.11: + +```bash +$ python setup.py test +``` + +- Bump version in `setup.py`. + +- Build source distribution: + +```bash +$ python setup.py sdist +``` + +- Check that it looks OK. + - Install it onto a virtualenv, + - run tests, and + - run yapf as a tool. + +- Build release: + +```bash +$ python setup.py sdist bdist_wheel +``` + +- Push to PyPI: + +```bash +$ twine upload dist/* +``` + +- Test in a clean virtualenv that 'pip install yapf' works with the new + version. + +- Commit the version bump and add tag with: + +```bash +$ git tag v$(VERSION_NUM) +$ git push --tags +``` diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index 3e2046942..000000000 --- a/HACKING.rst +++ /dev/null @@ -1,32 +0,0 @@ -Running YAPF on itself ----------------------- - -To run YAPF on all of YAPF:: - - $ PYTHONPATH=$PWD/yapf python -m yapf -i -r . - -To run YAPF on just the files changed in the current git branch:: - - $ PYTHONPATH=$PWD/yapf python -m yapf -i $(git diff --name-only @{upstream}) - -Releasing a new version ------------------------ - -* Run tests: python setup.py test - [don't forget to run with at least Python 3.7 and 3.11] - -* Bump version in setup.py. - -* Build source distribution: python setup.py sdist - -* Check it looks OK, install it onto a virtualenv, run tests, run yapf as a tool - -* Build release: python setup.py sdist bdist_wheel - -* Push to PyPI: twine upload dist/* - -* Test in a clean virtualenv that 'pip install yapf' works with the new version - -* Commit the version bump; add tag with git tag v; git push --tags - -TODO: discuss how to use tox to make virtualenv testing easier. From 83392466c977cafe2bee7bdd2dd218d0874e95e7 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 22 Jun 2023 02:28:33 -0500 Subject: [PATCH 646/719] Use correct filename --- MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 378edaade..c88aedecb 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ -include HACKING.rst LICENSE AUTHORS CHANGELOG CONTRIBUTING.md CONTRIBUTORS +include HACKING.md LICENSE AUTHORS CHANGELOG CONTRIBUTING.md CONTRIBUTORS include .coveragerc .editorconfig .flake8 plugins/README.md include plugins/vim/autoload/yapf.vim plugins/vim/plugin/yapf.vim pylintrc include .style.yapf tox.ini .travis.yml .vimrc From 8b887370c33b2b715be57ac85ffff9dcf1326051 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 23 Jun 2023 03:17:21 -0500 Subject: [PATCH 647/719] Alphabetize style list --- yapf/yapflib/style.py | 210 +++++++++++++++++++++++++----------------- 1 file changed, 126 insertions(+), 84 deletions(-) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index a341f0e92..72f277b25 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -52,10 +52,10 @@ def SetGlobalStyle(style): _STYLE_HELP = dict( + # BASED_ON_STYLE='Which predefined style this style is based on', ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=textwrap.dedent("""\ - Align closing bracket with visual indentation."""), - ALLOW_MULTILINE_LAMBDAS=textwrap.dedent("""\ - Allow lambdas to be formatted on more than one line."""), + Align closing bracket with visual indentation. + """), ALLOW_MULTILINE_DICTIONARY_KEYS=textwrap.dedent("""\ Allow dictionary keys to exist on multiple lines. For example: @@ -63,12 +63,17 @@ def SetGlobalStyle(style): ('this is the first element of a tuple', 'this is the second element of a tuple'): value, - }"""), + } + """), + ALLOW_MULTILINE_LAMBDAS=textwrap.dedent("""\ + Allow lambdas to be formatted on more than one line. + """), ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=textwrap.dedent("""\ Allow splitting before a default / named assignment in an argument list. - """), + """), ALLOW_SPLIT_BEFORE_DICT_VALUE=textwrap.dedent("""\ - Allow splits before the dictionary value."""), + Allow splits before the dictionary value. + """), ARITHMETIC_PRECEDENCE_INDICATION=textwrap.dedent("""\ Let spacing indicate operator precedence. For example: @@ -88,7 +93,13 @@ def SetGlobalStyle(style): e = 1*2 - 3 f = 1 + 2 + 3 + 4 - """), + """), + BLANK_LINE_BEFORE_CLASS_DOCSTRING=textwrap.dedent("""\ + Insert a blank line before a class-level docstring. + """), + BLANK_LINE_BEFORE_MODULE_DOCSTRING=textwrap.dedent("""\ + Insert a blank line before a module docstring. + """), BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=textwrap.dedent("""\ Insert a blank line before a 'def' or 'class' immediately nested within another 'def' or 'class'. For example: @@ -96,17 +107,16 @@ def SetGlobalStyle(style): class Foo: # <------ this blank line def method(): - ..."""), - BLANK_LINE_BEFORE_CLASS_DOCSTRING=textwrap.dedent("""\ - Insert a blank line before a class-level docstring."""), - BLANK_LINE_BEFORE_MODULE_DOCSTRING=textwrap.dedent("""\ - Insert a blank line before a module docstring."""), + pass + """), BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=textwrap.dedent("""\ Number of blank lines surrounding top-level function and class - definitions."""), + definitions. + """), BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES=textwrap.dedent("""\ Number of blank lines between top-level imports and variable - definitions."""), + definitions. + """), COALESCE_BRACKETS=textwrap.dedent("""\ Do not split consecutive brackets. Only relevant when dedent_closing_brackets is set. For example: @@ -123,9 +133,11 @@ def method(): call_func_that_takes_a_dict({ 'key1': 'value1', 'key2': 'value2', - })"""), + }) + """), COLUMN_LIMIT=textwrap.dedent("""\ - The column limit."""), + The column limit. + """), CONTINUATION_ALIGN_STYLE=textwrap.dedent("""\ The style for continuation alignment. Possible values are: @@ -135,9 +147,11 @@ def method(): CONTINUATION_INDENT_WIDTH spaces) for continuation alignment. - VALIGN-RIGHT: Vertically align continuation lines to multiple of INDENT_WIDTH columns. Slightly right (one tab or a few spaces) if - cannot vertically align continuation lines with indent characters."""), + cannot vertically align continuation lines with indent characters. + """), CONTINUATION_INDENT_WIDTH=textwrap.dedent("""\ - Indent width used for line continuations."""), + Indent width used for line continuations. + """), DEDENT_CLOSING_BRACKETS=textwrap.dedent("""\ Put closing brackets on a separate line, dedented, if the bracketed expression can't fit in a single line. Applies to all kinds of brackets, @@ -155,27 +169,32 @@ def method(): start_ts=now()-timedelta(days=3), end_ts=now(), ) # <--- this bracket is dedented and on a separate line - """), + """), DISABLE_ENDING_COMMA_HEURISTIC=textwrap.dedent("""\ Disable the heuristic which places each list element on a separate line - if the list is comma-terminated."""), + if the list is comma-terminated. + """), EACH_DICT_ENTRY_ON_SEPARATE_LINE=textwrap.dedent("""\ - Place each dictionary entry onto its own line."""), + Place each dictionary entry onto its own line. + """), FORCE_MULTILINE_DICT=textwrap.dedent("""\ Require multiline dictionary even if it would normally fit on one line. For example: config = { 'key1': 'value1' - }"""), + } + """), I18N_COMMENT=textwrap.dedent("""\ The regex for an i18n comment. The presence of this comment stops reformatting of that line, because the comments are required to be - next to the string they translate."""), + next to the string they translate. + """), I18N_FUNCTION_CALL=textwrap.dedent("""\ The i18n function call names. The presence of this function stops reformattting on that line, because the string it has cannot be moved - away from the i18n comment."""), + away from the i18n comment. + """), INDENT_CLOSING_BRACKETS=textwrap.dedent("""\ Put closing brackets on a separate line, indented, if the bracketed expression can't fit in a single line. Applies to all kinds of brackets, @@ -193,7 +212,7 @@ def method(): start_ts=now()-timedelta(days=3), end_ts=now(), ) # <--- this bracket is indented and on a separate line - """), + """), INDENT_DICTIONARY_VALUE=textwrap.dedent("""\ Indent the dictionary value if it cannot fit on the same line as the dictionary key. For example: @@ -204,13 +223,16 @@ def method(): 'key2': value1 + value2, } - """), - INDENT_WIDTH=textwrap.dedent("""\ - The number of columns to use for indentation."""), + """), INDENT_BLANK_LINES=textwrap.dedent("""\ - Indent blank lines."""), + Indent blank lines. + """), + INDENT_WIDTH=textwrap.dedent("""\ + The number of columns to use for indentation. + """), JOIN_MULTIPLE_LINES=textwrap.dedent("""\ - Join short lines into one line. E.g., single line 'if' statements."""), + Join short lines into one line. E.g., single line 'if' statements. + """), NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=textwrap.dedent("""\ Do not include spaces around selected binary operators. For example: @@ -219,21 +241,21 @@ def method(): will be formatted as follows when configured with "*,/": 1 + 2*3 - 4/5 - """), + """), SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=textwrap.dedent("""\ Insert a space between the ending comma and closing bracket of a list, - etc."""), + etc. + """), SPACE_INSIDE_BRACKETS=textwrap.dedent("""\ Use spaces inside brackets, braces, and parentheses. For example: method_call( 1 ) my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] my_set = { 1, 2, 3 } - """), - SPACES_AROUND_POWER_OPERATOR=textwrap.dedent("""\ - Use spaces around the power operator."""), + """), SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=textwrap.dedent("""\ - Use spaces around default or named assigns."""), + Use spaces around default or named assigns. + """), SPACES_AROUND_DICT_DELIMITERS=textwrap.dedent("""\ Adds a space after the opening '{' and before the ending '}' dict delimiters. @@ -243,7 +265,7 @@ def method(): will be formatted as: { 1: 2 } - """), + """), SPACES_AROUND_LIST_DELIMITERS=textwrap.dedent("""\ Adds a space after the opening '[' and before the ending ']' list delimiters. @@ -253,12 +275,15 @@ def method(): will be formatted as: [ 1, 2 ] - """), + """), + SPACES_AROUND_POWER_OPERATOR=textwrap.dedent("""\ + Use spaces around the power operator. + """), SPACES_AROUND_SUBSCRIPT_COLON=textwrap.dedent("""\ Use spaces around the subscript / slice operator. For example: my_list[1 : 10 : 2] - """), + """), SPACES_AROUND_TUPLE_DELIMITERS=textwrap.dedent("""\ Adds a space after the opening '(' and before the ending ')' tuple delimiters. @@ -268,7 +293,7 @@ def method(): will be formatted as: ( 1, 2, 3 ) - """), + """), SPACES_BEFORE_COMMENT=textwrap.dedent("""\ The number of spaces required before a trailing comment. This can be a single value (representing the number of spaces @@ -310,24 +335,30 @@ def method(): a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length short # This is a shorter statement - """), # noqa - SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=textwrap.dedent("""\ - Split before arguments if the argument list is terminated by a - comma."""), + """), # noqa SPLIT_ALL_COMMA_SEPARATED_VALUES=textwrap.dedent("""\ - Split before arguments"""), + Split before arguments. + """), SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=textwrap.dedent("""\ Split before arguments, but do not split all subexpressions recursively - (unless needed)."""), + (unless needed). + """), + SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=textwrap.dedent("""\ + Split before arguments if the argument list is terminated by a + comma. + """), SPLIT_BEFORE_ARITHMETIC_OPERATOR=textwrap.dedent("""\ Set to True to prefer splitting before '+', '-', '*', '/', '//', or '@' - rather than after."""), + rather than after. + """), SPLIT_BEFORE_BITWISE_OPERATOR=textwrap.dedent("""\ Set to True to prefer splitting before '&', '|' or '^' rather than - after."""), + after. + """), SPLIT_BEFORE_CLOSING_BRACKET=textwrap.dedent("""\ Split before the closing bracket if a list or dict literal doesn't fit on - a single line."""), + a single line. + """), SPLIT_BEFORE_DICT_SET_GENERATOR=textwrap.dedent("""\ Split before a dictionary or set generator (comp_for). For example, note the split before the 'for': @@ -335,7 +366,8 @@ def method(): foo = { variable: 'Hello world, have a nice day!' for variable in bar if variable != 42 - }"""), + } + """), SPLIT_BEFORE_DOT=textwrap.dedent("""\ Split before the '.' if we need to split a longer expression: @@ -345,19 +377,22 @@ def method(): foo = ('This is a really long string: {}, {}, {}, {}' .format(a, b, c, d)) - """), # noqa + """), # noqa SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=textwrap.dedent("""\ Split after the opening paren which surrounds an expression if it doesn't fit on a single line. - """), + """), SPLIT_BEFORE_FIRST_ARGUMENT=textwrap.dedent("""\ If an argument / parameter list is going to be split, then split before - the first argument."""), + the first argument. + """), SPLIT_BEFORE_LOGICAL_OPERATOR=textwrap.dedent("""\ Set to True to prefer splitting before 'and' or 'or' rather than - after."""), + after. + """), SPLIT_BEFORE_NAMED_ASSIGNS=textwrap.dedent("""\ - Split named assignments onto individual lines."""), + Split named assignments onto individual lines. + """), SPLIT_COMPLEX_COMPREHENSION=textwrap.dedent("""\ Set to True to split list comprehensions and generators that have non-trivial expressions and multiple clauses before each of these @@ -373,27 +408,34 @@ def method(): a_long_var + 100 for a_long_var in xrange(1000) if a_long_var % 10] - """), + """), SPLIT_PENALTY_AFTER_OPENING_BRACKET=textwrap.dedent("""\ - The penalty for splitting right after the opening bracket."""), + The penalty for splitting right after the opening bracket. + """), SPLIT_PENALTY_AFTER_UNARY_OPERATOR=textwrap.dedent("""\ - The penalty for splitting the line after a unary operator."""), + The penalty for splitting the line after a unary operator. + """), SPLIT_PENALTY_ARITHMETIC_OPERATOR=textwrap.dedent("""\ The penalty of splitting the line around the '+', '-', '*', '/', '//', - ``%``, and '@' operators."""), + `%`, and '@' operators. + """), SPLIT_PENALTY_BEFORE_IF_EXPR=textwrap.dedent("""\ - The penalty for splitting right before an if expression."""), + The penalty for splitting right before an if expression. + """), SPLIT_PENALTY_BITWISE_OPERATOR=textwrap.dedent("""\ - The penalty of splitting the line around the '&', '|', and '^' - operators."""), + The penalty of splitting the line around the '&', '|', and '^' operators. + """), SPLIT_PENALTY_COMPREHENSION=textwrap.dedent("""\ The penalty for splitting a list comprehension or generator - expression."""), + expression. + """), SPLIT_PENALTY_EXCESS_CHARACTER=textwrap.dedent("""\ - The penalty for characters over the column limit."""), + The penalty for characters over the column limit. + """), SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=textwrap.dedent("""\ The penalty incurred by adding a line split to the logical line. The - more line splits added the higher the penalty."""), + more line splits added the higher the penalty. + """), SPLIT_PENALTY_IMPORT_NAMES=textwrap.dedent("""\ The penalty of splitting a list of "import as" names. For example: @@ -405,13 +447,13 @@ def method(): from a_very_long_or_indented_module_name_yada_yad import ( long_argument_1, long_argument_2, long_argument_3) - """), # noqa + """), # noqa SPLIT_PENALTY_LOGICAL_OPERATOR=textwrap.dedent("""\ - The penalty of splitting the line around the 'and' and 'or' - operators."""), + The penalty of splitting the line around the 'and' and 'or' operators. + """), USE_TABS=textwrap.dedent("""\ - Use the Tab character for indentation."""), - # BASED_ON_STYLE='Which predefined style this style is based on', + Use the Tab character for indentation. + """), ) @@ -419,14 +461,14 @@ def CreatePEP8Style(): """Create the PEP8 formatting style.""" return dict( ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=True, - ALLOW_MULTILINE_LAMBDAS=False, ALLOW_MULTILINE_DICTIONARY_KEYS=False, + ALLOW_MULTILINE_LAMBDAS=False, ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=True, ALLOW_SPLIT_BEFORE_DICT_VALUE=True, ARITHMETIC_PRECEDENCE_INDICATION=False, - BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=True, BLANK_LINE_BEFORE_CLASS_DOCSTRING=False, BLANK_LINE_BEFORE_MODULE_DOCSTRING=False, + BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=True, BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=2, BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES=1, COALESCE_BRACKETS=False, @@ -434,12 +476,12 @@ def CreatePEP8Style(): CONTINUATION_ALIGN_STYLE='SPACE', CONTINUATION_INDENT_WIDTH=4, DEDENT_CLOSING_BRACKETS=False, - INDENT_CLOSING_BRACKETS=False, DISABLE_ENDING_COMMA_HEURISTIC=False, EACH_DICT_ENTRY_ON_SEPARATE_LINE=True, FORCE_MULTILINE_DICT=False, I18N_COMMENT='', I18N_FUNCTION_CALL='', + INDENT_CLOSING_BRACKETS=False, INDENT_DICTIONARY_VALUE=False, INDENT_WIDTH=4, INDENT_BLANK_LINES=False, @@ -447,16 +489,16 @@ def CreatePEP8Style(): NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=set(), SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=True, SPACE_INSIDE_BRACKETS=False, - SPACES_AROUND_POWER_OPERATOR=False, SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=False, SPACES_AROUND_DICT_DELIMITERS=False, SPACES_AROUND_LIST_DELIMITERS=False, + SPACES_AROUND_POWER_OPERATOR=False, SPACES_AROUND_SUBSCRIPT_COLON=False, SPACES_AROUND_TUPLE_DELIMITERS=False, SPACES_BEFORE_COMMENT=2, - SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False, SPLIT_ALL_COMMA_SEPARATED_VALUES=False, SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=False, + SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False, SPLIT_BEFORE_ARITHMETIC_OPERATOR=False, SPLIT_BEFORE_BITWISE_OPERATOR=True, SPLIT_BEFORE_CLOSING_BRACKET=True, @@ -526,15 +568,15 @@ def CreateFacebookStyle(): style['SPLIT_PENALTY_AFTER_OPENING_BRACKET'] = 0 style['SPLIT_PENALTY_BEFORE_IF_EXPR'] = 30 style['SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT'] = 30 - style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False style['SPLIT_BEFORE_BITWISE_OPERATOR'] = False + style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False return style _STYLE_NAME_TO_FACTORY = dict( - pep8=CreatePEP8Style, - google=CreateGoogleStyle, facebook=CreateFacebookStyle, + google=CreateGoogleStyle, + pep8=CreatePEP8Style, yapf=CreateYapfStyle, ) @@ -607,14 +649,14 @@ def _IntOrIntListConverter(s): # Note: this dict has to map all the supported style options. _STYLE_OPTION_VALUE_CONVERTER = dict( ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=_BoolConverter, - ALLOW_MULTILINE_LAMBDAS=_BoolConverter, ALLOW_MULTILINE_DICTIONARY_KEYS=_BoolConverter, + ALLOW_MULTILINE_LAMBDAS=_BoolConverter, ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=_BoolConverter, ALLOW_SPLIT_BEFORE_DICT_VALUE=_BoolConverter, ARITHMETIC_PRECEDENCE_INDICATION=_BoolConverter, - BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=_BoolConverter, BLANK_LINE_BEFORE_CLASS_DOCSTRING=_BoolConverter, BLANK_LINE_BEFORE_MODULE_DOCSTRING=_BoolConverter, + BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=_BoolConverter, BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=int, BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES=int, COALESCE_BRACKETS=_BoolConverter, @@ -622,29 +664,29 @@ def _IntOrIntListConverter(s): CONTINUATION_ALIGN_STYLE=_ContinuationAlignStyleStringConverter, CONTINUATION_INDENT_WIDTH=int, DEDENT_CLOSING_BRACKETS=_BoolConverter, - INDENT_CLOSING_BRACKETS=_BoolConverter, DISABLE_ENDING_COMMA_HEURISTIC=_BoolConverter, EACH_DICT_ENTRY_ON_SEPARATE_LINE=_BoolConverter, FORCE_MULTILINE_DICT=_BoolConverter, I18N_COMMENT=str, I18N_FUNCTION_CALL=_StringListConverter, + INDENT_BLANK_LINES=_BoolConverter, + INDENT_CLOSING_BRACKETS=_BoolConverter, INDENT_DICTIONARY_VALUE=_BoolConverter, INDENT_WIDTH=int, - INDENT_BLANK_LINES=_BoolConverter, JOIN_MULTIPLE_LINES=_BoolConverter, NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=_StringSetConverter, SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=_BoolConverter, SPACE_INSIDE_BRACKETS=_BoolConverter, - SPACES_AROUND_POWER_OPERATOR=_BoolConverter, SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=_BoolConverter, SPACES_AROUND_DICT_DELIMITERS=_BoolConverter, SPACES_AROUND_LIST_DELIMITERS=_BoolConverter, + SPACES_AROUND_POWER_OPERATOR=_BoolConverter, SPACES_AROUND_SUBSCRIPT_COLON=_BoolConverter, SPACES_AROUND_TUPLE_DELIMITERS=_BoolConverter, SPACES_BEFORE_COMMENT=_IntOrIntListConverter, - SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter, SPLIT_ALL_COMMA_SEPARATED_VALUES=_BoolConverter, SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=_BoolConverter, + SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter, SPLIT_BEFORE_ARITHMETIC_OPERATOR=_BoolConverter, SPLIT_BEFORE_BITWISE_OPERATOR=_BoolConverter, SPLIT_BEFORE_CLOSING_BRACKET=_BoolConverter, From e5e239df43dae438dbab7efe84b438edb0cba134 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 23 Jun 2023 13:24:34 -0500 Subject: [PATCH 648/719] Normalize test formats Testcases should be specified in the form: code = textwrap.dedent("""\ # testcase code """) --- yapftests/blank_line_calculator_test.py | 46 +- yapftests/comment_splicer_test.py | 170 +- yapftests/file_resources_test.py | 15 +- yapftests/format_decision_state_test.py | 16 +- yapftests/format_token_test.py | 5 +- yapftests/line_joiner_test.py | 12 +- yapftests/logical_line_test.py | 6 +- yapftests/pytree_unwrapper_test.py | 196 +-- yapftests/pytree_utils_test.py | 10 +- yapftests/pytree_visitor_test.py | 8 +- yapftests/reformatter_basic_test.py | 1048 ++++++------- yapftests/reformatter_buganizer_test.py | 1641 ++++++++++---------- yapftests/reformatter_facebook_test.py | 83 +- yapftests/reformatter_pep8_test.py | 572 ++++--- yapftests/reformatter_python3_test.py | 82 +- yapftests/reformatter_style_config_test.py | 20 +- yapftests/split_penalty_test.py | 70 +- yapftests/style_test.py | 40 +- yapftests/subtype_assigner_test.py | 30 +- yapftests/yapf_test.py | 712 +++++---- 20 files changed, 2392 insertions(+), 2390 deletions(-) diff --git a/yapftests/blank_line_calculator_test.py b/yapftests/blank_line_calculator_test.py index e8613b7d2..7c9ab0fe9 100644 --- a/yapftests/blank_line_calculator_test.py +++ b/yapftests/blank_line_calculator_test.py @@ -35,12 +35,12 @@ def testDecorators(self): def foo(): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ @bork() def foo(): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -59,7 +59,7 @@ class moo(object): def method(self): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ import sys @@ -76,7 +76,7 @@ class moo(object): @baz() def method(self): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -96,7 +96,7 @@ def method_2(self): raise Error except Error as error: pass - """) + """) expected_formatted_code = textwrap.dedent("""\ def foo(): pass @@ -121,7 +121,7 @@ def method_2(self): raise Error except Error as error: pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -154,7 +154,7 @@ def foo(self): # Another multiline # comment pass - """) + """) expected_formatted_code = textwrap.dedent("""\ # This is the first comment # And it's multiline @@ -187,7 +187,7 @@ def foo(self): # Another multiline # comment pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -198,7 +198,7 @@ class foo(object): # pylint: disable=invalid-name def f(self): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -211,7 +211,7 @@ def testCommentsBeforeClassDefs(self): class Foo(object): pass - ''') + ''') llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -221,7 +221,7 @@ def testCommentsBeforeDecorator(self): @foo() def a(): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -232,7 +232,7 @@ def a(): @foo() def a(): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -249,7 +249,7 @@ def _(): # reason="https://github.com/pypa/setuptools/issues/706") def test_unicode_filename_in_sdist(self, sdist_unicode, tmpdir, monkeypatch): pass - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -261,7 +261,7 @@ class Error(Exception): pass class TaskValidationError(Error): pass class DeployAPIHTTPError(Error): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ class DeployAPIClient(object): @@ -273,7 +273,7 @@ class TaskValidationError(Error): class DeployAPIHTTPError(Error): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -291,7 +291,7 @@ def D(): # 9 pass # 10 def E(): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ def A(): pass @@ -308,7 +308,7 @@ def D(): # 9 pass # 10 def E(): pass - """) + """) code, changed = yapf_api.FormatCode( unformatted_code, lines=[(4, 5), (9, 10)]) self.assertCodeEqual(expected_formatted_code, code) @@ -328,7 +328,7 @@ def B(): # 6 def C(): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ def A(): pass @@ -342,7 +342,7 @@ def B(): # 6 def C(): pass - """) + """) code, changed = yapf_api.FormatCode(unformatted_code, lines=[(6, 7)]) self.assertCodeEqual(expected_formatted_code, code) self.assertFalse(changed) @@ -362,7 +362,7 @@ def B(): # 6 def C(): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ def A(): pass @@ -376,7 +376,7 @@ def B(): # 6 def C(): pass - """) + """) code, changed = yapf_api.FormatCode(unformatted_code, lines=[(5, 9)]) self.assertCodeEqual(expected_formatted_code, code) self.assertTrue(changed) @@ -397,7 +397,7 @@ def B(): # 7 def C(): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ def A(): pass @@ -412,7 +412,7 @@ def B(): # 7 def C(): pass - """) + """) code, changed = yapf_api.FormatCode(unformatted_code, lines=[(6, 9)]) self.assertCodeEqual(expected_formatted_code, code) self.assertTrue(changed) diff --git a/yapftests/comment_splicer_test.py b/yapftests/comment_splicer_test.py index 64cb7083e..3a63da7ca 100644 --- a/yapftests/comment_splicer_test.py +++ b/yapftests/comment_splicer_test.py @@ -19,8 +19,10 @@ from yapf.pytree import comment_splicer from yapf.pytree import pytree_utils +from yapftests import yapf_test_helper -class CommentSplicerTest(unittest.TestCase): + +class CommentSplicerTest(yapf_test_helper.YAPFTest): def _AssertNodeType(self, expected_type, node): self.assertEqual(expected_type, pytree_utils.NodeName(node)) @@ -43,7 +45,9 @@ def _FindNthChildNamed(self, node, name, n=1): raise RuntimeError('No Nth child for n={0}'.format(n)) def testSimpleInline(self): - code = 'foo = 1 # and a comment\n' + code = textwrap.dedent("""\ + foo = 1 # and a comment + """) tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) @@ -56,11 +60,11 @@ def testSimpleInline(self): self._AssertNodeIsComment(comment_node, '# and a comment') def testSimpleSeparateLine(self): - code = textwrap.dedent(r''' - foo = 1 - # first comment - bar = 2 - ''') + code = textwrap.dedent("""\ + foo = 1 + # first comment + bar = 2 + """) tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) @@ -71,12 +75,12 @@ def testSimpleSeparateLine(self): self._AssertNodeIsComment(comment_node) def testTwoLineComment(self): - code = textwrap.dedent(r''' - foo = 1 - # first comment - # second comment - bar = 2 - ''') + code = textwrap.dedent("""\ + foo = 1 + # first comment + # second comment + bar = 2 + """) tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) @@ -85,11 +89,11 @@ def testTwoLineComment(self): self._AssertNodeIsComment(tree.children[1]) def testCommentIsFirstChildInCompound(self): - code = textwrap.dedent(r''' - if x: - # a comment - foo = 1 - ''') + code = textwrap.dedent(""" + if x: + # a comment + foo = 1 + """) tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) @@ -101,11 +105,11 @@ def testCommentIsFirstChildInCompound(self): self._AssertNodeIsComment(if_suite.children[1]) def testCommentIsLastChildInCompound(self): - code = textwrap.dedent(r''' - if x: - foo = 1 - # a comment - ''') + code = textwrap.dedent("""\ + if x: + foo = 1 + # a comment + """) tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) @@ -117,11 +121,11 @@ def testCommentIsLastChildInCompound(self): self._AssertNodeIsComment(if_suite.children[-2]) def testInlineAfterSeparateLine(self): - code = textwrap.dedent(r''' - bar = 1 - # line comment - foo = 1 # inline comment - ''') + code = textwrap.dedent("""\ + bar = 1 + # line comment + foo = 1 # inline comment + """) tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) @@ -135,11 +139,11 @@ def testInlineAfterSeparateLine(self): self._AssertNodeIsComment(inline_comment_node, '# inline comment') def testSeparateLineAfterInline(self): - code = textwrap.dedent(r''' - bar = 1 - foo = 1 # inline comment - # line comment - ''') + code = textwrap.dedent("""\ + bar = 1 + foo = 1 # inline comment + # line comment + """) tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) @@ -153,12 +157,12 @@ def testSeparateLineAfterInline(self): self._AssertNodeIsComment(inline_comment_node, '# inline comment') def testCommentBeforeDedent(self): - code = textwrap.dedent(r''' - if bar: - z = 1 - # a comment - j = 2 - ''') + code = textwrap.dedent("""\ + if bar: + z = 1 + # a comment + j = 2 + """) tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) @@ -168,13 +172,13 @@ def testCommentBeforeDedent(self): self._AssertNodeType('DEDENT', if_suite.children[-1]) def testCommentBeforeDedentTwoLevel(self): - code = textwrap.dedent(r''' - if foo: - if bar: - z = 1 - # a comment - y = 1 - ''') + code = textwrap.dedent("""\ + if foo: + if bar: + z = 1 + # a comment + y = 1 + """) tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) @@ -185,13 +189,13 @@ def testCommentBeforeDedentTwoLevel(self): self._AssertNodeType('DEDENT', if_suite.children[-1]) def testCommentBeforeDedentTwoLevelImproperlyIndented(self): - code = textwrap.dedent(r''' - if foo: - if bar: - z = 1 - # comment 2 - y = 1 - ''') + code = textwrap.dedent("""\ + if foo: + if bar: + z = 1 + # comment 2 + y = 1 + """) tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) @@ -205,15 +209,15 @@ def testCommentBeforeDedentTwoLevelImproperlyIndented(self): self._AssertNodeType('DEDENT', if_suite.children[-1]) def testCommentBeforeDedentThreeLevel(self): - code = textwrap.dedent(r''' - if foo: - if bar: - z = 1 - # comment 2 - # comment 1 - # comment 0 - j = 2 - ''') + code = textwrap.dedent("""\ + if foo: + if bar: + z = 1 + # comment 2 + # comment 1 + # comment 0 + j = 2 + """) tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) @@ -232,13 +236,13 @@ def testCommentBeforeDedentThreeLevel(self): self._AssertNodeType('DEDENT', if_suite_2.children[-1]) def testCommentsInClass(self): - code = textwrap.dedent(r''' - class Foo: - """docstring abc...""" - # top-level comment - def foo(): pass - # another comment - ''') + code = textwrap.dedent("""\ + class Foo: + '''docstring abc...''' + # top-level comment + def foo(): pass + # another comment + """) tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) @@ -254,13 +258,13 @@ def foo(): pass self._AssertNodeIsComment(toplevel_comment, '# top-level') def testMultipleBlockComments(self): - code = textwrap.dedent(r''' + code = textwrap.dedent("""\ # Block comment number 1 # Block comment number 2 def f(): pass - ''') + """) tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) @@ -273,7 +277,7 @@ def f(): self._AssertNodeIsComment(block_comment_2, '# Block comment number 2') def testCommentsOnDedents(self): - code = textwrap.dedent(r''' + code = textwrap.dedent("""\ class Foo(object): # A comment for qux. def qux(self): @@ -283,7 +287,7 @@ def qux(self): def mux(self): pass - ''') + """) tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) @@ -297,10 +301,10 @@ def mux(self): self._AssertNodeIsComment(interim_comment, '# Interim comment.') def testExprComments(self): - code = textwrap.dedent(r''' - foo( # Request fractions of an hour. - 948.0/3600, 20) - ''') + code = textwrap.dedent("""\ + foo( # Request fractions of an hour. + 948.0/3600, 20) + """) tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) @@ -309,12 +313,12 @@ def testExprComments(self): self._AssertNodeIsComment(comment, '# Request fractions of an hour.') def testMultipleCommentsInOneExpr(self): - code = textwrap.dedent(r''' - foo( # com 1 - 948.0/3600, # com 2 - 20 + 12 # com 3 - ) - ''') + code = textwrap.dedent("""\ + foo( # com 1 + 948.0/3600, # com 2 + 20 + 12 # com 3 + ) + """) tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index 888dea473..c55333f9d 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -26,6 +26,7 @@ from yapf.yapflib import file_resources from yapftests import utils +from yapftests import yapf_test_helper @contextlib.contextmanager @@ -47,7 +48,7 @@ def _exists_mocked_in_module(module, mock_implementation): setattr(module, 'exists', unmocked_exists) -class GetExcludePatternsForDir(unittest.TestCase): +class GetExcludePatternsForDir(yapf_test_helper.YAPFTest): def setUp(self): # pylint: disable=g-missing-super-call self.test_tmpdir = tempfile.mkdtemp() @@ -126,7 +127,7 @@ def test_get_exclude_file_patterns_with_no_config_files(self): sorted(ignore_patterns)) -class GetDefaultStyleForDirTest(unittest.TestCase): +class GetDefaultStyleForDirTest(yapf_test_helper.YAPFTest): def setUp(self): # pylint: disable=g-missing-super-call self.test_tmpdir = tempfile.mkdtemp() @@ -221,7 +222,7 @@ def _touch_files(filenames): open(name, 'a').close() -class GetCommandLineFilesTest(unittest.TestCase): +class GetCommandLineFilesTest(yapf_test_helper.YAPFTest): def setUp(self): # pylint: disable=g-missing-super-call self.test_tmpdir = tempfile.mkdtemp() @@ -408,7 +409,7 @@ def test_find_with_excluded_current_dir(self): file_resources.GetCommandLineFiles([], False, exclude=['./z']) -class IsPythonFileTest(unittest.TestCase): +class IsPythonFileTest(yapf_test_helper.YAPFTest): def setUp(self): # pylint: disable=g-missing-super-call self.test_tmpdir = tempfile.mkdtemp() @@ -451,7 +452,7 @@ def test_with_invalid_encoding(self): self.assertFalse(file_resources.IsPythonFile(file1)) -class IsIgnoredTest(unittest.TestCase): +class IsIgnoredTest(yapf_test_helper.YAPFTest): def test_root_path(self): self.assertTrue(file_resources.IsIgnored('media', ['media'])) @@ -480,7 +481,7 @@ def buffer(self): return self.stream -class WriteReformattedCodeTest(unittest.TestCase): +class WriteReformattedCodeTest(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): # pylint: disable=g-missing-super-call @@ -517,7 +518,7 @@ def test_write_encoded_to_stdout(self): self.assertEqual(stream.getvalue(), s) -class LineEndingTest(unittest.TestCase): +class LineEndingTest(yapf_test_helper.YAPFTest): def test_line_ending_linefeed(self): lines = ['spam\n', 'spam\n'] diff --git a/yapftests/format_decision_state_test.py b/yapftests/format_decision_state_test.py index 3bff578da..4dd7b8b53 100644 --- a/yapftests/format_decision_state_test.py +++ b/yapftests/format_decision_state_test.py @@ -31,10 +31,10 @@ def setUpClass(cls): style.SetGlobalStyle(style.CreateYapfStyle()) def testSimpleFunctionDefWithNoSplitting(self): - code = textwrap.dedent(r""" - def f(a, b): - pass - """) + code = textwrap.dedent("""\ + def f(a, b): + pass + """) llines = yapf_test_helper.ParseAndUnwrap(code) lline = logical_line.LogicalLine(0, _FilterLine(llines[0])) lline.CalculateFormattingInformation() @@ -85,10 +85,10 @@ def f(a, b): self.assertEqual(repr(state), repr(clone)) def testSimpleFunctionDefWithSplitting(self): - code = textwrap.dedent(r""" - def f(a, b): - pass - """) + code = textwrap.dedent("""\ + def f(a, b): + pass + """) llines = yapf_test_helper.ParseAndUnwrap(code) lline = logical_line.LogicalLine(0, _FilterLine(llines[0])) lline.CalculateFormattingInformation() diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index 59c167c13..72b378430 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -20,8 +20,9 @@ from yapf.yapflib import format_token +from yapftests import yapf_test_helper -class TabbedContinuationAlignPaddingTest(unittest.TestCase): +class TabbedContinuationAlignPaddingTest(yapf_test_helper.YAPFTest): def testSpace(self): align_style = 'SPACE' @@ -63,7 +64,7 @@ def testVAlignRight(self): self.assertEqual(pad, '\t' * 2) -class FormatTokenTest(unittest.TestCase): +class FormatTokenTest(yapf_test_helper.YAPFTest): def testSimple(self): tok = format_token.FormatToken( diff --git a/yapftests/line_joiner_test.py b/yapftests/line_joiner_test.py index 4fb55f4a3..01dd479b2 100644 --- a/yapftests/line_joiner_test.py +++ b/yapftests/line_joiner_test.py @@ -41,14 +41,14 @@ def _CheckLineJoining(self, code, join_lines): def testSimpleSingleLineStatement(self): code = textwrap.dedent("""\ if isinstance(a, int): continue - """) + """) self._CheckLineJoining(code, join_lines=True) def testSimpleMultipleLineStatement(self): code = textwrap.dedent("""\ if isinstance(b, int): continue - """) + """) self._CheckLineJoining(code, join_lines=False) def testSimpleMultipleLineComplexStatement(self): @@ -56,25 +56,25 @@ def testSimpleMultipleLineComplexStatement(self): if isinstance(c, int): while True: continue - """) + """) self._CheckLineJoining(code, join_lines=False) def testSimpleMultipleLineStatementWithComment(self): code = textwrap.dedent("""\ if isinstance(d, int): continue # We're pleased that d's an int. - """) + """) self._CheckLineJoining(code, join_lines=True) def testSimpleMultipleLineStatementWithLargeIndent(self): code = textwrap.dedent("""\ if isinstance(e, int): continue - """) + """) self._CheckLineJoining(code, join_lines=True) def testOverColumnLimit(self): code = textwrap.dedent("""\ if instance(bbbbbbbbbbbbbbbbbbbbbbbbb, int): cccccccccccccccccccccccccc = ddddddddddddddddddddd - """) # noqa + """) # noqa self._CheckLineJoining(code, join_lines=False) diff --git a/yapftests/logical_line_test.py b/yapftests/logical_line_test.py index bcb2b6133..2526b591c 100644 --- a/yapftests/logical_line_test.py +++ b/yapftests/logical_line_test.py @@ -26,7 +26,7 @@ from yapftests import yapf_test_helper -class LogicalLineBasicTest(unittest.TestCase): +class LogicalLineBasicTest(yapf_test_helper.YAPFTest): def testConstruction(self): toks = _MakeFormatTokenList([(token.DOT, '.', 'DOT'), @@ -61,10 +61,10 @@ def testAppendToken(self): class LogicalLineFormattingInformationTest(yapf_test_helper.YAPFTest): def testFuncDef(self): - code = textwrap.dedent(r""" + code = textwrap.dedent("""\ def f(a, b): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) f = llines[0].tokens[1] diff --git a/yapftests/pytree_unwrapper_test.py b/yapftests/pytree_unwrapper_test.py index 525278def..b297560d8 100644 --- a/yapftests/pytree_unwrapper_test.py +++ b/yapftests/pytree_unwrapper_test.py @@ -43,11 +43,11 @@ def _CheckLogicalLines(self, llines, list_of_expected): self.assertEqual(list_of_expected, actual) def testSimpleFileScope(self): - code = textwrap.dedent(r""" - x = 1 - # a comment - y = 2 - """) + code = textwrap.dedent("""\ + x = 1 + # a comment + y = 2 + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckLogicalLines(llines, [ (0, ['x', '=', '1']), @@ -56,20 +56,20 @@ def testSimpleFileScope(self): ]) def testSimpleMultilineStatement(self): - code = textwrap.dedent(r""" - y = (1 + - x) - """) + code = textwrap.dedent("""\ + y = (1 + + x) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckLogicalLines(llines, [ (0, ['y', '=', '(', '1', '+', 'x', ')']), ]) def testFileScopeWithInlineComment(self): - code = textwrap.dedent(r""" - x = 1 # a comment - y = 2 - """) + code = textwrap.dedent("""\ + x = 1 # a comment + y = 2 + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckLogicalLines(llines, [ (0, ['x', '=', '1', '# a comment']), @@ -77,11 +77,11 @@ def testFileScopeWithInlineComment(self): ]) def testSimpleIf(self): - code = textwrap.dedent(r""" - if foo: - x = 1 - y = 2 - """) + code = textwrap.dedent("""\ + if foo: + x = 1 + y = 2 + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckLogicalLines(llines, [ (0, ['if', 'foo', ':']), @@ -90,12 +90,12 @@ def testSimpleIf(self): ]) def testSimpleIfWithComments(self): - code = textwrap.dedent(r""" - # c1 - if foo: # c2 - x = 1 - y = 2 - """) + code = textwrap.dedent("""\ + # c1 + if foo: # c2 + x = 1 + y = 2 + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckLogicalLines(llines, [ (0, ['# c1']), @@ -105,13 +105,13 @@ def testSimpleIfWithComments(self): ]) def testIfWithCommentsInside(self): - code = textwrap.dedent(r""" - if foo: - # c1 - x = 1 # c2 - # c3 - y = 2 - """) + code = textwrap.dedent("""\ + if foo: + # c1 + x = 1 # c2 + # c3 + y = 2 + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckLogicalLines(llines, [ (0, ['if', 'foo', ':']), @@ -122,15 +122,15 @@ def testIfWithCommentsInside(self): ]) def testIfElifElse(self): - code = textwrap.dedent(r""" - if x: - x = 1 # c1 - elif y: # c2 - y = 1 - else: - # c3 - z = 1 - """) + code = textwrap.dedent("""\ + if x: + x = 1 # c1 + elif y: # c2 + y = 1 + else: + # c3 + z = 1 + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckLogicalLines(llines, [ (0, ['if', 'x', ':']), @@ -143,14 +143,14 @@ def testIfElifElse(self): ]) def testNestedCompoundTwoLevel(self): - code = textwrap.dedent(r""" - if x: - x = 1 # c1 - while t: - # c2 - j = 1 - k = 1 - """) + code = textwrap.dedent("""\ + if x: + x = 1 # c1 + while t: + # c2 + j = 1 + k = 1 + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckLogicalLines(llines, [ (0, ['if', 'x', ':']), @@ -162,11 +162,11 @@ def testNestedCompoundTwoLevel(self): ]) def testSimpleWhile(self): - code = textwrap.dedent(r""" - while x > 1: # c1 - # c2 - x = 1 - """) + code = textwrap.dedent("""\ + while x > 1: # c1 + # c2 + x = 1 + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckLogicalLines(llines, [ (0, ['while', 'x', '>', '1', ':', '# c1']), @@ -175,18 +175,18 @@ def testSimpleWhile(self): ]) def testSimpleTry(self): - code = textwrap.dedent(r""" - try: - pass - except: - pass - except: - pass - else: - pass - finally: - pass - """) + code = textwrap.dedent("""\ + try: + pass + except: + pass + except: + pass + else: + pass + finally: + pass + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckLogicalLines(llines, [ (0, ['try', ':']), @@ -202,11 +202,11 @@ def testSimpleTry(self): ]) def testSimpleFuncdef(self): - code = textwrap.dedent(r""" - def foo(x): # c1 - # c2 - return x - """) + code = textwrap.dedent("""\ + def foo(x): # c1 + # c2 + return x + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckLogicalLines(llines, [ (0, ['def', 'foo', '(', 'x', ')', ':', '# c1']), @@ -215,15 +215,15 @@ def foo(x): # c1 ]) def testTwoFuncDefs(self): - code = textwrap.dedent(r""" - def foo(x): # c1 - # c2 - return x - - def bar(): # c3 - # c4 - return x - """) + code = textwrap.dedent("""\ + def foo(x): # c1 + # c2 + return x + + def bar(): # c3 + # c4 + return x + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckLogicalLines(llines, [ (0, ['def', 'foo', '(', 'x', ')', ':', '# c1']), @@ -235,11 +235,11 @@ def bar(): # c3 ]) def testSimpleClassDef(self): - code = textwrap.dedent(r""" - class Klass: # c1 - # c2 - p = 1 - """) + code = textwrap.dedent("""\ + class Klass: # c1 + # c2 + p = 1 + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckLogicalLines(llines, [ (0, ['class', 'Klass', ':', '# c1']), @@ -248,9 +248,9 @@ class Klass: # c1 ]) def testSingleLineStmtInFunc(self): - code = textwrap.dedent(r""" + code = textwrap.dedent("""\ def f(): return 37 - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckLogicalLines(llines, [ (0, ['def', 'f', '(', ')', ':']), @@ -258,13 +258,13 @@ def f(): return 37 ]) def testMultipleComments(self): - code = textwrap.dedent(r""" + code = textwrap.dedent("""\ # Comment #1 # Comment #2 def f(): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckLogicalLines(llines, [ (0, ['# Comment #1']), @@ -274,13 +274,13 @@ def f(): ]) def testSplitListWithComment(self): - code = textwrap.dedent(r""" - a = [ - 'a', - 'b', - 'c', # hello world - ] - """) + code = textwrap.dedent("""\ + a = [ + 'a', + 'b', + 'c', # hello world + ] + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckLogicalLines(llines, [(0, [ 'a', '=', '[', "'a'", ',', "'b'", ',', "'c'", ',', '# hello world', ']' @@ -320,7 +320,7 @@ def testFunctionDef(self): code = textwrap.dedent("""\ def foo(a, b=['w','d'], c=[42, 37]): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckMatchingBrackets(llines, [ [(2, 20), (7, 11), (15, 19)], @@ -332,7 +332,7 @@ def testDecorator(self): @bar() def foo(a, b, c): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckMatchingBrackets(llines, [ [(2, 3)], @@ -344,7 +344,7 @@ def testClassDef(self): code = textwrap.dedent("""\ class A(B, C, D): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckMatchingBrackets(llines, [ [(2, 8)], diff --git a/yapftests/pytree_utils_test.py b/yapftests/pytree_utils_test.py index a0be50d03..fe31eb83c 100644 --- a/yapftests/pytree_utils_test.py +++ b/yapftests/pytree_utils_test.py @@ -21,6 +21,8 @@ from yapf.pytree import pytree_utils +from yapftests import yapf_test_helper + # More direct access to the symbol->number mapping living within the grammar # module. _GRAMMAR_SYMBOL2NUMBER = pygram.python_grammar.symbol2number @@ -33,7 +35,7 @@ _FOO5 = 'foo5' -class NodeNameTest(unittest.TestCase): +class NodeNameTest(yapf_test_helper.YAPFTest): def testNodeNameForLeaf(self): leaf = pytree.Leaf(token.LPAR, '(') @@ -45,7 +47,7 @@ def testNodeNameForNode(self): self.assertEqual('suite', pytree_utils.NodeName(node)) -class ParseCodeToTreeTest(unittest.TestCase): +class ParseCodeToTreeTest(yapf_test_helper.YAPFTest): def testParseCodeToTree(self): # Since ParseCodeToTree is a thin wrapper around underlying lib2to3 @@ -71,7 +73,7 @@ def testClassNotLocal(self): pytree_utils.ParseCodeToTree('class nonlocal: pass\n') -class InsertNodesBeforeAfterTest(unittest.TestCase): +class InsertNodesBeforeAfterTest(yapf_test_helper.YAPFTest): def _BuildSimpleTree(self): # Builds a simple tree we can play with in the tests. @@ -143,7 +145,7 @@ def testInsertNodesWhichHasParent(self): self._simple_tree.children[0]) -class AnnotationsTest(unittest.TestCase): +class AnnotationsTest(yapf_test_helper.YAPFTest): def setUp(self): self._leaf = pytree.Leaf(token.LPAR, '(') diff --git a/yapftests/pytree_visitor_test.py b/yapftests/pytree_visitor_test.py index d9000133c..1d908d4d3 100644 --- a/yapftests/pytree_visitor_test.py +++ b/yapftests/pytree_visitor_test.py @@ -19,6 +19,8 @@ from yapf.pytree import pytree_utils from yapf.pytree import pytree_visitor +from yapftests import yapf_test_helper + class _NodeNameCollector(pytree_visitor.PyTreeVisitor): """A tree visitor that collects the names of all tree nodes into a list. @@ -46,19 +48,19 @@ def Visit_NAME(self, leaf): self.DefaultLeafVisit(leaf) -_VISITOR_TEST_SIMPLE_CODE = r""" +_VISITOR_TEST_SIMPLE_CODE = """\ foo = bar baz = x """ -_VISITOR_TEST_NESTED_CODE = r""" +_VISITOR_TEST_NESTED_CODE = """\ if x: if y: return z """ -class PytreeVisitorTest(unittest.TestCase): +class PytreeVisitorTest(yapf_test_helper.YAPFTest): def testCollectAllNodeNamesSimpleCode(self): tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_SIMPLE_CODE) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 034c45d6c..0a05b3b1b 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -37,75 +37,75 @@ def testSplittingAllArgs(self): style.CreateStyleFromConfig( '{split_all_comma_separated_values: true, column_limit: 40}')) unformatted_code = textwrap.dedent("""\ - responseDict = {"timestamp": timestamp, "someValue": value, "whatever": 120} - """) # noqa + responseDict = {"timestamp": timestamp, "someValue": value, "whatever": 120} + """) # noqa expected_formatted_code = textwrap.dedent("""\ - responseDict = { - "timestamp": timestamp, - "someValue": value, - "whatever": 120 - } - """) + responseDict = { + "timestamp": timestamp, + "someValue": value, + "whatever": 120 + } + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ - yes = { 'yes': 'no', 'no': 'yes', } - """) + yes = { 'yes': 'no', 'no': 'yes', } + """) expected_formatted_code = textwrap.dedent("""\ - yes = { - 'yes': 'no', - 'no': 'yes', - } - """) + yes = { + 'yes': 'no', + 'no': 'yes', + } + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ - def foo(long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args): - pass - """) # noqa - expected_formatted_code = textwrap.dedent("""\ - def foo(long_arg, - really_long_arg, - really_really_long_arg, - cant_keep_all_these_args): + def foo(long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args): pass - """) + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + def foo(long_arg, + really_long_arg, + really_really_long_arg, + cant_keep_all_these_args): + pass + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ - foo_tuple = [long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args] - """) # noqa + foo_tuple = [long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args] + """) # noqa expected_formatted_code = textwrap.dedent("""\ - foo_tuple = [ - long_arg, - really_long_arg, - really_really_long_arg, - cant_keep_all_these_args - ] - """) + foo_tuple = [ + long_arg, + really_long_arg, + really_really_long_arg, + cant_keep_all_these_args + ] + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ - foo_tuple = [short, arg] - """) + foo_tuple = [short, arg] + """) expected_formatted_code = textwrap.dedent("""\ - foo_tuple = [short, arg] - """) + foo_tuple = [short, arg] + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # There is a test for split_all_top_level_comma_separated_values, with # different expected value unformatted_code = textwrap.dedent("""\ - someLongFunction(this_is_a_very_long_parameter, - abc=(a, this_will_just_fit_xxxxxxx)) - """) + someLongFunction(this_is_a_very_long_parameter, + abc=(a, this_will_just_fit_xxxxxxx)) + """) expected_formatted_code = textwrap.dedent("""\ - someLongFunction( - this_is_a_very_long_parameter, - abc=(a, - this_will_just_fit_xxxxxxx)) - """) + someLongFunction( + this_is_a_very_long_parameter, + abc=(a, + this_will_just_fit_xxxxxxx)) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -116,114 +116,114 @@ def testSplittingTopLevelAllArgs(self): 'column_limit: 40}')) # Works the same way as split_all_comma_separated_values unformatted_code = textwrap.dedent("""\ - responseDict = {"timestamp": timestamp, "someValue": value, "whatever": 120} - """) # noqa + responseDict = {"timestamp": timestamp, "someValue": value, "whatever": 120} + """) # noqa expected_formatted_code = textwrap.dedent("""\ - responseDict = { - "timestamp": timestamp, - "someValue": value, - "whatever": 120 - } - """) + responseDict = { + "timestamp": timestamp, + "someValue": value, + "whatever": 120 + } + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Works the same way as split_all_comma_separated_values unformatted_code = textwrap.dedent("""\ - def foo(long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args): - pass - """) # noqa + def foo(long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args): + pass + """) # noqa expected_formatted_code = textwrap.dedent("""\ - def foo(long_arg, - really_long_arg, - really_really_long_arg, - cant_keep_all_these_args): - pass - """) + def foo(long_arg, + really_long_arg, + really_really_long_arg, + cant_keep_all_these_args): + pass + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Works the same way as split_all_comma_separated_values unformatted_code = textwrap.dedent("""\ - foo_tuple = [long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args] - """) # noqa + foo_tuple = [long_arg, really_long_arg, really_really_long_arg, cant_keep_all_these_args] + """) # noqa expected_formatted_code = textwrap.dedent("""\ - foo_tuple = [ - long_arg, - really_long_arg, - really_really_long_arg, - cant_keep_all_these_args - ] - """) + foo_tuple = [ + long_arg, + really_long_arg, + really_really_long_arg, + cant_keep_all_these_args + ] + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Works the same way as split_all_comma_separated_values unformatted_code = textwrap.dedent("""\ - foo_tuple = [short, arg] - """) + foo_tuple = [short, arg] + """) expected_formatted_code = textwrap.dedent("""\ - foo_tuple = [short, arg] - """) + foo_tuple = [short, arg] + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # There is a test for split_all_comma_separated_values, with different # expected value unformatted_code = textwrap.dedent("""\ - someLongFunction(this_is_a_very_long_parameter, - abc=(a, this_will_just_fit_xxxxxxx)) - """) + someLongFunction(this_is_a_very_long_parameter, + abc=(a, this_will_just_fit_xxxxxxx)) + """) expected_formatted_code = textwrap.dedent("""\ - someLongFunction( - this_is_a_very_long_parameter, - abc=(a, this_will_just_fit_xxxxxxx)) - """) + someLongFunction( + this_is_a_very_long_parameter, + abc=(a, this_will_just_fit_xxxxxxx)) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) actual_formatted_code = reformatter.Reformat(llines) self.assertEqual(40, len(actual_formatted_code.splitlines()[-1])) self.assertCodeEqual(expected_formatted_code, actual_formatted_code) unformatted_code = textwrap.dedent("""\ - someLongFunction(this_is_a_very_long_parameter, - abc=(a, this_will_not_fit_xxxxxxxxx)) - """) + someLongFunction(this_is_a_very_long_parameter, + abc=(a, this_will_not_fit_xxxxxxxxx)) + """) expected_formatted_code = textwrap.dedent("""\ - someLongFunction( - this_is_a_very_long_parameter, - abc=(a, - this_will_not_fit_xxxxxxxxx)) - """) + someLongFunction( + this_is_a_very_long_parameter, + abc=(a, + this_will_not_fit_xxxxxxxxx)) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Exercise the case where there's no opening bracket (for a, b) unformatted_code = textwrap.dedent("""\ - a, b = f( - a_very_long_parameter, yet_another_one, and_another) - """) + a, b = f( + a_very_long_parameter, yet_another_one, and_another) + """) expected_formatted_code = textwrap.dedent("""\ - a, b = f( - a_very_long_parameter, yet_another_one, and_another) - """) + a, b = f( + a_very_long_parameter, yet_another_one, and_another) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # Don't require splitting before comments. unformatted_code = textwrap.dedent("""\ - KO = { - 'ABC': Abc, # abc - 'DEF': Def, # def - 'LOL': Lol, # wtf - 'GHI': Ghi, - 'JKL': Jkl, - } - """) - expected_formatted_code = textwrap.dedent("""\ - KO = { - 'ABC': Abc, # abc - 'DEF': Def, # def - 'LOL': Lol, # wtf - 'GHI': Ghi, - 'JKL': Jkl, - } - """) + KO = { + 'ABC': Abc, # abc + 'DEF': Def, # def + 'LOL': Lol, # wtf + 'GHI': Ghi, + 'JKL': Jkl, + } + """) + expected_formatted_code = textwrap.dedent("""\ + KO = { + 'ABC': Abc, # abc + 'DEF': Def, # def + 'LOL': Lol, # wtf + 'GHI': Ghi, + 'JKL': Jkl, + } + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -239,7 +239,7 @@ def f( # Intermediate comment if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ def g(): # Trailing comment if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and @@ -252,7 +252,7 @@ def f( # Intermediate comment if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -260,12 +260,12 @@ def testBlankLinesBetweenTopLevelImportsAndVariables(self): unformatted_code = textwrap.dedent("""\ import foo as bar VAR = 'baz' - """) + """) expected_formatted_code = textwrap.dedent("""\ import foo as bar VAR = 'baz' - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -273,13 +273,13 @@ def testBlankLinesBetweenTopLevelImportsAndVariables(self): import foo as bar VAR = 'baz' - """) + """) expected_formatted_code = textwrap.dedent("""\ import foo as bar VAR = 'baz' - """) + """) try: style.SetGlobalStyle( style.CreateStyleFromConfig( @@ -294,11 +294,11 @@ def testBlankLinesBetweenTopLevelImportsAndVariables(self): unformatted_code = textwrap.dedent("""\ import foo as bar # Some comment - """) + """) expected_formatted_code = textwrap.dedent("""\ import foo as bar # Some comment - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -306,14 +306,14 @@ def testBlankLinesBetweenTopLevelImportsAndVariables(self): import foo as bar class Baz(): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ import foo as bar class Baz(): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -321,14 +321,14 @@ class Baz(): import foo as bar def foobar(): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ import foo as bar def foobar(): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -336,12 +336,12 @@ def foobar(): def foobar(): from foo import Bar Bar.baz() - """) + """) expected_formatted_code = textwrap.dedent("""\ def foobar(): from foo import Bar Bar.baz() - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -352,11 +352,11 @@ def foobar(): # foo - """) + """) expected_formatted_code = textwrap.dedent("""\ def foobar(): # foo pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -365,10 +365,10 @@ def foobar(): # foo 'c':927} - """) + """) expected_formatted_code = textwrap.dedent("""\ x = {'a': 37, 'b': 42, 'c': 927} - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -390,7 +390,7 @@ def barfoo(self, x, y): # bar def bar(): return 0 - """) + """) expected_formatted_code = """\ class foo(object):\n \n def foobar(self):\n \n pass\n \n def barfoo(self, x, y): # bar\n \n if x:\n \n return y\n\n\ndef bar():\n \n return 0 """ # noqa @@ -427,7 +427,7 @@ def g(self, x,y=42): return y def f ( a ) : return 37+-+a[42-x : y**3] - """) + """) expected_formatted_code = textwrap.dedent("""\ x = {'a': 37, 'b': 42, 'c': 927} @@ -447,7 +447,7 @@ def g(self, x, y=42): def f(a): return 37 + -+a[42 - x:y**3] - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -473,7 +473,7 @@ class Baz(object): class Qux(object): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ class Foo(object): pass @@ -500,14 +500,14 @@ class Baz(object): class Qux(object): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSingleComment(self): code = textwrap.dedent("""\ # Thing 1 - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -517,7 +517,7 @@ def testCommentsWithTrailingSpaces(self): expected_formatted_code = textwrap.dedent("""\ # Thing 1 # Thing 2 - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -534,7 +534,7 @@ def f(): # Ending comment. }) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -543,7 +543,7 @@ def testEndingWhitespaceAfterSimpleStatement(self): import foo as bar # Thing 1 # Thing 2 - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -564,7 +564,7 @@ def qux(self): """ print('hello {}'.format('world')) return 42 - ''') + ''') expected_formatted_code = textwrap.dedent('''\ u"""Module-level docstring.""" import os @@ -581,7 +581,7 @@ def qux(self): """ print('hello {}'.format('world')) return 42 - ''') + ''') llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -599,7 +599,7 @@ def foo(self): # Another multiline # comment pass - ''') + ''') expected_formatted_code = textwrap.dedent('''\ """Hello world""" @@ -616,7 +616,7 @@ def foo(self): # Another multiline # comment pass - ''') + ''') llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -643,7 +643,7 @@ def foo(self): # Another multiline # comment pass - ''') + ''') expected_formatted_code = textwrap.dedent('''\ """Hello world @@ -669,17 +669,17 @@ def foo(self): # Another multiline # comment pass - ''') + ''') llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testTupleCommaBeforeLastParen(self): unformatted_code = textwrap.dedent("""\ a = ( 1, ) - """) + """) expected_formatted_code = textwrap.dedent("""\ a = (1,) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -695,7 +695,7 @@ def f(): def f(): assert port >= minimum, 'Unexpected port %d when minimum was %d.' % (port, minimum) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -707,7 +707,7 @@ class A(object): @baz() def x(self): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ @foo() class A(object): @@ -716,7 +716,7 @@ class A(object): @baz() def x(self): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -727,14 +727,14 @@ def testCommentBetweenDecorators(self): @bar def x (self): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ @foo() # frob @bar def x(self): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -743,11 +743,11 @@ def testListComprehension(self): def given(y): [k for k in () if k in y] - """) + """) expected_formatted_code = textwrap.dedent("""\ def given(y): [k for k in () if k in y] - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -758,13 +758,13 @@ def given(y): long_var_name + 1 for long_var_name in () if long_var_name == 2] - """) + """) expected_formatted_code = textwrap.dedent("""\ def given(y): long_variable_name = [ long_var_name + 1 for long_var_name in () if long_var_name == 2 ] - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -773,12 +773,12 @@ def testListComprehensionPreferOneLineOverArithmeticSplit(self): def given(used_identifiers): return (sum(len(identifier) for identifier in used_identifiers) / len(used_identifiers)) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def given(used_identifiers): return (sum(len(identifier) for identifier in used_identifiers) / len(used_identifiers)) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -789,7 +789,7 @@ def given(y): long_var_name + 1 for long_var_name, number_two in () if long_var_name == 2 and number_two == 3] - """) + """) expected_formatted_code = textwrap.dedent("""\ def given(y): long_variable_name = [ @@ -797,7 +797,7 @@ def given(y): for long_var_name, number_two in () if long_var_name == 2 and number_two == 3 ] - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -808,43 +808,43 @@ def given(y): long_var_name for long_var_name, number_two in () if long_var_name == 2 and number_two == 3] - """) + """) expected_formatted_code = textwrap.dedent("""\ def given(y): long_variable_name = [ long_var_name for long_var_name, number_two in () if long_var_name == 2 and number_two == 3 ] - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testOpeningAndClosingBrackets(self): - unformatted_code = """\ -foo( (1, ) ) -foo( ( 1, 2, 3 ) ) -foo( ( 1, 2, 3, ) ) -""" - expected_formatted_code = """\ -foo((1,)) -foo((1, 2, 3)) -foo(( - 1, - 2, - 3, -)) -""" + unformatted_code = textwrap.dedent("""\ + foo( (1, ) ) + foo( ( 1, 2, 3 ) ) + foo( ( 1, 2, 3, ) ) + """) + expected_formatted_code = textwrap.dedent("""\ + foo((1,)) + foo((1, 2, 3)) + foo(( + 1, + 2, + 3, + )) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSingleLineFunctions(self): unformatted_code = textwrap.dedent("""\ def foo(): return 42 - """) + """) expected_formatted_code = textwrap.dedent("""\ def foo(): return 42 - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -852,23 +852,23 @@ def testNoQueueSeletionInMiddleOfLine(self): # If the queue isn't properly constructed, then a token in the middle of the # line may be selected as the one with least penalty. The tokens after that # one are then splatted at the end of the line with no formatting. - unformatted_code = """\ -find_symbol(node.type) + "< " + " ".join(find_pattern(n) for n in node.child) + " >" -""" # noqa - expected_formatted_code = """\ -find_symbol(node.type) + "< " + " ".join( - find_pattern(n) for n in node.child) + " >" -""" + unformatted_code = textwrap.dedent("""\ + find_symbol(node.type) + "< " + " ".join(find_pattern(n) for n in node.child) + " >" + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + find_symbol(node.type) + "< " + " ".join( + find_pattern(n) for n in node.child) + " >" + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoSpacesBetweenSubscriptsAndCalls(self): unformatted_code = textwrap.dedent("""\ aaaaaaaaaa = bbbbbbbb.ccccccccc() [42] (a, 2) - """) + """) expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaa = bbbbbbbb.ccccccccc()[42](a, 2) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -876,10 +876,10 @@ def testNoSpacesBetweenOpeningBracketAndStartingOperator(self): # Unary operator. unformatted_code = textwrap.dedent("""\ aaaaaaaaaa = bbbbbbbb.ccccccccc[ -1 ]( -42 ) - """) + """) expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaa = bbbbbbbb.ccccccccc[-1](-42) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -887,11 +887,11 @@ def testNoSpacesBetweenOpeningBracketAndStartingOperator(self): unformatted_code = textwrap.dedent("""\ aaaaaaaaaa = bbbbbbbb.ccccccccc( *varargs ) aaaaaaaaaa = bbbbbbbb.ccccccccc( **kwargs ) - """) + """) expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaa = bbbbbbbb.ccccccccc(*varargs) aaaaaaaaaa = bbbbbbbb.ccccccccc(**kwargs) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -901,13 +901,13 @@ def testMultilineCommentReformatted(self): # This is a multiline # comment. pass - """) + """) expected_formatted_code = textwrap.dedent("""\ if True: # This is a multiline # comment. pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -919,7 +919,7 @@ def testDictionaryMakerFormatting(self): 'yield_stmt': 'import_stmt', lambda: 'global_stmt': 'exec_stmt', 'assert_stmt': 'if_stmt', 'while_stmt': 'for_stmt', }) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ _PYTHON_STATEMENTS = frozenset({ lambda x, y: 'simple_stmt': 'small_stmt', @@ -932,7 +932,7 @@ def testDictionaryMakerFormatting(self): 'assert_stmt': 'if_stmt', 'while_stmt': 'for_stmt', }) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -950,7 +950,7 @@ def testSimpleMultilineCode(self): vvvvvvvvv) aaaaaaaaaaaaaa.bbbbbbbbbbbbbb.ccccccc(zzzzzzzzzzzz, xxxxxxxxxxx, yyyyyyyyyyyy, vvvvvvvvv) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -963,14 +963,14 @@ def testMultilineComment(self): # Yo man. # Yo man. a = 42 - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testSpaceBetweenStringAndParentheses(self): code = textwrap.dedent("""\ b = '0' ('hello') - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -985,7 +985,7 @@ def testMultilineString(self): # Yo man. a = 42 ''') - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -997,7 +997,7 @@ def f(): Residence: """+palace["Winter"]+"""
""" - ''') # noqa + ''') # noqa expected_formatted_code = textwrap.dedent('''\ def f(): email_text += """This is a really long docstring that goes over the column limit and is multi-line.

@@ -1006,7 +1006,7 @@ def f(): Residence: """ + palace["Winter"] + """
""" - ''') # noqa + ''') # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1018,7 +1018,7 @@ def testSimpleMultilineWithComments(self): b): # A trailing comment # Whoa! A normal comment!! pass # Another trailing comment - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1027,12 +1027,12 @@ def testMatchingParenSplittingMatching(self): def f(): raise RuntimeError('unable to find insertion point for target node', (target,)) - """) + """) expected_formatted_code = textwrap.dedent("""\ def f(): raise RuntimeError('unable to find insertion point for target node', (target,)) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1046,7 +1046,7 @@ def _ProcessArgLists(self, node): self._SetTokenSubtype( child, subtype=_ARGLIST_TOKEN_TO_SUBTYPE.get( child.value, format_token.Subtype.NONE)) - ''') + ''') expected_formatted_code = textwrap.dedent('''\ class F: @@ -1058,17 +1058,17 @@ def _ProcessArgLists(self, node): child, subtype=_ARGLIST_TOKEN_TO_SUBTYPE.get(child.value, format_token.Subtype.NONE)) - ''') # noqa + ''') # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testTrailingCommaAndBracket(self): - unformatted_code = textwrap.dedent('''\ + unformatted_code = textwrap.dedent("""\ a = { 42, } b = ( 42, ) c = [ 42, ] - ''') - expected_formatted_code = textwrap.dedent('''\ + """) + expected_formatted_code = textwrap.dedent("""\ a = { 42, } @@ -1076,20 +1076,20 @@ def testTrailingCommaAndBracket(self): c = [ 42, ] - ''') + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testI18n(self): code = textwrap.dedent("""\ N_('Some years ago - never mind how long precisely - having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world.') # A comment is here. - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) code = textwrap.dedent("""\ foo('Fake function call') #. Some years ago - never mind how long precisely - having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1103,12 +1103,12 @@ def f(): #. Second i18n comment. 'snork': 'bar#.*=\\\\0', }) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testClosingBracketIndent(self): - code = textwrap.dedent('''\ + code = textwrap.dedent("""\ def f(): def g(): @@ -1116,7 +1116,7 @@ def g(): xxxxxxxxxxxxxxxxxxxxx( yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): pass - ''') # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1134,7 +1134,7 @@ def bar(self): "horkhorkhork": 4, "porkporkpork": 5, }) - """) + """) expected_formatted_code = textwrap.dedent("""\ class Foo(object): @@ -1148,7 +1148,7 @@ def bar(self): "horkhorkhork": 4, "porkporkpork": 5, }) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1161,21 +1161,21 @@ def x(self, node, name, n=1): itertools.ifilter(lambda c: pytree_utils.NodeName(c) == name, node.pre_order())): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionCallContinuationLine(self): - code = """\ -class foo: - - def bar(self, node, name, n=1): - if True: - if True: - return [(aaaaaaaaaa, - bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb( - cccc, ddddddddddddddddddddddddddddddddddddd))] -""" + code = textwrap.dedent("""\ + class foo: + + def bar(self, node, name, n=1): + if True: + if True: + return [(aaaaaaaaaa, + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb( + cccc, ddddddddddddddddddddddddddddddddddddd))] + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1187,7 +1187,7 @@ def __init__(self, fieldname, #. Error message indicating an invalid e-mail address. message=N_('Please check your email address.'), **kwargs): pass - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1195,7 +1195,7 @@ def testNoSpaceBetweenUnaryOpAndOpeningParen(self): code = textwrap.dedent("""\ if ~(a or b): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1213,7 +1213,7 @@ def __init__(self, aaaaaaaaaaaaaaaaaa=False, bbbbbbbbbbbbbbb=False): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1225,7 +1225,7 @@ def Moo(self): ccccccccccccc=ccccccccccccc, ddddddd=ddddddd, eeee=eeee, fffff=fffff, ggggggg=ggggggg, hhhhhhhhhhhhh=hhhhhhhhhhhhh, iiiiiii=iiiiiiiiiiiiii) - """) + """) expected_formatted_code = textwrap.dedent("""\ class Fnord(object): @@ -1238,7 +1238,7 @@ def Moo(self): ggggggg=ggggggg, hhhhhhhhhhhhh=hhhhhhhhhhhhh, iiiiiii=iiiiiiiiiiiiii) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1246,7 +1246,7 @@ def testSpaceAfterNotOperator(self): code = textwrap.dedent("""\ if not (this and that): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1259,18 +1259,18 @@ def f(): os.path.join(filename, f) for f in os.listdir(filename) if IsPythonFile(os.path.join(filename, f))) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testExpressionPenalties(self): code = textwrap.dedent("""\ - def f(): - if ((left.value == '(' and right.value == ')') or - (left.value == '[' and right.value == ']') or - (left.value == '{' and right.value == '}')): - return False - """) + def f(): + if ((left.value == '(' and right.value == ')') or + (left.value == '[' and right.value == ']') or + (left.value == '{' and right.value == '}')): + return False + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1281,7 +1281,7 @@ def testLineDepthOfSingleLineStatement(self): try: a = 42 except: b = 42 with open(a) as fd: a = fd.read() - """) + """) expected_formatted_code = textwrap.dedent("""\ while True: continue @@ -1293,7 +1293,7 @@ def testLineDepthOfSingleLineStatement(self): b = 42 with open(a) as fd: a = fd.read() - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1301,7 +1301,7 @@ def testSplitListWithTerminatingComma(self): unformatted_code = textwrap.dedent("""\ FOO = ['bar', 'baz', 'mux', 'qux', 'quux', 'quuux', 'quuuux', 'quuuuux', 'quuuuuux', 'quuuuuuux', lambda a, b: 37,] - """) + """) expected_formatted_code = textwrap.dedent("""\ FOO = [ 'bar', @@ -1316,7 +1316,7 @@ def testSplitListWithTerminatingComma(self): 'quuuuuuux', lambda a, b: 37, ] - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1335,14 +1335,14 @@ def testSplitListWithInterspersedComments(self): 'quuuuuuux', # quuuuuuux lambda a, b: 37 # lambda ] - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testRelativeImportStatements(self): code = textwrap.dedent("""\ from ... import bork - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1353,11 +1353,11 @@ def testSingleLineList(self): ("...", "."), "..", ".............................................." ) - """) + """) expected_formatted_code = textwrap.dedent("""\ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = aaaaaaaaaaa( ("...", "."), "..", "..............................................") - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1376,7 +1376,7 @@ def timeout(seconds=1): pass except: pass - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ import signal @@ -1391,7 +1391,7 @@ def timeout(seconds=1): pass except: pass - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1403,17 +1403,17 @@ def b(self): if self.aaaaaaaaaaaaaaaaaaaa not in self.bbbbbbbbbb( cccccccccccccccccccc=True): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testTrailerOnSingleLine(self): - code = """\ -urlpatterns = patterns('', url(r'^$', 'homepage_view'), - url(r'^/login/$', 'login_view'), - url(r'^/login/$', 'logout_view'), - url(r'^/user/(?P\\w+)/$', 'profile_view')) -""" + code = textwrap.dedent("""\ + urlpatterns = patterns('', url(r'^$', 'homepage_view'), + url(r'^/login/$', 'login_view'), + url(r'^/login/$', 'logout_view'), + url(r'^/user/(?P\\w+)/$', 'profile_view')) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1426,7 +1426,7 @@ def bar(): if (child.type == grammar_token.NAME and child.value in substatement_names): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1437,14 +1437,14 @@ def testContinuationMarkers(self): "ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis "\\ "sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. "\\ "Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet" - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) code = textwrap.dedent("""\ from __future__ import nested_scopes, generators, division, absolute_import, with_statement, \\ print_function, unicode_literals - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1452,7 +1452,7 @@ def testContinuationMarkers(self): if aaaaaaaaa == 42 and bbbbbbbbbbbbbb == 42 and \\ cccccccc == 42: pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1463,7 +1463,7 @@ def fn(arg): #c1 key2=arg)\\ .fn3() - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1472,16 +1472,16 @@ def testMultipleContinuationMarkers(self): xyz = \\ \\ some_thing() - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testContinuationMarkerAfterStringWithContinuation(self): - code = """\ -s = 'foo \\ - bar' \\ - .format() -""" + code = textwrap.dedent("""\ + s = 'foo \\ + bar' \\ + .format() + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1491,14 +1491,14 @@ def testEmptyContainers(self): 'output_dirs', [], 'Lorem ipsum dolor sit amet, consetetur adipiscing elit. Donec a diam lectus. ' 'Sed sit amet ipsum mauris. Maecenas congue.') - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testSplitStringsIfSurroundedByParens(self): unformatted_code = textwrap.dedent("""\ a = foo.bar({'xxxxxxxxxxxxxxxxxxxxxxx' 'yyyyyyyyyyyyyyyyyyyyyyyyyy': baz[42]} + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbb' 'cccccccccccccccccccccccccccccccc' 'ddddddddddddddddddddddddddddd') - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ a = foo.bar({'xxxxxxxxxxxxxxxxxxxxxxx' 'yyyyyyyyyyyyyyyyyyyyyyyyyy': baz[42]} + @@ -1506,7 +1506,7 @@ def testSplitStringsIfSurroundedByParens(self): 'bbbbbbbbbbbbbbbbbbbbbbbbbb' 'cccccccccccccccccccccccccccccccc' 'ddddddddddddddddddddddddddddd') - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1514,7 +1514,7 @@ def testSplitStringsIfSurroundedByParens(self): a = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' \ 'bbbbbbbbbbbbbbbbbbbbbbbbbb' 'cccccccccccccccccccccccccccccccc' \ 'ddddddddddddddddddddddddddddd' - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1534,7 +1534,7 @@ def testMultilineShebang(self): import os assert os.environ['FOO'] == '123' - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1542,7 +1542,7 @@ def testNoSplittingAroundTermOperators(self): code = textwrap.dedent("""\ a_very_long_function_call_yada_yada_etc_etc_etc(long_arg1, long_arg2 / long_arg3) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1554,7 +1554,7 @@ def testNoSplittingAroundCompOperators(self): c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa is bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) c = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa <= bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) - """) # noqa + """) # noqa expected_code = textwrap.dedent("""\ c = ( aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -1572,7 +1572,7 @@ def testNoSplittingAroundCompOperators(self): c = ( aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa <= bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) @@ -1582,7 +1582,7 @@ def testNoSplittingWithinSubscriptList(self): 'somelongkey': 1, 'someotherlongkey': 2 } - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1594,7 +1594,7 @@ def bar(self): self.write(s=[ '%s%s %s' % ('many of really', 'long strings', '+ just makes up 81') ]) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1604,7 +1604,7 @@ def _(): if True: if contract == allow_contract and attr_dict.get(if_attribute) == has_value: return True - """) # noqa + """) # noqa expected_code = textwrap.dedent("""\ def _(): if True: @@ -1612,7 +1612,7 @@ def _(): if contract == allow_contract and attr_dict.get( if_attribute) == has_value: return True - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) @@ -1623,7 +1623,7 @@ def testDictSetGenerator(self): for variable in fnord if variable != 37 } - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1632,10 +1632,10 @@ def testDictSetGenerator(self): x: x for x in fnord } - """) # noqa + """) # noqa expected_code = textwrap.dedent("""\ foo = {x: x for x in fnord} - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) @@ -1646,7 +1646,7 @@ def testUnaryOpInDictionaryValue(self): test = {'alpha': beta[-1]} print(beta[-1]) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1658,33 +1658,37 @@ def testUnaryNotOperator(self): if True: remote_checksum = self.get_checksum(conn, tmp, dest, inject, not directory_prepended, source) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testRelaxArraySubscriptAffinity(self): - code = """\ -class A(object): + code = textwrap.dedent("""\ + class A(object): - def f(self, aaaaaaaaa, bbbbbbbbbbbbb, row): - if True: - if True: - if True: - if True: - if row[4] is None or row[5] is None: - bbbbbbbbbbbbb[ - '..............'] = row[5] if row[5] is not None else 5 -""" + def f(self, aaaaaaaaa, bbbbbbbbbbbbb, row): + if True: + if True: + if True: + if True: + if row[4] is None or row[5] is None: + bbbbbbbbbbbbb[ + '..............'] = row[5] if row[5] is not None else 5 + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionCallInDict(self): - code = "a = {'a': b(c=d, **e)}\n" + code = textwrap.dedent("""\ + a = {'a': b(c=d, **e)} + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionCallInNestedDict(self): - code = "a = {'a': {'a': {'a': b(c=d, **e)}}}\n" + code = textwrap.dedent("""\ + a = {'a': {'a': {'a': b(c=d, **e)}}} + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1693,100 +1697,100 @@ def testUnbreakableNot(self): def test(): if not "Foooooooooooooooooooooooooooooo" or "Foooooooooooooooooooooooooooooo" == "Foooooooooooooooooooooooooooooo": pass - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testSplitListWithComment(self): code = textwrap.dedent("""\ - a = [ - 'a', - 'b', - 'c' # hello world - ] - """) + a = [ + 'a', + 'b', + 'c' # hello world + ] + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testOverColumnLimit(self): unformatted_code = textwrap.dedent("""\ - class Test: + class Test: - def testSomething(self): - expected = { - ('aaaaaaaaaaaaa', 'bbbb'): 'ccccccccccccccccccccccccccccccccccccccccccc', - ('aaaaaaaaaaaaa', 'bbbb'): 'ccccccccccccccccccccccccccccccccccccccccccc', - ('aaaaaaaaaaaaa', 'bbbb'): 'ccccccccccccccccccccccccccccccccccccccccccc', - } - """) # noqa - expected_formatted_code = textwrap.dedent("""\ - class Test: - - def testSomething(self): - expected = { - ('aaaaaaaaaaaaa', 'bbbb'): - 'ccccccccccccccccccccccccccccccccccccccccccc', - ('aaaaaaaaaaaaa', 'bbbb'): - 'ccccccccccccccccccccccccccccccccccccccccccc', - ('aaaaaaaaaaaaa', 'bbbb'): - 'ccccccccccccccccccccccccccccccccccccccccccc', - } - """) + def testSomething(self): + expected = { + ('aaaaaaaaaaaaa', 'bbbb'): 'ccccccccccccccccccccccccccccccccccccccccccc', + ('aaaaaaaaaaaaa', 'bbbb'): 'ccccccccccccccccccccccccccccccccccccccccccc', + ('aaaaaaaaaaaaa', 'bbbb'): 'ccccccccccccccccccccccccccccccccccccccccccc', + } + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + class Test: + + def testSomething(self): + expected = { + ('aaaaaaaaaaaaa', 'bbbb'): + 'ccccccccccccccccccccccccccccccccccccccccccc', + ('aaaaaaaaaaaaa', 'bbbb'): + 'ccccccccccccccccccccccccccccccccccccccccccc', + ('aaaaaaaaaaaaa', 'bbbb'): + 'ccccccccccccccccccccccccccccccccccccccccccc', + } + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testEndingComment(self): code = textwrap.dedent("""\ - a = f( - a="something", - b="something requiring comment which is quite long", # comment about b (pushes line over 79) - c="something else, about which comment doesn't make sense") - """) # noqa + a = f( + a="something", + b="something requiring comment which is quite long", # comment about b (pushes line over 79) + c="something else, about which comment doesn't make sense") + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testContinuationSpaceRetention(self): code = textwrap.dedent("""\ - def fn(): - return module \\ - .method(Object(data, - fn2(arg) - )) - """) + def fn(): + return module \\ + .method(Object(data, + fn2(arg) + )) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testIfExpressionWithFunctionCall(self): code = textwrap.dedent("""\ - if x or z.y( - a, - c, - aaaaaaaaaaaaaaaaaaaaa=aaaaaaaaaaaaaaaaaa, - bbbbbbbbbbbbbbbbbbbbb=bbbbbbbbbbbbbbbbbb): - pass - """) + if x or z.y( + a, + c, + aaaaaaaaaaaaaaaaaaaaa=aaaaaaaaaaaaaaaaaa, + bbbbbbbbbbbbbbbbbbbbb=bbbbbbbbbbbbbbbbbb): + pass + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testUnformattedAfterMultilineString(self): code = textwrap.dedent("""\ - def foo(): - com_text = \\ - ''' - TEST - ''' % (input_fname, output_fname) - """) + def foo(): + com_text = \\ + ''' + TEST + ''' % (input_fname, output_fname) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSpacesAroundKeywordDefaultValues(self): code = textwrap.dedent("""\ - sources = { - 'json': request.get_json(silent=True) or {}, - 'json2': request.get_json(silent=True), - } - json = request.get_json(silent=True) or {} - """) + sources = { + 'json': request.get_json(silent=True) or {}, + 'json2': request.get_json(silent=True), + } + json = request.get_json(silent=True) or {} + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1795,13 +1799,13 @@ def testNoSplittingBeforeEndingSubscriptBracket(self): if True: if True: status = cf.describe_stacks(StackName=stackname)[u'Stacks'][0][u'StackStatus'] - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ if True: if True: status = cf.describe_stacks( StackName=stackname)[u'Stacks'][0][u'StackStatus'] - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1815,7 +1819,7 @@ def testNoSplittingOnSingleArgument(self): aaaaaaa.bbbbbbbbbbbb).group(a.b) + re.search(r'\\d+\\.\\d+\\.\\d+\\.(\\d+)', ccccccc).group(c.d)) - """) + """) expected_formatted_code = textwrap.dedent("""\ xxxxxxxxxxxxxx = ( re.search(r'(\\d+\\.\\d+\\.\\d+\\.)\\d+', aaaaaaa.bbbbbbbbbbbb).group(1) + @@ -1823,7 +1827,7 @@ def testNoSplittingOnSingleArgument(self): xxxxxxxxxxxxxx = ( re.search(r'(\\d+\\.\\d+\\.\\d+\\.)\\d+', aaaaaaa.bbbbbbbbbbbb).group(a.b) + re.search(r'\\d+\\.\\d+\\.\\d+\\.(\\d+)', ccccccc).group(c.d)) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1833,7 +1837,7 @@ def testSplittingArraysSensibly(self): while True: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list['bbbbbbbbbbbbbbbbbbbbbbbbb'].split(',') aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list('bbbbbbbbbbbbbbbbbbbbbbbbb').split(',') - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ while True: while True: @@ -1841,7 +1845,7 @@ def testSplittingArraysSensibly(self): 'bbbbbbbbbbbbbbbbbbbbbbbbb'].split(',') aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list( 'bbbbbbbbbbbbbbbbbbbbbbbbb').split(',') - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1851,14 +1855,14 @@ class f: def __repr__(self): tokens_repr = ','.join(['{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens]) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ class f: def __repr__(self): tokens_repr = ','.join( ['{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens]) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1872,7 +1876,7 @@ def f(): pytree_utils.InsertNodesBefore(_CreateCommentsFromPrefix( comment_prefix, comment_lineno, comment_column, standalone=True)) - """) + """) expected_formatted_code = textwrap.dedent("""\ def f(): if True: @@ -1883,7 +1887,7 @@ def f(): pytree_utils.InsertNodesBefore( _CreateCommentsFromPrefix( comment_prefix, comment_lineno, comment_column, standalone=True)) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1891,66 +1895,66 @@ def testBinaryOperators(self): unformatted_code = textwrap.dedent("""\ a = b ** 37 c = (20 ** -3) / (_GRID_ROWS ** (code_length - 10)) - """) + """) expected_formatted_code = textwrap.dedent("""\ a = b**37 c = (20**-3) / (_GRID_ROWS**(code_length - 10)) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) code = textwrap.dedent("""\ - def f(): - if True: - if (self.stack[-1].split_before_closing_bracket and - # FIXME(morbo): Use the 'matching_bracket' instead of this. - # FIXME(morbo): Don't forget about tuples! - current.value in ']}'): - pass - """) + def f(): + if True: + if (self.stack[-1].split_before_closing_bracket and + # FIXME(morbo): Use the 'matching_bracket' instead of this. + # FIXME(morbo): Don't forget about tuples! + current.value in ']}'): + pass + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testContiguousList(self): code = textwrap.dedent("""\ - [retval1, retval2] = a_very_long_function(argument_1, argument2, argument_3, - argument_4) - """) # noqa + [retval1, retval2] = a_very_long_function(argument_1, argument2, argument_3, + argument_4) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testArgsAndKwargsFormatting(self): code = textwrap.dedent("""\ - a(a=aaaaaaaaaaaaaaaaaaaaa, - b=aaaaaaaaaaaaaaaaaaaaaaaa, - c=aaaaaaaaaaaaaaaaaa, - *d, - **e) - """) + a(a=aaaaaaaaaaaaaaaaaaaaa, + b=aaaaaaaaaaaaaaaaaaaaaaaa, + c=aaaaaaaaaaaaaaaaaa, + *d, + **e) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) code = textwrap.dedent("""\ - def foo(): - return [ - Bar(xxx='some string', - yyy='another long string', - zzz='a third long string') - ] - """) + def foo(): + return [ + Bar(xxx='some string', + yyy='another long string', + zzz='a third long string') + ] + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentColumnLimitOverflow(self): code = textwrap.dedent("""\ - def f(): - if True: - TaskManager.get_tags = MagicMock( - name='get_tags_mock', - return_value=[157031694470475], - # side_effect=[(157031694470475), (157031694470475),], - ) - """) + def f(): + if True: + TaskManager.get_tags = MagicMock( + name='get_tags_mock', + return_value=[157031694470475], + # side_effect=[(157031694470475), (157031694470475),], + ) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1965,7 +1969,7 @@ def succeeded(self, dddddddddddddd): if self.do_something: d.addCallback(lambda _: self.aaaaaa.bbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccccccc(dddddddddddddd)) return d - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ class SomeClass(object): do_something = True @@ -1977,7 +1981,7 @@ def succeeded(self, dddddddddddddd): d.addCallback(lambda _: self.aaaaaa.bbbbbbbbbbbbbbbb. cccccccccccccccccccccccccccccccc(dddddddddddddd)) return d - """) + """) try: style.SetGlobalStyle( @@ -1999,7 +2003,7 @@ def testMultilineDictionaryKeys(self): ('vehicula convallis nulla. Vestibulum dictum nisl in malesuada finibus.',): 3 } - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ MAP_WITH_LONG_KEYS = { ('lorem ipsum', 'dolor sit amet'): @@ -2010,7 +2014,7 @@ def testMultilineDictionaryKeys(self): ('vehicula convallis nulla. Vestibulum dictum nisl in malesuada finibus.',): 3 } - """) # noqa + """) # noqa try: style.SetGlobalStyle( @@ -2036,7 +2040,7 @@ def method(self): } }] } - """) # noqa + """) # noqa try: style.SetGlobalStyle( @@ -2061,7 +2065,7 @@ def testStableInlinedDictionaryFormatting(self): def _(): url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( value, urllib.urlencode({'action': 'update', 'parameter': value})) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def _(): url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( @@ -2069,7 +2073,7 @@ def _(): 'action': 'update', 'parameter': value })) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) reformatted_code = reformatter.Reformat(llines) @@ -2086,36 +2090,36 @@ def testDontSplitKeywordValueArguments(self): def mark_game_scored(gid): _connect.execute(_games.update().where(_games.c.gid == gid).values( scored=True)) - """) + """) expected_formatted_code = textwrap.dedent("""\ def mark_game_scored(gid): _connect.execute( _games.update().where(_games.c.gid == gid).values(scored=True)) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDontAddBlankLineAfterMultilineString(self): code = textwrap.dedent("""\ - query = '''SELECT id - FROM table - WHERE day in {}''' - days = ",".join(days) - """) + query = '''SELECT id + FROM table + WHERE day in {}''' + days = ",".join(days) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFormattingListComprehensions(self): code = textwrap.dedent("""\ - def a(): - if True: + def a(): if True: if True: - columns = [ - x for x, y in self._heap_this_is_very_long if x.route[0] == choice - ] - self._heap = [x for x in self._heap if x.route and x.route[0] == choice] - """) # noqa + if True: + columns = [ + x for x, y in self._heap_this_is_very_long if x.route[0] == choice + ] + self._heap = [x for x in self._heap if x.route and x.route[0] == choice] + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -2132,7 +2136,7 @@ def testNoSplittingWhenBinPacking(self): long_argument_name_1=1, long_argument_name_2=2, long_argument_name_3=3, long_argument_name_4=4 ) - """) # noqa + """) # noqa try: style.SetGlobalStyle( @@ -2157,12 +2161,12 @@ def testNotSplittingAfterSubscript(self): if not aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.b(c == d[ 'eeeeee']).ffffff(): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ if not aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.b( c == d['eeeeee']).ffffff(): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -2175,7 +2179,7 @@ def _(): if True: if True: boxes[id_] = np.concatenate((points.min(axis=0), qoints.max(axis=0))) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def _(): if True: @@ -2185,7 +2189,7 @@ def _(): if True: boxes[id_] = np.concatenate( (points.min(axis=0), qoints.max(axis=0))) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -2202,7 +2206,7 @@ def _pack_results_for_constraint_or(cls, combination, constraints): clue for clue in combination if not clue == Verifier.UNMATCHED ), constraints, InvestigationResult.OR ) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ class _(): @@ -2214,7 +2218,7 @@ def _pack_results_for_constraint_or(cls, combination, constraints): return cls._create_investigation_result( (clue for clue in combination if not clue == Verifier.UNMATCHED), constraints, InvestigationResult.OR) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -2229,7 +2233,7 @@ def testSplittingArgumentsTerminatedByComma(self): a_very_long_function_name(long_argument_name_1, long_argument_name_2, long_argument_name_3, long_argument_name_4,) r =f0 (1, 2,3,) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3) @@ -2257,7 +2261,7 @@ def testSplittingArgumentsTerminatedByComma(self): 2, 3, ) - """) + """) try: style.SetGlobalStyle( @@ -2280,7 +2284,7 @@ def testImportAsList(self): from toto import titi, tata, tutu # noqa from toto import titi, tata, tutu from toto import (titi, tata, tutu) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -2308,7 +2312,7 @@ def testDictionaryValuesOnOwnLines(self): 'jjjjjjjjjjjjjjjjjjjjjjjjjj': Check('QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ', '=', False), } - """) + """) expected_formatted_code = textwrap.dedent("""\ a = { 'aaaaaaaaaaaaaaaaaaaaaaaa': @@ -2332,7 +2336,7 @@ def testDictionaryValuesOnOwnLines(self): 'jjjjjjjjjjjjjjjjjjjjjjjjjj': Check('QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ', '=', False), } - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -2342,11 +2346,11 @@ def testDictionaryOnOwnLine(self): content={ 'a': 'b' }, branch_key=branch.key, collection_key=collection.key) - """) + """) expected_formatted_code = textwrap.dedent("""\ doc = test_utils.CreateTestDocumentViaController( content={'a': 'b'}, branch_key=branch.key, collection_key=collection.key) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -2356,14 +2360,14 @@ def testDictionaryOnOwnLine(self): branch_key=branch.key, collection_key=collection.key, collection_key2=collection.key2) - """) + """) expected_formatted_code = textwrap.dedent("""\ doc = test_utils.CreateTestDocumentViaController( content={'a': 'b'}, branch_key=branch.key, collection_key=collection.key, collection_key2=collection.key2) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -2396,7 +2400,7 @@ def testNestedListsInDictionary(self): 'cccccccccc': ('^21109', # PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP. ), } - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ _A = { 'cccccccccc': ('^^1',), @@ -2430,7 +2434,7 @@ def testNestedListsInDictionary(self): '^21109', # PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP. ), } - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -2444,7 +2448,7 @@ def _(): breadcrumbs = [{'name': 'Admin', 'url': url_for(".home")}, {'title': title}] - """) + """) expected_formatted_code = textwrap.dedent("""\ class _(): def _(): @@ -2458,7 +2462,7 @@ def _(): }, ] breadcrumbs = [{'name': 'Admin', 'url': url_for(".home")}, {'title': title}] - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -2478,18 +2482,18 @@ def _(): Environment.YYYYYYY: 'some text more text even more text yet ag', Environment.ZZZZZZZZZZZ: 'some text more text even more text yet again tex', } - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNotInParams(self): unformatted_code = textwrap.dedent("""\ list("a long line to break the line. a long line to break the brk a long lin", not True) - """) # noqa + """) # noqa expected_code = textwrap.dedent("""\ list("a long line to break the line. a long line to break the brk a long lin", not True) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) @@ -2500,14 +2504,14 @@ def _(): with py3compat.open_with_encoding(filename, mode='w', encoding=encoding) as fd: pass - """) + """) expected_code = textwrap.dedent("""\ def _(): if True: with py3compat.open_with_encoding( filename, mode='w', encoding=encoding) as fd: pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) @@ -2522,7 +2526,7 @@ class A: def __init__(self): pass - ''') + ''') expected_code = textwrap.dedent('''\ class A: """Does something. @@ -2532,7 +2536,7 @@ class A: def __init__(self): pass - ''') + ''') llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) @@ -2546,7 +2550,7 @@ class A: def __init__(self): pass - ''') + ''') expected_formatted_code = textwrap.dedent('''\ class A: @@ -2557,7 +2561,7 @@ class A: def __init__(self): pass - ''') + ''') try: style.SetGlobalStyle( @@ -2581,7 +2585,7 @@ def testBlankLineBeforeModuleDocstring(self): def foobar(): pass - ''') + ''') expected_code = textwrap.dedent('''\ #!/usr/bin/env python # -*- coding: utf-8 name> -*- @@ -2590,7 +2594,7 @@ def foobar(): def foobar(): pass - ''') + ''') llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) @@ -2602,7 +2606,7 @@ def foobar(): def foobar(): pass - ''') + ''') expected_formatted_code = textwrap.dedent('''\ #!/usr/bin/env python # -*- coding: utf-8 name> -*- @@ -2612,7 +2616,7 @@ def foobar(): def foobar(): pass - ''') + ''') try: style.SetGlobalStyle( @@ -2631,27 +2635,27 @@ def testTupleCohesion(self): def f(): this_is_a_very_long_function_name(an_extremely_long_variable_name, ( 'a string that may be too long %s' % 'M15')) - """) + """) expected_code = textwrap.dedent("""\ def f(): this_is_a_very_long_function_name( an_extremely_long_variable_name, ('a string that may be too long %s' % 'M15')) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testSubscriptExpression(self): code = textwrap.dedent("""\ foo = d[not a] - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testSubscriptExpressionTerminatedByComma(self): unformatted_code = textwrap.dedent("""\ A[B, C,] - """) + """) expected_code = textwrap.dedent("""\ A[ B, @@ -2673,7 +2677,7 @@ def foo(): yyy='another long string', zzz='a third long string') ] - """) + """) expected_code = textwrap.dedent("""\ def foo(): return [ @@ -2684,7 +2688,7 @@ def foo(): yyy='another long string', zzz='a third long string') ] - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) @@ -2692,29 +2696,29 @@ def testEllipses(self): unformatted_code = textwrap.dedent("""\ X=... Y = X if ... else X - """) + """) expected_code = textwrap.dedent("""\ X = ... Y = X if ... else X - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) def testPseudoParens(self): - unformatted_code = """\ -my_dict = { - 'key': # Some comment about the key - {'nested_key': 1, }, -} -""" - expected_code = """\ -my_dict = { - 'key': # Some comment about the key - { - 'nested_key': 1, - }, -} -""" + unformatted_code = textwrap.dedent("""\ + my_dict = { + 'key': # Some comment about the key + {'nested_key': 1, }, + } + """) + expected_code = textwrap.dedent("""\ + my_dict = { + 'key': # Some comment about the key + { + 'nested_key': 1, + }, + } + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) @@ -2723,11 +2727,11 @@ def testSplittingBeforeFirstArgumentOnFunctionCall(self): unformatted_code = textwrap.dedent("""\ a_very_long_function_name("long string with formatting {0:s}".format( "mystring")) - """) + """) expected_formatted_code = textwrap.dedent("""\ a_very_long_function_name( "long string with formatting {0:s}".format("mystring")) - """) + """) try: style.SetGlobalStyle( @@ -2746,12 +2750,12 @@ def testSplittingBeforeFirstArgumentOnFunctionDefinition(self): def _GetNumberOfSecondsFromElements(year, month, day, hours, minutes, seconds, microseconds): return - """) + """) expected_formatted_code = textwrap.dedent("""\ def _GetNumberOfSecondsFromElements( year, month, day, hours, minutes, seconds, microseconds): return - """) + """) try: style.SetGlobalStyle( @@ -2772,12 +2776,12 @@ def testSplittingBeforeFirstArgumentOnCompoundStatement(self): long_argument_name_3 == 3 or long_argument_name_4 == 4): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ if (long_argument_name_1 == 1 or long_argument_name_2 == 2 or long_argument_name_3 == 3 or long_argument_name_4 == 4): pass - """) + """) try: style.SetGlobalStyle( @@ -2803,7 +2807,7 @@ def testCoalesceBracketsOnDict(self): u'seconds': seconds } ) - """) + """) expected_formatted_code = textwrap.dedent("""\ date_time_values = ({ u'year': year, @@ -2813,7 +2817,7 @@ def testCoalesceBracketsOnDict(self): u'minutes': minutes, u'seconds': seconds }) - """) + """) try: style.SetGlobalStyle( @@ -2834,7 +2838,7 @@ def testSplitAfterComment(self): "validUntil": int(time() + (6 * 7 * 24 * 60 * 60)) # in 6 weeks time } - """) + """) try: style.SetGlobalStyle( @@ -2849,7 +2853,7 @@ def testSplitAfterComment(self): def testDisableEndingCommaHeuristic(self): code = textwrap.dedent("""\ x = [1, 2, 3, 4, 5, 6, 7,] - """) + """) try: style.SetGlobalStyle( @@ -2869,7 +2873,7 @@ def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: pass - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def function( first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None @@ -2881,7 +2885,7 @@ def function( first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None ) -> None: pass - """) # noqa + """) # noqa try: style.SetGlobalStyle( @@ -2902,7 +2906,7 @@ def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None) -> None: pass - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def function( first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None @@ -2914,7 +2918,7 @@ def function( first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_argument=None ) -> None: pass - """) # noqa + """) # noqa try: style.SetGlobalStyle( @@ -2935,7 +2939,7 @@ def function(first_argument_xxxxxxxxxxxxxxxx=(0,), second_argument=None, third_a def function(first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_and_last_argument=None): pass - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def function( first_argument_xxxxxxxxxxxxxxxx=(0,), @@ -2949,7 +2953,7 @@ def function( first_argument_xxxxxxxxxxxxxxxxxxxxxxx=(0,), second_and_last_argument=None ): pass - """) # noqa + """) # noqa try: style.SetGlobalStyle( @@ -2971,7 +2975,7 @@ def function(): def function(): some_var = ('a couple', 'small', 'elemens') return False - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def function(): some_var = ( @@ -2984,7 +2988,7 @@ def function(): def function(): some_var = ('a couple', 'small', 'elemens') return False - """) # noqa + """) # noqa try: style.SetGlobalStyle( @@ -3006,7 +3010,7 @@ def function(): def function(): some_var = ['a couple', 'small', 'elemens'] return False - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def function(): some_var = [ @@ -3019,7 +3023,7 @@ def function(): def function(): some_var = ['a couple', 'small', 'elemens'] return False - """) + """) try: style.SetGlobalStyle( @@ -3041,7 +3045,7 @@ def function(): def function(): some_var = {1: 'a couple', 2: 'small', 3: 'elemens'} return False - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def function(): some_var = { @@ -3060,7 +3064,7 @@ def function(): def function(): some_var = {1: 'a couple', 2: 'small', 3: 'elemens'} return False - """) # noqa + """) # noqa try: style.SetGlobalStyle( @@ -3099,7 +3103,7 @@ def b(): } ] } - """) + """) expected_formatted_code = textwrap.dedent("""\ class A: @@ -3122,7 +3126,7 @@ def b(): } }] } - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -3131,20 +3135,20 @@ def testForceMultilineDict_True(self): style.SetGlobalStyle( style.CreateStyleFromConfig('{force_multiline_dict: true}')) unformatted_code = textwrap.dedent("""\ - responseDict = {'childDict': {'spam': 'eggs'}} - generatedDict = {x: x for x in 'value'} + responseDict = {'childDict': {'spam': 'eggs'}} + generatedDict = {x: x for x in 'value'} """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) actual = reformatter.Reformat(llines) expected = textwrap.dedent("""\ - responseDict = { - 'childDict': { - 'spam': 'eggs' - } - } - generatedDict = { - x: x for x in 'value' - } + responseDict = { + 'childDict': { + 'spam': 'eggs' + } + } + generatedDict = { + x: x for x in 'value' + } """) self.assertCodeEqual(expected, actual) finally: @@ -3155,8 +3159,8 @@ def testForceMultilineDict_False(self): style.SetGlobalStyle( style.CreateStyleFromConfig('{force_multiline_dict: false}')) unformatted_code = textwrap.dedent("""\ - responseDict = {'childDict': {'spam': 'eggs'}} - generatedDict = {x: x for x in 'value'} + responseDict = {'childDict': {'spam': 'eggs'}} + generatedDict = {x: x for x in 'value'} """) expected_formatted_code = unformatted_code llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) @@ -3168,12 +3172,12 @@ def testForceMultilineDict_False(self): @unittest.skipUnless(PY38, 'Requires Python 3.8') def testWalrus(self): unformatted_code = textwrap.dedent("""\ - if (x := len([1]*1000)>100): - print(f'{x} is pretty big' ) + if (x := len([1]*1000)>100): + print(f'{x} is pretty big' ) """) expected = textwrap.dedent("""\ - if (x := len([1] * 1000) > 100): - print(f'{x} is pretty big') + if (x := len([1] * 1000) > 100): + print(f'{x} is pretty big') """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected, reformatter.Reformat(llines)) @@ -3186,14 +3190,14 @@ def testStructuredPatternMatching(self): ... # interpret single-verb action case[action, obj]: ... # interpret action, obj - """) + """) expected = textwrap.dedent("""\ match command.split(): case [action]: ... # interpret single-verb action case [action, obj]: ... # interpret action, obj - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected, reformatter.Reformat(llines)) @@ -3202,7 +3206,7 @@ def testParenthesizedContextManagers(self): unformatted_code = textwrap.dedent("""\ with (cert_authority.cert_pem.tempfile() as ca_temp_path, patch.object(os, 'environ', os.environ | {'REQUESTS_CA_BUNDLE': ca_temp_path}),): httpserver_url = httpserver.url_for('/resource.jar') - """) # noqa: E501 + """) # noqa: E501 expected = textwrap.dedent("""\ with ( cert_authority.cert_pem.tempfile() as ca_temp_path, @@ -3210,7 +3214,7 @@ def testParenthesizedContextManagers(self): os.environ | {'REQUESTS_CA_BUNDLE': ca_temp_path}), ): httpserver_url = httpserver.url_for('/resource.jar') - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected, reformatter.Reformat(llines)) diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 254000840..1efa81b75 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -29,827 +29,827 @@ def setUpClass(cls): style.SetGlobalStyle(style.CreateYapfStyle()) def testB137580392(self): - code = """\ -def _create_testing_simulator_and_sink( -) -> Tuple[_batch_simulator:_batch_simulator.BatchSimulator, - _batch_simulator.SimulationSink]: - pass -""" + code = textwrap.dedent("""\ + def _create_testing_simulator_and_sink( + ) -> Tuple[_batch_simulator:_batch_simulator.BatchSimulator, + _batch_simulator.SimulationSink]: + pass + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB73279849(self): - unformatted_code = """\ -class A: - def _(a): - return 'hello' [ a ] -""" - expected_formatted_code = """\ -class A: - def _(a): - return 'hello'[a] -""" + unformatted_code = textwrap.dedent("""\ + class A: + def _(a): + return 'hello' [ a ] + """) + expected_formatted_code = textwrap.dedent("""\ + class A: + def _(a): + return 'hello'[a] + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB122455211(self): - unformatted_code = """\ -_zzzzzzzzzzzzzzzzzzzz = Union[sssssssssssssssssssss.pppppppppppppppp, - sssssssssssssssssssss.pppppppppppppppppppppppppppp] -""" - expected_formatted_code = """\ -_zzzzzzzzzzzzzzzzzzzz = Union[ - sssssssssssssssssssss.pppppppppppppppp, - sssssssssssssssssssss.pppppppppppppppppppppppppppp] -""" + unformatted_code = textwrap.dedent("""\ + _zzzzzzzzzzzzzzzzzzzz = Union[sssssssssssssssssssss.pppppppppppppppp, + sssssssssssssssssssss.pppppppppppppppppppppppppppp] + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + _zzzzzzzzzzzzzzzzzzzz = Union[ + sssssssssssssssssssss.pppppppppppppppp, + sssssssssssssssssssss.pppppppppppppppppppppppppppp] + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB119300344(self): - code = """\ -def _GenerateStatsEntries( - process_id: Text, - timestamp: Optional[rdfvalue.RDFDatetime] = None -) -> Sequence[stats_values.StatsStoreEntry]: - pass -""" + code = textwrap.dedent("""\ + def _GenerateStatsEntries( + process_id: Text, + timestamp: Optional[rdfvalue.RDFDatetime] = None + ) -> Sequence[stats_values.StatsStoreEntry]: + pass + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB132886019(self): - code = """\ -X = { - 'some_dict_key': - frozenset([ - # pylint: disable=line-too-long - '//this/path/is/really/too/long/for/this/line/and/probably/should/be/split', - ]), -} -""" + code = textwrap.dedent("""\ + X = { + 'some_dict_key': + frozenset([ + # pylint: disable=line-too-long + '//this/path/is/really/too/long/for/this/line/and/probably/should/be/split', + ]), + } + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB26521719(self): - code = """\ -class _(): + code = textwrap.dedent("""\ + class _(): - def _(self): - self.stubs.Set(some_type_of_arg, 'ThisIsAStringArgument', - lambda *unused_args, **unused_kwargs: fake_resolver) -""" + def _(self): + self.stubs.Set(some_type_of_arg, 'ThisIsAStringArgument', + lambda *unused_args, **unused_kwargs: fake_resolver) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB122541552(self): - code = """\ -# pylint: disable=g-explicit-bool-comparison,singleton-comparison -_QUERY = account.Account.query(account.Account.enabled == True) -# pylint: enable=g-explicit-bool-comparison,singleton-comparison + code = textwrap.dedent("""\ + # pylint: disable=g-explicit-bool-comparison,singleton-comparison + _QUERY = account.Account.query(account.Account.enabled == True) + # pylint: enable=g-explicit-bool-comparison,singleton-comparison -def _(): - pass -""" + def _(): + pass + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB124415889(self): - code = """\ -class _(): + code = textwrap.dedent("""\ + class _(): - def run_queue_scanners(): - return xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( - { - components.NAME.FNOR: True, - components.NAME.DEVO: True, - }, - default=False) - - def modules_to_install(): - modules = DeepCopy(GetDef({})) - modules.update({ - 'xxxxxxxxxxxxxxxxxxxx': - GetDef('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz', None), - }) - return modules -""" + def run_queue_scanners(): + return xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( + { + components.NAME.FNOR: True, + components.NAME.DEVO: True, + }, + default=False) + + def modules_to_install(): + modules = DeepCopy(GetDef({})) + modules.update({ + 'xxxxxxxxxxxxxxxxxxxx': + GetDef('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz', None), + }) + return modules + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB73166511(self): - code = """\ -def _(): - if min_std is not None: - groundtruth_age_variances = tf.maximum(groundtruth_age_variances, - min_std**2) -""" + code = textwrap.dedent("""\ + def _(): + if min_std is not None: + groundtruth_age_variances = tf.maximum(groundtruth_age_variances, + min_std**2) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB118624921(self): - code = """\ -def _(): - function_call( - alert_name='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', - time_delta='1h', - alert_level='bbbbbbbb', - metric='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - bork=foo) -""" + code = textwrap.dedent("""\ + def _(): + function_call( + alert_name='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', + time_delta='1h', + alert_level='bbbbbbbb', + metric='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + bork=foo) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB35417079(self): - code = """\ -class _(): - - def _(): - X = ( - _ares_label_prefix + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' # pylint: disable=line-too-long - 'PyTypePyTypePyTypePyTypePyTypePyTypePyTypePyTypePyTypePyTypePyTypePyTypePyType' # pytype: disable=attribute-error - 'CopybaraCopybaraCopybaraCopybaraCopybaraCopybaraCopybaraCopybaraCopybara' # copybara:strip - ) -""" # noqa + code = textwrap.dedent("""\ + class _(): + + def _(): + X = ( + _ares_label_prefix + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' # pylint: disable=line-too-long + 'PyTypePyTypePyTypePyTypePyTypePyTypePyTypePyTypePyTypePyTypePyTypePyTypePyType' # pytype: disable=attribute-error + 'CopybaraCopybaraCopybaraCopybaraCopybaraCopybaraCopybaraCopybaraCopybara' # copybara:strip + ) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB120047670(self): - unformatted_code = """\ -X = { - 'NO_PING_COMPONENTS': [ - 79775, # Releases / FOO API - 79770, # Releases / BAZ API - 79780], # Releases / MUX API - - 'PING_BLOCKED_BUGS': False, -} -""" - expected_formatted_code = """\ -X = { - 'NO_PING_COMPONENTS': [ - 79775, # Releases / FOO API - 79770, # Releases / BAZ API - 79780 - ], # Releases / MUX API - 'PING_BLOCKED_BUGS': False, -} -""" + unformatted_code = textwrap.dedent("""\ + X = { + 'NO_PING_COMPONENTS': [ + 79775, # Releases / FOO API + 79770, # Releases / BAZ API + 79780], # Releases / MUX API + + 'PING_BLOCKED_BUGS': False, + } + """) + expected_formatted_code = textwrap.dedent("""\ + X = { + 'NO_PING_COMPONENTS': [ + 79775, # Releases / FOO API + 79770, # Releases / BAZ API + 79780 + ], # Releases / MUX API + 'PING_BLOCKED_BUGS': False, + } + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB120245013(self): - unformatted_code = """\ -class Foo(object): - def testNoAlertForShortPeriod(self, rutabaga): - self.targets[:][streamz_path,self._fillInOtherFields(streamz_path, {streamz_field_of_interest:True})] = series.Counter('1s', '+ 500x10000') -""" # noqa - expected_formatted_code = """\ -class Foo(object): + unformatted_code = textwrap.dedent("""\ + class Foo(object): + def testNoAlertForShortPeriod(self, rutabaga): + self.targets[:][streamz_path,self._fillInOtherFields(streamz_path, {streamz_field_of_interest:True})] = series.Counter('1s', '+ 500x10000') + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + class Foo(object): - def testNoAlertForShortPeriod(self, rutabaga): - self.targets[:][ - streamz_path, - self._fillInOtherFields(streamz_path, {streamz_field_of_interest: True} - )] = series.Counter('1s', '+ 500x10000') -""" + def testNoAlertForShortPeriod(self, rutabaga): + self.targets[:][ + streamz_path, + self._fillInOtherFields(streamz_path, {streamz_field_of_interest: True} + )] = series.Counter('1s', '+ 500x10000') + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB117841880(self): - code = """\ -def xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( - aaaaaaaaaaaaaaaaaaa: AnyStr, - bbbbbbbbbbbb: Optional[Sequence[AnyStr]] = None, - cccccccccc: AnyStr = cst.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD, - dddddddddd: Sequence[SliceDimension] = (), - eeeeeeeeeeee: AnyStr = cst.DEFAULT_CONTROL_NAME, - ffffffffffffffffffff: Optional[Callable[[pd.DataFrame], - pd.DataFrame]] = None, - gggggggggggggg: ooooooooooooo = ooooooooooooo() -) -> pd.DataFrame: - pass -""" + code = textwrap.dedent("""\ + def xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( + aaaaaaaaaaaaaaaaaaa: AnyStr, + bbbbbbbbbbbb: Optional[Sequence[AnyStr]] = None, + cccccccccc: AnyStr = cst.DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD, + dddddddddd: Sequence[SliceDimension] = (), + eeeeeeeeeeee: AnyStr = cst.DEFAULT_CONTROL_NAME, + ffffffffffffffffffff: Optional[Callable[[pd.DataFrame], + pd.DataFrame]] = None, + gggggggggggggg: ooooooooooooo = ooooooooooooo() + ) -> pd.DataFrame: + pass + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB111764402(self): - unformatted_code = """\ -x = self.stubs.stub(video_classification_map, 'read_video_classifications', (lambda external_ids, **unused_kwargs: {external_id: self._get_serving_classification('video') for external_id in external_ids})) -""" # noqa - expected_formatted_code = """\ -x = self.stubs.stub(video_classification_map, 'read_video_classifications', - (lambda external_ids, **unused_kwargs: { - external_id: self._get_serving_classification('video') - for external_id in external_ids - })) -""" + unformatted_code = textwrap.dedent("""\ + x = self.stubs.stub(video_classification_map, 'read_video_classifications', (lambda external_ids, **unused_kwargs: {external_id: self._get_serving_classification('video') for external_id in external_ids})) + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + x = self.stubs.stub(video_classification_map, 'read_video_classifications', + (lambda external_ids, **unused_kwargs: { + external_id: self._get_serving_classification('video') + for external_id in external_ids + })) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB116825060(self): - code = """\ -result_df = pd.DataFrame({LEARNED_CTR_COLUMN: learned_ctr}, - index=df_metrics.index) -""" + code = textwrap.dedent("""\ + result_df = pd.DataFrame({LEARNED_CTR_COLUMN: learned_ctr}, + index=df_metrics.index) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB112711217(self): - code = """\ -def _(): - stats['moderated'] = ~stats.moderation_reason.isin( - approved_moderation_reasons) -""" + code = textwrap.dedent("""\ + def _(): + stats['moderated'] = ~stats.moderation_reason.isin( + approved_moderation_reasons) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB112867548(self): - unformatted_code = """\ -def _(): - return flask.make_response( - 'Records: {}, Problems: {}, More: {}'.format( - process_result.result_ct, process_result.problem_ct, - process_result.has_more), - httplib.ACCEPTED if process_result.has_more else httplib.OK, - {'content-type': _TEXT_CONTEXT_TYPE}) -""" - expected_formatted_code = """\ -def _(): - return flask.make_response( - 'Records: {}, Problems: {}, More: {}'.format(process_result.result_ct, - process_result.problem_ct, - process_result.has_more), - httplib.ACCEPTED if process_result.has_more else httplib.OK, - {'content-type': _TEXT_CONTEXT_TYPE}) -""" + unformatted_code = textwrap.dedent("""\ + def _(): + return flask.make_response( + 'Records: {}, Problems: {}, More: {}'.format( + process_result.result_ct, process_result.problem_ct, + process_result.has_more), + httplib.ACCEPTED if process_result.has_more else httplib.OK, + {'content-type': _TEXT_CONTEXT_TYPE}) + """) + expected_formatted_code = textwrap.dedent("""\ + def _(): + return flask.make_response( + 'Records: {}, Problems: {}, More: {}'.format(process_result.result_ct, + process_result.problem_ct, + process_result.has_more), + httplib.ACCEPTED if process_result.has_more else httplib.OK, + {'content-type': _TEXT_CONTEXT_TYPE}) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB112651423(self): - unformatted_code = """\ -def potato(feeditems, browse_use_case=None): - for item in turnip: - if kumquat: - if not feeds_variants.variants['FEEDS_LOAD_PLAYLIST_VIDEOS_FOR_ALL_ITEMS'] and item.video: - continue -""" # noqa - expected_formatted_code = """\ -def potato(feeditems, browse_use_case=None): - for item in turnip: - if kumquat: - if not feeds_variants.variants[ - 'FEEDS_LOAD_PLAYLIST_VIDEOS_FOR_ALL_ITEMS'] and item.video: - continue -""" + unformatted_code = textwrap.dedent("""\ + def potato(feeditems, browse_use_case=None): + for item in turnip: + if kumquat: + if not feeds_variants.variants['FEEDS_LOAD_PLAYLIST_VIDEOS_FOR_ALL_ITEMS'] and item.video: + continue + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + def potato(feeditems, browse_use_case=None): + for item in turnip: + if kumquat: + if not feeds_variants.variants[ + 'FEEDS_LOAD_PLAYLIST_VIDEOS_FOR_ALL_ITEMS'] and item.video: + continue + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB80484938(self): - code = """\ -for sssssss, aaaaaaaaaa in [ - ('ssssssssssssssssssss', 'sssssssssssssssssssssssss'), - ('nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn', - 'nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn'), - ('pppppppppppppppppppppppppppp', 'pppppppppppppppppppppppppppppppp'), - ('wwwwwwwwwwwwwwwwwwww', 'wwwwwwwwwwwwwwwwwwwwwwwww'), - ('sssssssssssssssss', 'sssssssssssssssssssssss'), - ('ggggggggggggggggggggggg', 'gggggggggggggggggggggggggggg'), - ('ggggggggggggggggg', 'gggggggggggggggggggggg'), - ('eeeeeeeeeeeeeeeeeeeeee', 'eeeeeeeeeeeeeeeeeeeeeeeeeee') -]: - pass - -for sssssss, aaaaaaaaaa in [ - ('ssssssssssssssssssss', 'sssssssssssssssssssssssss'), - ('nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn', 'nnnnnnnnnnnnnnnnnnnnnnnnn'), - ('pppppppppppppppppppppppppppp', 'pppppppppppppppppppppppppppppppp'), - ('wwwwwwwwwwwwwwwwwwww', 'wwwwwwwwwwwwwwwwwwwwwwwww'), - ('sssssssssssssssss', 'sssssssssssssssssssssss'), - ('ggggggggggggggggggggggg', 'gggggggggggggggggggggggggggg'), - ('ggggggggggggggggg', 'gggggggggggggggggggggg'), - ('eeeeeeeeeeeeeeeeeeeeee', 'eeeeeeeeeeeeeeeeeeeeeeeeeee') -]: - pass - -for sssssss, aaaaaaaaaa in [ - ('ssssssssssssssssssss', 'sssssssssssssssssssssssss'), - ('nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn', - 'nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn'), - ('pppppppppppppppppppppppppppp', 'pppppppppppppppppppppppppppppppp'), - ('wwwwwwwwwwwwwwwwwwww', 'wwwwwwwwwwwwwwwwwwwwwwwww'), - ('sssssssssssssssss', 'sssssssssssssssssssssss'), - ('ggggggggggggggggggggggg', 'gggggggggggggggggggggggggggg'), - ('ggggggggggggggggg', 'gggggggggggggggggggggg'), - ('eeeeeeeeeeeeeeeeeeeeee', 'eeeeeeeeeeeeeeeeeeeeeeeeeee'), -]: - pass -""" + code = textwrap.dedent("""\ + for sssssss, aaaaaaaaaa in [ + ('ssssssssssssssssssss', 'sssssssssssssssssssssssss'), + ('nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn', + 'nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn'), + ('pppppppppppppppppppppppppppp', 'pppppppppppppppppppppppppppppppp'), + ('wwwwwwwwwwwwwwwwwwww', 'wwwwwwwwwwwwwwwwwwwwwwwww'), + ('sssssssssssssssss', 'sssssssssssssssssssssss'), + ('ggggggggggggggggggggggg', 'gggggggggggggggggggggggggggg'), + ('ggggggggggggggggg', 'gggggggggggggggggggggg'), + ('eeeeeeeeeeeeeeeeeeeeee', 'eeeeeeeeeeeeeeeeeeeeeeeeeee') + ]: + pass + + for sssssss, aaaaaaaaaa in [ + ('ssssssssssssssssssss', 'sssssssssssssssssssssssss'), + ('nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn', 'nnnnnnnnnnnnnnnnnnnnnnnnn'), + ('pppppppppppppppppppppppppppp', 'pppppppppppppppppppppppppppppppp'), + ('wwwwwwwwwwwwwwwwwwww', 'wwwwwwwwwwwwwwwwwwwwwwwww'), + ('sssssssssssssssss', 'sssssssssssssssssssssss'), + ('ggggggggggggggggggggggg', 'gggggggggggggggggggggggggggg'), + ('ggggggggggggggggg', 'gggggggggggggggggggggg'), + ('eeeeeeeeeeeeeeeeeeeeee', 'eeeeeeeeeeeeeeeeeeeeeeeeeee') + ]: + pass + + for sssssss, aaaaaaaaaa in [ + ('ssssssssssssssssssss', 'sssssssssssssssssssssssss'), + ('nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn', + 'nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn'), + ('pppppppppppppppppppppppppppp', 'pppppppppppppppppppppppppppppppp'), + ('wwwwwwwwwwwwwwwwwwww', 'wwwwwwwwwwwwwwwwwwwwwwwww'), + ('sssssssssssssssss', 'sssssssssssssssssssssss'), + ('ggggggggggggggggggggggg', 'gggggggggggggggggggggggggggg'), + ('ggggggggggggggggg', 'gggggggggggggggggggggg'), + ('eeeeeeeeeeeeeeeeeeeeee', 'eeeeeeeeeeeeeeeeeeeeeeeeeee'), + ]: + pass + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB120771563(self): - code = """\ -class A: - - def b(): - d = { - "123456": [{ - "12": "aa" - }, { - "12": "bb" - }, { - "12": "cc", - "1234567890": { - "1234567": [{ - "12": "dd", - "12345": "text 1" + code = textwrap.dedent("""\ + class A: + + def b(): + d = { + "123456": [{ + "12": "aa" + }, { + "12": "bb" }, { - "12": "ee", - "12345": "text 2" + "12": "cc", + "1234567890": { + "1234567": [{ + "12": "dd", + "12345": "text 1" + }, { + "12": "ee", + "12345": "text 2" + }] + } }] } - }] - } -""" + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB79462249(self): - code = """\ -foo.bar(baz, [ - quux(thud=42), - norf, -]) -foo.bar(baz, [ - quux(), - norf, -]) -foo.bar(baz, quux(thud=42), aaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbb, - ccccccccccccccccccc) -foo.bar( - baz, - quux(thud=42), - aaaaaaaaaaaaaaaaaaaaaa=1, - bbbbbbbbbbbbbbbbbbbbb=2, - ccccccccccccccccccc=3) -""" + code = textwrap.dedent("""\ + foo.bar(baz, [ + quux(thud=42), + norf, + ]) + foo.bar(baz, [ + quux(), + norf, + ]) + foo.bar(baz, quux(thud=42), aaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbb, + ccccccccccccccccccc) + foo.bar( + baz, + quux(thud=42), + aaaaaaaaaaaaaaaaaaaaaa=1, + bbbbbbbbbbbbbbbbbbbbb=2, + ccccccccccccccccccc=3) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB113210278(self): - unformatted_code = """\ -def _(): - aaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccc(\ -eeeeeeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffffffffffffffffffffff.\ -ggggggggggggggggggggggggggggggggg.hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh()) -""" # noqa - expected_formatted_code = """\ -def _(): - aaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccc( - eeeeeeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffffffffffffffffffffff - .ggggggggggggggggggggggggggggggggg.hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh()) -""" # noqa + unformatted_code = textwrap.dedent("""\ + def _(): + aaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccc(\ + eeeeeeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffffffffffffffffffffff.\ + ggggggggggggggggggggggggggggggggg.hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh()) + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + def _(): + aaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccc( + eeeeeeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffffffffffffffffffffff + .ggggggggggggggggggggggggggggggggg.hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh()) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB77923341(self): - code = """\ -def f(): - if (aaaaaaaaaaaaaa.bbbbbbbbbbbb.ccccc <= 0 and # pytype: disable=attribute-error - ddddddddddd.eeeeeeeee == constants.FFFFFFFFFFFFFF): - raise "yo" -""" # noqa + code = textwrap.dedent("""\ + def f(): + if (aaaaaaaaaaaaaa.bbbbbbbbbbbb.ccccc <= 0 and # pytype: disable=attribute-error + ddddddddddd.eeeeeeeee == constants.FFFFFFFFFFFFFF): + raise "yo" + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB77329955(self): - code = """\ -class _(): - - @parameterized.named_parameters( - ('ReadyExpiredSuccess', True, True, True, None, None), - ('SpannerUpdateFails', True, False, True, None, None), - ('ReadyNotExpired', False, True, True, True, None), - # ('ReadyNotExpiredNotHealthy', False, True, True, False, True), - # ('ReadyNotExpiredNotHealthyErrorFails', False, True, True, False, False - # ('ReadyNotExpiredNotHealthyUpdateFails', False, False, True, False, True - ) - def _(): - pass -""" + code = textwrap.dedent("""\ + class _(): + + @parameterized.named_parameters( + ('ReadyExpiredSuccess', True, True, True, None, None), + ('SpannerUpdateFails', True, False, True, None, None), + ('ReadyNotExpired', False, True, True, True, None), + # ('ReadyNotExpiredNotHealthy', False, True, True, False, True), + # ('ReadyNotExpiredNotHealthyErrorFails', False, True, True, False, False + # ('ReadyNotExpiredNotHealthyUpdateFails', False, False, True, False, True + ) + def _(): + pass + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB65197969(self): - unformatted_code = """\ -class _(): + unformatted_code = textwrap.dedent("""\ + class _(): - def _(): - return timedelta(seconds=max(float(time_scale), small_interval) * - 1.41 ** min(num_attempts, 9)) -""" - expected_formatted_code = """\ -class _(): + def _(): + return timedelta(seconds=max(float(time_scale), small_interval) * + 1.41 ** min(num_attempts, 9)) + """) + expected_formatted_code = textwrap.dedent("""\ + class _(): - def _(): - return timedelta( - seconds=max(float(time_scale), small_interval) * - 1.41**min(num_attempts, 9)) -""" + def _(): + return timedelta( + seconds=max(float(time_scale), small_interval) * + 1.41**min(num_attempts, 9)) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB65546221(self): - unformatted_code = """\ -SUPPORTED_PLATFORMS = ( - "centos-6", - "centos-7", - "ubuntu-1204-precise", - "ubuntu-1404-trusty", - "ubuntu-1604-xenial", - "debian-7-wheezy", - "debian-8-jessie", - "debian-9-stretch",) -""" - expected_formatted_code = """\ -SUPPORTED_PLATFORMS = ( - "centos-6", - "centos-7", - "ubuntu-1204-precise", - "ubuntu-1404-trusty", - "ubuntu-1604-xenial", - "debian-7-wheezy", - "debian-8-jessie", - "debian-9-stretch", -) -""" + unformatted_code = textwrap.dedent("""\ + SUPPORTED_PLATFORMS = ( + "centos-6", + "centos-7", + "ubuntu-1204-precise", + "ubuntu-1404-trusty", + "ubuntu-1604-xenial", + "debian-7-wheezy", + "debian-8-jessie", + "debian-9-stretch",) + """) + expected_formatted_code = textwrap.dedent("""\ + SUPPORTED_PLATFORMS = ( + "centos-6", + "centos-7", + "ubuntu-1204-precise", + "ubuntu-1404-trusty", + "ubuntu-1604-xenial", + "debian-7-wheezy", + "debian-8-jessie", + "debian-9-stretch", + ) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30500455(self): - unformatted_code = """\ -INITIAL_SYMTAB = dict([(name, 'exception#' + name) for name in INITIAL_EXCEPTIONS -] * [(name, 'type#' + name) for name in INITIAL_TYPES] + [ - (name, 'function#' + name) for name in INITIAL_FUNCTIONS -] + [(name, 'const#' + name) for name in INITIAL_CONSTS]) -""" # noqa - expected_formatted_code = """\ -INITIAL_SYMTAB = dict( - [(name, 'exception#' + name) for name in INITIAL_EXCEPTIONS] * - [(name, 'type#' + name) for name in INITIAL_TYPES] + - [(name, 'function#' + name) for name in INITIAL_FUNCTIONS] + - [(name, 'const#' + name) for name in INITIAL_CONSTS]) -""" + unformatted_code = textwrap.dedent("""\ + INITIAL_SYMTAB = dict([(name, 'exception#' + name) for name in INITIAL_EXCEPTIONS + ] * [(name, 'type#' + name) for name in INITIAL_TYPES] + [ + (name, 'function#' + name) for name in INITIAL_FUNCTIONS + ] + [(name, 'const#' + name) for name in INITIAL_CONSTS]) + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + INITIAL_SYMTAB = dict( + [(name, 'exception#' + name) for name in INITIAL_EXCEPTIONS] * + [(name, 'type#' + name) for name in INITIAL_TYPES] + + [(name, 'function#' + name) for name in INITIAL_FUNCTIONS] + + [(name, 'const#' + name) for name in INITIAL_CONSTS]) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB38343525(self): - code = """\ -# This does foo. -@arg.String('some_path_to_a_file', required=True) -# This does bar. -@arg.String('some_path_to_a_file', required=True) -def f(): - print(1) -""" + code = textwrap.dedent("""\ + # This does foo. + @arg.String('some_path_to_a_file', required=True) + # This does bar. + @arg.String('some_path_to_a_file', required=True) + def f(): + print(1) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB37099651(self): - unformatted_code = """\ -_MEMCACHE = lazy.MakeLazy( - # pylint: disable=g-long-lambda - lambda: function.call.mem.clients(FLAGS.some_flag_thingy, default_namespace=_LAZY_MEM_NAMESPACE, allow_pickle=True) - # pylint: enable=g-long-lambda -) -""" # noqa - expected_formatted_code = """\ -_MEMCACHE = lazy.MakeLazy( - # pylint: disable=g-long-lambda - lambda: function.call.mem.clients( - FLAGS.some_flag_thingy, - default_namespace=_LAZY_MEM_NAMESPACE, - allow_pickle=True) - # pylint: enable=g-long-lambda -) -""" + unformatted_code = textwrap.dedent("""\ + _MEMCACHE = lazy.MakeLazy( + # pylint: disable=g-long-lambda + lambda: function.call.mem.clients(FLAGS.some_flag_thingy, default_namespace=_LAZY_MEM_NAMESPACE, allow_pickle=True) + # pylint: enable=g-long-lambda + ) + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + _MEMCACHE = lazy.MakeLazy( + # pylint: disable=g-long-lambda + lambda: function.call.mem.clients( + FLAGS.some_flag_thingy, + default_namespace=_LAZY_MEM_NAMESPACE, + allow_pickle=True) + # pylint: enable=g-long-lambda + ) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB33228502(self): - unformatted_code = """\ -def _(): - success_rate_stream_table = module.Precompute( - query_function=module.DefineQueryFunction( - name='Response error ratio', - expression=((m.Fetch( - m.Raw('monarch.BorgTask', - '/corp/travel/trips2/dispatcher/email/response'), - {'borg_job': module_config.job, 'metric:response_type': 'SUCCESS'}), - m.Fetch(m.Raw('monarch.BorgTask', '/corp/travel/trips2/dispatcher/email/response'), {'borg_job': module_config.job})) - | m.Window(m.Delta('1h')) - | m.Join('successes', 'total') - | m.Point(m.VAL['successes'] / m.VAL['total'])))) -""" # noqa - expected_formatted_code = """\ -def _(): - success_rate_stream_table = module.Precompute( - query_function=module.DefineQueryFunction( - name='Response error ratio', - expression=( - (m.Fetch( - m.Raw('monarch.BorgTask', - '/corp/travel/trips2/dispatcher/email/response'), { - 'borg_job': module_config.job, - 'metric:response_type': 'SUCCESS' - }), - m.Fetch( - m.Raw('monarch.BorgTask', - '/corp/travel/trips2/dispatcher/email/response'), - {'borg_job': module_config.job})) - | m.Window(m.Delta('1h')) - | m.Join('successes', 'total') - | m.Point(m.VAL['successes'] / m.VAL['total'])))) -""" + unformatted_code = textwrap.dedent("""\ + def _(): + success_rate_stream_table = module.Precompute( + query_function=module.DefineQueryFunction( + name='Response error ratio', + expression=((m.Fetch( + m.Raw('monarch.BorgTask', + '/corp/travel/trips2/dispatcher/email/response'), + {'borg_job': module_config.job, 'metric:response_type': 'SUCCESS'}), + m.Fetch(m.Raw('monarch.BorgTask', '/corp/travel/trips2/dispatcher/email/response'), {'borg_job': module_config.job})) + | m.Window(m.Delta('1h')) + | m.Join('successes', 'total') + | m.Point(m.VAL['successes'] / m.VAL['total'])))) + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + def _(): + success_rate_stream_table = module.Precompute( + query_function=module.DefineQueryFunction( + name='Response error ratio', + expression=( + (m.Fetch( + m.Raw('monarch.BorgTask', + '/corp/travel/trips2/dispatcher/email/response'), { + 'borg_job': module_config.job, + 'metric:response_type': 'SUCCESS' + }), + m.Fetch( + m.Raw('monarch.BorgTask', + '/corp/travel/trips2/dispatcher/email/response'), + {'borg_job': module_config.job})) + | m.Window(m.Delta('1h')) + | m.Join('successes', 'total') + | m.Point(m.VAL['successes'] / m.VAL['total'])))) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30394228(self): - code = """\ -class _(): - - def _(self): - return some.randome.function.calling( - wf, None, alert.Format(alert.subject, alert=alert, threshold=threshold), - alert.Format(alert.body, alert=alert, threshold=threshold), - alert.html_formatting) -""" + code = textwrap.dedent("""\ + class _(): + + def _(self): + return some.randome.function.calling( + wf, None, alert.Format(alert.subject, alert=alert, threshold=threshold), + alert.Format(alert.body, alert=alert, threshold=threshold), + alert.html_formatting) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB65246454(self): - unformatted_code = """\ -class _(): + unformatted_code = textwrap.dedent("""\ + class _(): - def _(self): - self.assertEqual({i.id - for i in successful_instances}, - {i.id - for i in self._statuses.successful_instances}) -""" - expected_formatted_code = """\ -class _(): + def _(self): + self.assertEqual({i.id + for i in successful_instances}, + {i.id + for i in self._statuses.successful_instances}) + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + class _(): - def _(self): - self.assertEqual({i.id for i in successful_instances}, - {i.id for i in self._statuses.successful_instances}) -""" + def _(self): + self.assertEqual({i.id for i in successful_instances}, + {i.id for i in self._statuses.successful_instances}) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB67935450(self): - unformatted_code = """\ -def _(): - return ( - (Gauge( - metric='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - group_by=group_by + ['metric:process_name'], - metric_filter={'metric:process_name': process_name_re}), - Gauge( - metric='bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', - group_by=group_by + ['metric:process_name'], - metric_filter={'metric:process_name': process_name_re})) - | expr.Join( - left_name='start', left_default=0, right_name='end', right_default=0) - | m.Point( - m.Cond(m.VAL['end'] != 0, m.VAL['end'], k.TimestampMicros() / - 1000000L) - m.Cond(m.VAL['start'] != 0, m.VAL['start'], - m.TimestampMicros() / 1000000L))) -""" - expected_formatted_code = """\ -def _(): - return ( - (Gauge( - metric='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - group_by=group_by + ['metric:process_name'], - metric_filter={'metric:process_name': process_name_re}), - Gauge( - metric='bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', - group_by=group_by + ['metric:process_name'], - metric_filter={'metric:process_name': process_name_re})) - | expr.Join( - left_name='start', left_default=0, right_name='end', right_default=0) - | m.Point( - m.Cond(m.VAL['end'] != 0, m.VAL['end'], - k.TimestampMicros() / 1000000L) - - m.Cond(m.VAL['start'] != 0, m.VAL['start'], - m.TimestampMicros() / 1000000L))) -""" + unformatted_code = textwrap.dedent("""\ + def _(): + return ( + (Gauge( + metric='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + group_by=group_by + ['metric:process_name'], + metric_filter={'metric:process_name': process_name_re}), + Gauge( + metric='bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', + group_by=group_by + ['metric:process_name'], + metric_filter={'metric:process_name': process_name_re})) + | expr.Join( + left_name='start', left_default=0, right_name='end', right_default=0) + | m.Point( + m.Cond(m.VAL['end'] != 0, m.VAL['end'], k.TimestampMicros() / + 1000000L) - m.Cond(m.VAL['start'] != 0, m.VAL['start'], + m.TimestampMicros() / 1000000L))) + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + def _(): + return ( + (Gauge( + metric='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + group_by=group_by + ['metric:process_name'], + metric_filter={'metric:process_name': process_name_re}), + Gauge( + metric='bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', + group_by=group_by + ['metric:process_name'], + metric_filter={'metric:process_name': process_name_re})) + | expr.Join( + left_name='start', left_default=0, right_name='end', right_default=0) + | m.Point( + m.Cond(m.VAL['end'] != 0, m.VAL['end'], + k.TimestampMicros() / 1000000L) - + m.Cond(m.VAL['start'] != 0, m.VAL['start'], + m.TimestampMicros() / 1000000L))) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB66011084(self): - unformatted_code = """\ -X = { -"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": # Comment 1. -([] if True else [ # Comment 2. - "bbbbbbbbbbbbbbbbbbb", # Comment 3. - "cccccccccccccccccccccccc", # Comment 4. - "ddddddddddddddddddddddddd", # Comment 5. - "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", # Comment 6. - "fffffffffffffffffffffffffffffff", # Comment 7. - "ggggggggggggggggggggggggggg", # Comment 8. - "hhhhhhhhhhhhhhhhhh", # Comment 9. -]), -} -""" - expected_formatted_code = """\ -X = { - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": # Comment 1. - ([] if True else [ # Comment 2. + unformatted_code = textwrap.dedent("""\ + X = { + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": # Comment 1. + ([] if True else [ # Comment 2. "bbbbbbbbbbbbbbbbbbb", # Comment 3. - "cccccccccccccccccccccccc", # Comment 4. - "ddddddddddddddddddddddddd", # Comment 5. - "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", # Comment 6. - "fffffffffffffffffffffffffffffff", # Comment 7. - "ggggggggggggggggggggggggggg", # Comment 8. + "cccccccccccccccccccccccc", # Comment 4. + "ddddddddddddddddddddddddd", # Comment 5. + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", # Comment 6. + "fffffffffffffffffffffffffffffff", # Comment 7. + "ggggggggggggggggggggggggggg", # Comment 8. "hhhhhhhhhhhhhhhhhh", # Comment 9. ]), -} -""" + } + """) + expected_formatted_code = textwrap.dedent("""\ + X = { + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": # Comment 1. + ([] if True else [ # Comment 2. + "bbbbbbbbbbbbbbbbbbb", # Comment 3. + "cccccccccccccccccccccccc", # Comment 4. + "ddddddddddddddddddddddddd", # Comment 5. + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", # Comment 6. + "fffffffffffffffffffffffffffffff", # Comment 7. + "ggggggggggggggggggggggggggg", # Comment 8. + "hhhhhhhhhhhhhhhhhh", # Comment 9. + ]), + } + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB67455376(self): - unformatted_code = """\ -sponge_ids.extend(invocation.id() for invocation in self._client.GetInvocationsByLabels(labels)) -""" # noqa - expected_formatted_code = """\ -sponge_ids.extend(invocation.id() - for invocation in self._client.GetInvocationsByLabels(labels)) -""" + unformatted_code = textwrap.dedent("""\ + sponge_ids.extend(invocation.id() for invocation in self._client.GetInvocationsByLabels(labels)) + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + sponge_ids.extend(invocation.id() + for invocation in self._client.GetInvocationsByLabels(labels)) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB35210351(self): - unformatted_code = """\ -def _(): - config.AnotherRuleThing( - 'the_title_to_the_thing_here', - {'monitorname': 'firefly', - 'service': ACCOUNTING_THING, - 'severity': 'the_bug', - 'monarch_module_name': alerts.TheLabel(qa_module_regexp, invert=True)}, - fanout, - alerts.AlertUsToSomething( - GetTheAlertToIt('the_title_to_the_thing_here'), - GetNotificationTemplate('your_email_here'))) -""" - expected_formatted_code = """\ -def _(): - config.AnotherRuleThing( - 'the_title_to_the_thing_here', { - 'monitorname': 'firefly', - 'service': ACCOUNTING_THING, - 'severity': 'the_bug', - 'monarch_module_name': alerts.TheLabel(qa_module_regexp, invert=True) - }, fanout, - alerts.AlertUsToSomething( - GetTheAlertToIt('the_title_to_the_thing_here'), - GetNotificationTemplate('your_email_here'))) -""" + unformatted_code = textwrap.dedent("""\ + def _(): + config.AnotherRuleThing( + 'the_title_to_the_thing_here', + {'monitorname': 'firefly', + 'service': ACCOUNTING_THING, + 'severity': 'the_bug', + 'monarch_module_name': alerts.TheLabel(qa_module_regexp, invert=True)}, + fanout, + alerts.AlertUsToSomething( + GetTheAlertToIt('the_title_to_the_thing_here'), + GetNotificationTemplate('your_email_here'))) + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + def _(): + config.AnotherRuleThing( + 'the_title_to_the_thing_here', { + 'monitorname': 'firefly', + 'service': ACCOUNTING_THING, + 'severity': 'the_bug', + 'monarch_module_name': alerts.TheLabel(qa_module_regexp, invert=True) + }, fanout, + alerts.AlertUsToSomething( + GetTheAlertToIt('the_title_to_the_thing_here'), + GetNotificationTemplate('your_email_here'))) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB34774905(self): - unformatted_code = """\ -x=[VarExprType(ir_name=IrName( value='x', -expr_type=UnresolvedAttrExprType( atom=UnknownExprType(), attr_name=IrName( - value='x', expr_type=UnknownExprType(), usage='UNKNOWN', fqn=None, - astn=None), usage='REF'), usage='ATTR', fqn='.x', astn=None))] -""" - expected_formatted_code = """\ -x = [ - VarExprType( - ir_name=IrName( - value='x', - expr_type=UnresolvedAttrExprType( - atom=UnknownExprType(), - attr_name=IrName( + unformatted_code = textwrap.dedent("""\ + x=[VarExprType(ir_name=IrName( value='x', + expr_type=UnresolvedAttrExprType( atom=UnknownExprType(), attr_name=IrName( + value='x', expr_type=UnknownExprType(), usage='UNKNOWN', fqn=None, + astn=None), usage='REF'), usage='ATTR', fqn='.x', astn=None))] + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + x = [ + VarExprType( + ir_name=IrName( value='x', - expr_type=UnknownExprType(), - usage='UNKNOWN', - fqn=None, - astn=None), - usage='REF'), - usage='ATTR', - fqn='.x', - astn=None)) -] -""" + expr_type=UnresolvedAttrExprType( + atom=UnknownExprType(), + attr_name=IrName( + value='x', + expr_type=UnknownExprType(), + usage='UNKNOWN', + fqn=None, + astn=None), + usage='REF'), + usage='ATTR', + fqn='.x', + astn=None)) + ] + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB65176185(self): - code = """\ -xx = zip(*[(a, b) for (a, b, c) in yy]) -""" + code = textwrap.dedent("""\ + xx = zip(*[(a, b) for (a, b, c) in yy]) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB35210166(self): - unformatted_code = """\ -def _(): - query = ( - m.Fetch(n.Raw('monarch.BorgTask', '/proc/container/memory/usage'), { 'borg_user': borguser, 'borg_job': jobname }) - | o.Window(m.Align('5m')) | p.GroupBy(['borg_user', 'borg_job', 'borg_cell'], q.Mean())) -""" # noqa - expected_formatted_code = """\ -def _(): - query = ( - m.Fetch( - n.Raw('monarch.BorgTask', '/proc/container/memory/usage'), { - 'borg_user': borguser, - 'borg_job': jobname - }) - | o.Window(m.Align('5m')) - | p.GroupBy(['borg_user', 'borg_job', 'borg_cell'], q.Mean())) -""" + unformatted_code = textwrap.dedent("""\ + def _(): + query = ( + m.Fetch(n.Raw('monarch.BorgTask', '/proc/container/memory/usage'), { 'borg_user': borguser, 'borg_job': jobname }) + | o.Window(m.Align('5m')) | p.GroupBy(['borg_user', 'borg_job', 'borg_cell'], q.Mean())) + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + def _(): + query = ( + m.Fetch( + n.Raw('monarch.BorgTask', '/proc/container/memory/usage'), { + 'borg_user': borguser, + 'borg_job': jobname + }) + | o.Window(m.Align('5m')) + | p.GroupBy(['borg_user', 'borg_job', 'borg_cell'], q.Mean())) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB32167774(self): - unformatted_code = """\ -X = ( - 'is_official', - 'is_cover', - 'is_remix', - 'is_instrumental', - 'is_live', - 'has_lyrics', - 'is_album', - 'is_compilation',) -""" - expected_formatted_code = """\ -X = ( - 'is_official', - 'is_cover', - 'is_remix', - 'is_instrumental', - 'is_live', - 'has_lyrics', - 'is_album', - 'is_compilation', -) -""" + unformatted_code = textwrap.dedent("""\ + X = ( + 'is_official', + 'is_cover', + 'is_remix', + 'is_instrumental', + 'is_live', + 'has_lyrics', + 'is_album', + 'is_compilation',) + """) + expected_formatted_code = textwrap.dedent("""\ + X = ( + 'is_official', + 'is_cover', + 'is_remix', + 'is_instrumental', + 'is_live', + 'has_lyrics', + 'is_album', + 'is_compilation', + ) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB66912275(self): - unformatted_code = """\ -def _(): - with self.assertRaisesRegexp(errors.HttpError, 'Invalid'): - patch_op = api_client.forwardingRules().patch( - project=project_id, - region=region, - forwardingRule=rule_name, - body={'fingerprint': base64.urlsafe_b64encode('invalid_fingerprint')}).execute() -""" # noqa - expected_formatted_code = """\ -def _(): - with self.assertRaisesRegexp(errors.HttpError, 'Invalid'): - patch_op = api_client.forwardingRules().patch( - project=project_id, - region=region, - forwardingRule=rule_name, - body={ - 'fingerprint': base64.urlsafe_b64encode('invalid_fingerprint') - }).execute() -""" + unformatted_code = textwrap.dedent("""\ + def _(): + with self.assertRaisesRegexp(errors.HttpError, 'Invalid'): + patch_op = api_client.forwardingRules().patch( + project=project_id, + region=region, + forwardingRule=rule_name, + body={'fingerprint': base64.urlsafe_b64encode('invalid_fingerprint')}).execute() + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + def _(): + with self.assertRaisesRegexp(errors.HttpError, 'Invalid'): + patch_op = api_client.forwardingRules().patch( + project=project_id, + region=region, + forwardingRule=rule_name, + body={ + 'fingerprint': base64.urlsafe_b64encode('invalid_fingerprint') + }).execute() + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB67312284(self): - code = """\ -def _(): - self.assertEqual( - [u'to be published 2', u'to be published 1', u'to be published 0'], - [el.text for el in page.first_column_tds]) -""" + code = textwrap.dedent("""\ + def _(): + self.assertEqual( + [u'to be published 2', u'to be published 1', u'to be published 0'], + [el.text for el in page.first_column_tds]) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB65241516(self): - unformatted_code = """\ -checkpoint_files = gfile.Glob(os.path.join(TrainTraceDir(unit_key, "*", "*"), embedding_model.CHECKPOINT_FILENAME + "-*")) -""" # noqa - expected_formatted_code = """\ -checkpoint_files = gfile.Glob( - os.path.join( - TrainTraceDir(unit_key, "*", "*"), - embedding_model.CHECKPOINT_FILENAME + "-*")) -""" + unformatted_code = textwrap.dedent("""\ + checkpoint_files = gfile.Glob(os.path.join(TrainTraceDir(unit_key, "*", "*"), embedding_model.CHECKPOINT_FILENAME + "-*")) + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + checkpoint_files = gfile.Glob( + os.path.join( + TrainTraceDir(unit_key, "*", "*"), + embedding_model.CHECKPOINT_FILENAME + "-*")) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -857,26 +857,26 @@ def testB37460004(self): code = textwrap.dedent("""\ assert all(s not in (_SENTINEL, None) for s in nested_schemas ), 'Nested schemas should never contain None/_SENTINEL' - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB36806207(self): - code = """\ -def _(): - linearity_data = [[row] for row in [ - "%.1f mm" % (np.mean(linearity_values["pos_error"]) * 1000.0), - "%.1f mm" % (np.max(linearity_values["pos_error"]) * 1000.0), - "%.1f mm" % (np.mean(linearity_values["pos_error_chunk_mean"]) * 1000.0), - "%.1f mm" % (np.max(linearity_values["pos_error_chunk_max"]) * 1000.0), - "%.1f deg" % math.degrees(np.mean(linearity_values["rot_noise"])), - "%.1f deg" % math.degrees(np.max(linearity_values["rot_noise"])), - "%.1f deg" % math.degrees(np.mean(linearity_values["rot_drift"])), - "%.1f deg" % math.degrees(np.max(linearity_values["rot_drift"])), - "%.1f%%" % (np.max(linearity_values["pos_discontinuity"]) * 100.0), - "%.1f%%" % (np.max(linearity_values["rot_discontinuity"]) * 100.0) - ]] -""" + code = textwrap.dedent("""\ + def _(): + linearity_data = [[row] for row in [ + "%.1f mm" % (np.mean(linearity_values["pos_error"]) * 1000.0), + "%.1f mm" % (np.max(linearity_values["pos_error"]) * 1000.0), + "%.1f mm" % (np.mean(linearity_values["pos_error_chunk_mean"]) * 1000.0), + "%.1f mm" % (np.max(linearity_values["pos_error_chunk_max"]) * 1000.0), + "%.1f deg" % math.degrees(np.mean(linearity_values["rot_noise"])), + "%.1f deg" % math.degrees(np.max(linearity_values["rot_noise"])), + "%.1f deg" % math.degrees(np.mean(linearity_values["rot_drift"])), + "%.1f deg" % math.degrees(np.max(linearity_values["rot_drift"])), + "%.1f%%" % (np.max(linearity_values["pos_discontinuity"]) * 100.0), + "%.1f%%" % (np.max(linearity_values["rot_discontinuity"]) * 100.0) + ]] + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -890,7 +890,7 @@ def _(): _(ppppppppppppppppppppppppppppppppppppp), *(qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq), **(qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq)) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -903,7 +903,7 @@ def _(): ('/some/path/to/a/file/that/is/needed/by/this/process') } } - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def _(): X = { @@ -912,7 +912,7 @@ def _(): ('/some/path/to/a/file/that/is/needed/by/this/process') } } - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -921,13 +921,13 @@ def testB31063453(self): def _(): while ((not mpede_proc) or ((time_time() - last_modified) < FLAGS_boot_idle_timeout)): pass - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def _(): while ((not mpede_proc) or ((time_time() - last_modified) < FLAGS_boot_idle_timeout)): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -942,7 +942,7 @@ def _(): 'read': 'name/some-type-of-very-long-name-for-reading-perms', 'modify': 'name/some-other-type-of-very-long-name-for-modifying' }) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def _(): labelacl = Env( @@ -954,18 +954,18 @@ def _(): 'read': 'name/some-type-of-very-long-name-for-reading-perms', 'modify': 'name/some-other-type-of-very-long-name-for-modifying' }) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB34682902(self): unformatted_code = textwrap.dedent("""\ logging.info("Mean angular velocity norm: %.3f", np.linalg.norm(np.mean(ang_vel_arr, axis=0))) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ logging.info("Mean angular velocity norm: %.3f", np.linalg.norm(np.mean(ang_vel_arr, axis=0))) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -975,13 +975,13 @@ class _(): def _(): hints.append(('hg tag -f -l -r %s %s # %s' % (short(ctx.node( )), candidatetag, firstline))[:78]) - """) + """) expected_formatted_code = textwrap.dedent("""\ class _(): def _(): hints.append(('hg tag -f -l -r %s %s # %s' % (short(ctx.node()), candidatetag, firstline))[:78]) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1016,7 +1016,7 @@ def testB32931780(self): 'this is an entry', } } - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ environments = { 'prod': { @@ -1043,7 +1043,7 @@ def testB32931780(self): '.....': 'this is an entry', } } - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1057,7 +1057,7 @@ def _(): }, 'order': 'ASCENDING' }) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1087,7 +1087,7 @@ def _BlankDefinition(): 'isnew': True, 'dirty': False, } - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1098,13 +1098,13 @@ def testB32737279(self): # Comment. 'value' } - """) + """) expected_formatted_code = textwrap.dedent("""\ here_is_a_dict = { 'key': # Comment. 'value' } - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1115,7 +1115,7 @@ def _(): job_message.call not in ('*', call) or job_message.mall not in ('*', job_name)): return False - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1125,23 +1125,23 @@ class _(): def __init__(self, metric, fields_cb=None): self._fields_cb = fields_cb or (lambda *unused_args, **unused_kwargs: {}) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB31911533(self): - code = """\ -class _(): - - @parameterized.NamedParameters( - ('IncludingModInfoWithHeaderList', AAAA, aaaa), - ('IncludingModInfoWithoutHeaderList', BBBB, bbbbb), - ('ExcludingModInfoWithHeaderList', CCCCC, cccc), - ('ExcludingModInfoWithoutHeaderList', DDDDD, ddddd), - ) - def _(): - pass -""" + code = textwrap.dedent("""\ + class _(): + + @parameterized.NamedParameters( + ('IncludingModInfoWithHeaderList', AAAA, aaaa), + ('IncludingModInfoWithoutHeaderList', BBBB, bbbbb), + ('ExcludingModInfoWithHeaderList', CCCCC, cccc), + ('ExcludingModInfoWithoutHeaderList', DDDDD, ddddd), + ) + def _(): + pass + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1154,7 +1154,7 @@ def aaaaa(self, bbbbb, cccccccccccccc=None): # TODO(who): pylint: disable=unuse def xxxxx(self, yyyyy, zzzzzzzzzzzzzz=None): # A normal comment that runs over the column limit. return 1 - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ class _(): @@ -1166,7 +1166,7 @@ def xxxxx( yyyyy, zzzzzzzzzzzzzz=None): # A normal comment that runs over the column limit. return 1 - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1174,13 +1174,13 @@ def testB30760569(self): unformatted_code = textwrap.dedent("""\ {'1234567890123456789012345678901234567890123456789012345678901234567890': '1234567890123456789012345678901234567890'} - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ { '1234567890123456789012345678901234567890123456789012345678901234567890': '1234567890123456789012345678901234567890' } - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1190,7 +1190,7 @@ class Thing: def Function(self): thing.Scrape('/aaaaaaaaa/bbbbbbbbbb/ccccc/dddd/eeeeeeeeeeeeee/ffffffffffffff').AndReturn(42) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ class Thing: @@ -1198,7 +1198,7 @@ def Function(self): thing.Scrape( '/aaaaaaaaa/bbbbbbbbbb/ccccc/dddd/eeeeeeeeeeeeee/ffffffffffffff' ).AndReturn(42) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1211,7 +1211,7 @@ def main(unused_argv): bbbbbbbbb.usage, ccccccccc.within, imports.ddddddddddddddddddd(name_item.ffffffffffffffff))) - """) + """) expected_formatted_code = textwrap.dedent("""\ def main(unused_argv): if True: @@ -1219,7 +1219,7 @@ def main(unused_argv): aaaaaaaaaaa.comment('import-from[{}] {} {}'.format( bbbbbbbbb.usage, ccccccccc.within, imports.ddddddddddddddddddd(name_item.ffffffffffffffff))) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1228,12 +1228,12 @@ def testB30442148(self): def lulz(): return (some_long_module_name.SomeLongClassName. some_long_attribute_name.some_long_method_name()) - """) + """) expected_formatted_code = textwrap.dedent("""\ def lulz(): return (some_long_module_name.SomeLongClassName.some_long_attribute_name .some_long_method_name()) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1252,7 +1252,7 @@ def _(): 'lllllllllllll': None, # use the default } } - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def _(): xxxxxxxxxxxxxxxxxxx = { @@ -1269,7 +1269,7 @@ def _(): 'lllllllllllll': None, # use the default } } - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1280,7 +1280,7 @@ class _(): def _(): self.assertFalse( evaluation_runner.get_larps_in_eval_set('these_arent_the_larps')) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1291,7 +1291,7 @@ class _(): def __repr__(self): return '' % ( self._id, self._stub._stub.rpc_channel().target()) # pylint:disable=protected-access - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1304,7 +1304,7 @@ def _(): # This is another comment foo() - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1316,7 +1316,7 @@ def testB30087363(self): # This is another comment elif True: foo() - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1325,14 +1325,14 @@ def testB29093579(self): def _(): _xxxxxxxxxxxxxxx(aaaaaaaa, bbbbbbbbbbbbbb.cccccccccc[ dddddddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffff]) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def _(): _xxxxxxxxxxxxxxx( aaaaaaaa, bbbbbbbbbbbbbb.cccccccccc[dddddddddddddddddddddddddddd .eeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffff]) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1344,7 +1344,7 @@ def testB26382315(self): # Comment def foo(): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1359,7 +1359,7 @@ def testB27616132(self): mock.call(100, start_cursor=cursor_2), ]) - """) + """) expected_formatted_code = textwrap.dedent("""\ if True: query.fetch_page.assert_has_calls([ @@ -1367,7 +1367,7 @@ def testB27616132(self): mock.call(100, start_cursor=cursor_1), mock.call(100, start_cursor=cursor_2), ]) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1381,7 +1381,7 @@ def testB27590179(self): False: self.bbb.cccccccccc(ddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee) }) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ if True: if True: @@ -1391,7 +1391,7 @@ def testB27590179(self): False: self.bbb.cccccccccc(ddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee) }) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1399,13 +1399,13 @@ def testB27266946(self): unformatted_code = textwrap.dedent("""\ def _(): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = (self.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccccccccccc) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def _(): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = ( self.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb .cccccccccccccccccccccccccccccccccccc) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1420,7 +1420,7 @@ def testB25505359(self): 'dddddddddddd': [] }] } - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1429,7 +1429,7 @@ def testB25324261(self): aaaaaaaaa = set(bbbb.cccc for ddd in eeeeee.fffffffffff.gggggggggggggggg for cccc in ddd.specification) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1441,7 +1441,7 @@ def test(self): self.bbbbbbb[0]['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', { 'xxxxxx': 'yyyyyy' }] = cccccc.ddd('1m', '10x1+1') - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1449,7 +1449,7 @@ def testB25165602(self): code = textwrap.dedent("""\ def f(): ids = {u: i for u, i in zip(self.aaaaa, xrange(42, 42 + len(self.aaaaaa)))} - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1458,7 +1458,7 @@ def testB25157123(self): def ListArgs(): FairlyLongMethodName([relatively_long_identifier_for_a_list], another_argument_with_a_long_identifier) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1470,7 +1470,7 @@ def foo(): 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa': '$bbbbbbbbbbbbbbbbbbbbbbbb', }) - """) + """) expected_formatted_code = textwrap.dedent("""\ def foo(): return collections.OrderedDict({ @@ -1478,7 +1478,7 @@ def foo(): 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa': '$bbbbbbbbbbbbbbbbbbbbbbbb', }) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1488,7 +1488,7 @@ def testB25131481(self): 'materialize': lambda x: some_type_of_function('materialize ' + x.command_def), '#': lambda x: x # do nothing }) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ APPARENT_ACTIONS = ( 'command_type', @@ -1498,7 +1498,7 @@ def testB25131481(self): '#': lambda x: x # do nothing }) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1513,7 +1513,7 @@ def foo(): "PPPPPPPPPPPPPPPPPPPPP": FLAGS.aaaaaaaaaaaaaa + FLAGS.bbbbbbbbbbbbbbbbbbb, }) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def foo(): if True: @@ -1525,7 +1525,7 @@ def foo(): "PPPPPPPPPPPPPPPPPPPPP": FLAGS.aaaaaaaaaaaaaa + FLAGS.bbbbbbbbbbbbbbbbbbb, }) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1537,7 +1537,7 @@ def foo(self): unused_error, result = server.Query( ['AA BBBB CCC DDD EEEEEEEE X YY ZZZZ FFF EEE AAAAAAAA'], aaaaaaaaaaa=True, bbbbbbbb=None) - """) + """) expected_formatted_code = textwrap.dedent("""\ class A(object): @@ -1564,7 +1564,7 @@ def f(): 'wiz': {'account': 'wiz', 'lines': 'l8'} }) - """) + """) expected_formatted_code = textwrap.dedent("""\ class F(): @@ -1584,7 +1584,7 @@ def f(): 'lines': 'l8' } }) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1593,13 +1593,13 @@ def testB20551180(self): def foo(): if True: return (struct.pack('aaaa', bbbbbbbbbb, ccccccccccccccc, dddddddd) + eeeeeee) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def foo(): if True: return (struct.pack('aaaa', bbbbbbbbbb, ccccccccccccccc, dddddddd) + eeeeeee) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1608,7 +1608,7 @@ def testB23944849(self): class A(object): def xxxxxxxxx(self, aaaaaaa, bbbbbbb=ccccccccccc, dddddd=300, eeeeeeeeeeeeee=None, fffffffffffffff=0): pass - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ class A(object): @@ -1619,7 +1619,7 @@ def xxxxxxxxx(self, eeeeeeeeeeeeee=None, fffffffffffffff=0): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1628,14 +1628,14 @@ def testB23935890(self): class F(): def functioni(self, aaaaaaa, bbbbbbb, cccccc, dddddddddddddd, eeeeeeeeeeeeeee): pass - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ class F(): def functioni(self, aaaaaaa, bbbbbbb, cccccc, dddddddddddddd, eeeeeeeeeeeeeee): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1660,7 +1660,7 @@ def _(): | m.ggggggg(bbbbbbbbbbbbbbb)) | m.jjjj() | m.ppppp(m.vvv[0] + m.vvv[1])) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1678,7 +1678,7 @@ def f(): | m.ggggggg(self.gggggggg)) | m.jjjj() | m.ppppp(m.VAL[0] / m.VAL[1])) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1686,11 +1686,11 @@ def testB20016122(self): unformatted_code = textwrap.dedent("""\ from a_very_long_or_indented_module_name_yada_yada import (long_argument_1, long_argument_2) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ from a_very_long_or_indented_module_name_yada_yada import ( long_argument_1, long_argument_2) - """) + """) try: style.SetGlobalStyle( @@ -1719,7 +1719,7 @@ def __eq__(self, other): and self.gggggg == other.gggggg and self.hhh == other.hhh and len(self.iiiiiiii) == len(other.iiiiiiii) and all(jjjjjjj in other.iiiiiiii for jjjjjjj in self.iiiiiiii)) - """) # noqa + """) # noqa try: style.SetGlobalStyle( @@ -1736,13 +1736,13 @@ def testB22527411(self): def f(): if True: aaaaaa.bbbbbbbbbbbbbbbbbbbb[-1].cccccccccccccc.ddd().eeeeeeee(ffffffffffffff) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def f(): if True: aaaaaa.bbbbbbbbbbbbbbbbbbbb[-1].cccccccccccccc.ddd().eeeeeeee( ffffffffffffff) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1754,7 +1754,7 @@ def main(unused_argv): 'xxx': '%s/cccccc/ddddddddddddddddddd.jar' % (eeeeee.FFFFFFFFFFFFFFFFFF), } - """) + """) expected_formatted_code = textwrap.dedent("""\ def main(unused_argv): if True: @@ -1762,7 +1762,7 @@ def main(unused_argv): 'xxx': '%s/cccccc/ddddddddddddddddddd.jar' % (eeeeee.FFFFFFFFFFFFFFFFFF), } - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1771,7 +1771,7 @@ def testB20813997(self): def myfunc_1(): myarray = numpy.zeros((2, 2, 2)) print(myarray[:, 1, :]) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1785,7 +1785,7 @@ def testB20605036(self): 'dddddddddddddddddddddddddddddddddddddddddd', } } - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1797,7 +1797,7 @@ def testB20562732(self): # Comment about second list item 'Second item', ] - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1817,7 +1817,7 @@ def testB20128830(self): ], }, } - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1834,7 +1834,7 @@ def do_nothing(self, class_1_count): class_0_count=class_0_count, class_1_name=self.class_1_name, class_1_count=class_1_count)) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1843,7 +1843,7 @@ def testB19626808(self): if True: aaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbb( 'ccccccccccc', ddddddddd='eeeee').fffffffff([ggggggggggggggggggggg]) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1857,7 +1857,7 @@ def testB19547210(self): xxxxxxxxxxxx.yyyyyyyyyyyyyy.zzzzzzzz, xxxxxxxxxxxx.yyyyyyyyyyyyyy.zzzzzzzz): continue - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1867,7 +1867,7 @@ def f(): if (aaaaaaaaaaaaaaa.start >= aaaaaaaaaaaaaaa.end or bbbbbbbbbbbbbbb.start >= bbbbbbbbbbbbbbb.end): return False - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1879,7 +1879,7 @@ def f(): if b: continue if c: break return 0 - """) + """) try: style.SetGlobalStyle(style.CreatePEP8Style()) @@ -1893,7 +1893,7 @@ def testB19353268(self): code = textwrap.dedent("""\ a = {1, 2, 3}[x] b = {'foo': 42, 'bar': 37}['foo'] - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1907,7 +1907,7 @@ def bar(self): fffffffffff=(aaaaaaa.bbbbbbbb.ccccccc.dddddddddddddddddddd .Mmmmmmmmmmmmmmmmmm(-1, 'permission error'))): self.assertRaises(nnnnnnnnnnnnnnnn.ooooo, ppppp.qqqqqqqqqqqqqqqqq) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ class Foo(object): @@ -1918,7 +1918,7 @@ def bar(self): aaaaaaa.bbbbbbbb.ccccccc.dddddddddddddddddddd.Mmmmmmmmmmmmmmmmmm( -1, 'permission error'))): self.assertRaises(nnnnnnnnnnnnnnnn.ooooo, ppppp.qqqqqqqqqqqqqqqqq) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -1927,19 +1927,19 @@ def testB19194420(self): method.Set( 'long argument goes here that causes the line to break', lambda arg2=0.5: arg2) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19073499(self): - code = """\ -instance = ( - aaaaaaa.bbbbbbb().ccccccccccccccccc().ddddddddddd({ - 'aa': 'context!' - }).eeeeeeeeeeeeeeeeeee({ # Inline comment about why fnord has the value 6. - 'fnord': 6 - })) -""" + code = textwrap.dedent("""\ + instance = ( + aaaaaaa.bbbbbbb().ccccccccccccccccc().ddddddddddd({ + 'aa': 'context!' + }).eeeeeeeeeeeeeeeeeee({ # Inline comment about why fnord has the value 6. + 'fnord': 6 + })) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1949,7 +1949,7 @@ def testB18257115(self): if True: self._Test(aaaa, bbbbbbb.cccccccccc, dddddddd, eeeeeeeeeee, [ffff, ggggggggggg, hhhhhhhhhhhh, iiiiii, jjjj]) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1967,7 +1967,7 @@ def Bar(self): 'kkkkkkkkkkkk': kkkkkkkkkkkk, }, llllllllll=mmmmmm.nnnnnnnnnnnnnnnn) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1986,7 +1986,7 @@ def testB18256826(self): # Line two. elif False: pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -1997,7 +1997,7 @@ def testB18255697(self): # Next comment 'YYYYYYYYYYYYYYYY': ['zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'], } - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -2006,12 +2006,12 @@ def testB17534869(self): if True: self.assertLess(abs(time.time()-aaaa.bbbbbbbbbbb( datetime.datetime.now())), 1) - """) + """) expected_formatted_code = textwrap.dedent("""\ if True: self.assertLess( abs(time.time() - aaaa.bbbbbbbbbbb(datetime.datetime.now())), 1) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -2020,16 +2020,15 @@ def testB17489866(self): def f(): if True: if True: - return aaaa.bbbbbbbbb(ccccccc=dddddddddddddd({('eeee', \ -'ffffffff'): str(j)})) - """) + return aaaa.bbbbbbbbb(ccccccc=dddddddddddddd({('eeee', 'ffffffff'): str(j)})) + """) # noqa expected_formatted_code = textwrap.dedent("""\ def f(): if True: if True: return aaaa.bbbbbbbbb( ccccccc=dddddddddddddd({('eeee', 'ffffffff'): str(j)})) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -2044,7 +2043,7 @@ def bbbbbbbbbb(self): "eeeeeeeee ffffffffff" ), "rb") as gggggggggggggggggggg: print(gggggggggggggggggggg) - """) + """) expected_formatted_code = textwrap.dedent("""\ class aaaaaaaaaaaaaa(object): @@ -2054,7 +2053,7 @@ def bbbbbbbbbb(self): os.path.join(aaaaa.bbbbb.ccccccccccc, DDDDDDDDDDDDDDD, "eeeeeeeee ffffffffff"), "rb") as gggggggggggggggggggg: print(gggggggggggggggggggg) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -2069,7 +2068,7 @@ class SomeClass(object): 'BBB': 1.0, 'DDDDDDDD': 0.4811 } - """) + """) expected_formatted_code = textwrap.dedent("""\ '''blah......''' @@ -2081,7 +2080,7 @@ class SomeClass(object): 'BBB': 1.0, 'DDDDDDDD': 0.4811 } - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -2092,13 +2091,13 @@ def testB16783631(self): eeeeeeeee=self.fffffffffffff )as gggg: pass - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ if True: with aaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccc( ddddddddddddd, eeeeeeeee=self.fffffffffffff) as gggg: pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -2107,7 +2106,7 @@ def testB16572361(self): def foo(self): def bar(my_dict_name): self.my_dict_name['foo-bar-baz-biz-boo-baa-baa'].IncrementBy.assert_called_once_with('foo_bar_baz_boo') - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def foo(self): @@ -2115,7 +2114,7 @@ def bar(my_dict_name): self.my_dict_name[ 'foo-bar-baz-biz-boo-baa-baa'].IncrementBy.assert_called_once_with( 'foo_bar_baz_boo') - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -2125,7 +2124,7 @@ def testB15884241(self): if 1: for row in AAAA: self.create(aaaaaaaa="/aaa/bbbb/cccc/dddddd/eeeeeeeeeeeeeeeeeeeeeeeeee/%s" % row [0].replace(".foo", ".bar"), aaaaa=bbb[1], ccccc=bbb[2], dddd=bbb[3], eeeeeeeeeee=[s.strip() for s in bbb[4].split(",")], ffffffff=[s.strip() for s in bbb[5].split(",")], gggggg=bbb[6]) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ if 1: if 1: @@ -2139,7 +2138,7 @@ def testB15884241(self): eeeeeeeeeee=[s.strip() for s in bbb[4].split(",")], ffffffff=[s.strip() for s in bbb[5].split(",")], gggggg=bbb[6]) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -2152,7 +2151,7 @@ def main(unused_argv): bad_slice = map(math.sqrt, an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A]) a_long_name_slicing = an_array_with_an_exceedingly_long_name[:ARBITRARY_CONSTANT_A] bad_slice = ("I am a crazy, no good, string what's too long, etc." + " no really ")[:ARBITRARY_CONSTANT_A] - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def main(unused_argv): ARBITRARY_CONSTANT_A = 10 @@ -2164,36 +2163,36 @@ def main(unused_argv): ARBITRARY_CONSTANT_A] bad_slice = ("I am a crazy, no good, string what's too long, etc." + " no really ")[:ARBITRARY_CONSTANT_A] - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB15597568(self): - unformatted_code = """\ -if True: - if True: - if True: - print(("Return code was %d" + (", and the process timed out." if did_time_out else ".")) % errorcode) -""" # noqa - expected_formatted_code = """\ -if True: - if True: - if True: - print(("Return code was %d" + - (", and the process timed out." if did_time_out else ".")) % - errorcode) -""" + unformatted_code = textwrap.dedent("""\ + if True: + if True: + if True: + print(("Return code was %d" + (", and the process timed out." if did_time_out else ".")) % errorcode) + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + if True: + if True: + if True: + print(("Return code was %d" + + (", and the process timed out." if did_time_out else ".")) % + errorcode) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB15542157(self): unformatted_code = textwrap.dedent("""\ aaaaaaaaaaaa = bbbb.ccccccccccccccc(dddddd.eeeeeeeeeeeeee, ffffffffffffffffff, gggggg.hhhhhhhhhhhhhhhhh) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaaaa = bbbb.ccccccccccccccc(dddddd.eeeeeeeeeeeeee, ffffffffffffffffff, gggggg.hhhhhhhhhhhhhhhhh) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -2213,7 +2212,7 @@ def testB15438132(self): iiiiiiiiiiiiiiiiiii.jjjjjjjjjj.kkkkkkk, lllll.mm), nnnnnnnnnn=ooooooo.pppppppppp) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ if aaaaaaa.bbbbbbbbbb: cccccc.dddddddddd(eeeeeeeeeee=fffffffffffff.gggggggggggggggggg) @@ -2228,22 +2227,22 @@ def testB15438132(self): dddddddddddd=eeeeeeeeeeeeeeeeeee.fffffffffffffffff( gggggg.hh, iiiiiiiiiiiiiiiiiii.jjjjjjjjjj.kkkkkkk, lllll.mm), nnnnnnnnnn=ooooooo.pppppppppp) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB14468247(self): - unformatted_code = """\ -call(a=1, - b=2, -) -""" - expected_formatted_code = """\ -call( - a=1, - b=2, -) -""" + unformatted_code = textwrap.dedent("""\ + call(a=1, + b=2, + ) + """) + expected_formatted_code = textwrap.dedent("""\ + call( + a=1, + b=2, + ) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -2251,12 +2250,12 @@ def testB14406499(self): unformatted_code = textwrap.dedent("""\ def foo1(parameter_1, parameter_2, parameter_3, parameter_4, \ parameter_5, parameter_6): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ def foo1(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6): pass - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -2264,11 +2263,11 @@ def testB13900309(self): unformatted_code = textwrap.dedent("""\ self.aaaaaaaaaaa( # A comment in the middle of it all. 948.0/3600, self.bbb.ccccccccccccccccccccc(dddddddddddddddd.eeee, True)) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ self.aaaaaaaaaaa( # A comment in the middle of it all. 948.0 / 3600, self.bbb.ccccccccccccccccccccc(dddddddddddddddd.eeee, True)) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -2277,49 +2276,49 @@ def testB13900309(self): DC_1, (CL - 50, CL), AAAAAAAA, BBBBBBBBBBBBBBBB, 98.0, CCCCCCC).ddddddddd( # Look! A comment is here. AAAAAAAA - (20 * 60 - 5)) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc().dddddddddddddddddddddddddd(1, 2, 3, 4) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc( ).dddddddddddddddddddddddddd(1, 2, 3, 4) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc(x).dddddddddddddddddddddddddd(1, 2, 3, 4) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccccccccccccccccccccc( x).dddddddddddddddddddddddddd(1, 2, 3, 4) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx).dddddddddddddddddddddddddd(1, 2, 3, 4) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa( xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx).dddddddddddddddddddddddddd(1, 2, 3, 4) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa().bbbbbbbbbbbbbbbbbbbbbbbb().ccccccccccccccccccc().\ dddddddddddddddddd().eeeeeeeeeeeeeeeeeeeee().fffffffffffffffff().gggggggggggggggggg() - """) + """) expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaaaaaaaaaaaaaaaa().bbbbbbbbbbbbbbbbbbbbbbbb().ccccccccccccccccccc( ).dddddddddddddddddd().eeeeeeeeeeeeeeeeeeeee().fffffffffffffffff( ).gggggggggggggggggg() - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -2337,11 +2336,11 @@ def testB67935687(self): expand_text % { 'creator': creator }) - """) + """) expected_formatted_code = textwrap.dedent("""\ shelf_renderer.expand_text = text.translate_to_unicode(expand_text % {'creator': creator}) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) diff --git a/yapftests/reformatter_facebook_test.py b/yapftests/reformatter_facebook_test.py index c61f32bf5..dfb87d378 100644 --- a/yapftests/reformatter_facebook_test.py +++ b/yapftests/reformatter_facebook_test.py @@ -33,11 +33,11 @@ def testNoNeedForLineBreaks(self): def overly_long_function_name( just_one_arg, **kwargs): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ def overly_long_function_name(just_one_arg, **kwargs): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -47,13 +47,13 @@ def overly_long_function_name( first_argument_on_the_same_line, second_argument_makes_the_line_too_long): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ def overly_long_function_name( first_argument_on_the_same_line, second_argument_makes_the_line_too_long ): pass - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -62,14 +62,13 @@ def testBreakAfterOpeningBracketIfContentsTooBig(self): def overly_long_function_name(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ def overly_long_function_name( - a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, \ -v, w, x, y, z + a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z ): pass - """) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -81,7 +80,7 @@ def overly_long_function_name( # comment about the second argument second_argument_makes_the_line_too_long): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ def overly_long_function_name( # comment about the first argument @@ -90,7 +89,7 @@ def overly_long_function_name( second_argument_makes_the_line_too_long ): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -102,7 +101,7 @@ def testDedentImportAsNames(self): SOME_CONSTANT_NUMBER2, SOME_CONSTANT_NUMBER3, ) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -121,7 +120,7 @@ def testDedentTestListGexp(self): IOError, OSError, LookupError, RuntimeError, OverflowError, ) as exception: pass - """) + """) expected_formatted_code = textwrap.dedent("""\ try: pass @@ -140,7 +139,7 @@ def testDedentTestListGexp(self): OverflowError, ) as exception: pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -151,7 +150,7 @@ def testBrokenIdempotency(self): pass except (IOError, OSError, LookupError, RuntimeError, OverflowError) as exception: pass - """) # noqa + """) # noqa pass1_code = textwrap.dedent("""\ try: pass @@ -159,7 +158,7 @@ def testBrokenIdempotency(self): IOError, OSError, LookupError, RuntimeError, OverflowError ) as exception: pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(pass0_code) self.assertCodeEqual(pass1_code, reformatter.Reformat(llines)) @@ -170,7 +169,7 @@ def testBrokenIdempotency(self): IOError, OSError, LookupError, RuntimeError, OverflowError ) as exception: pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(pass1_code) self.assertCodeEqual(pass2_code, reformatter.Reformat(llines)) @@ -183,7 +182,7 @@ def testIfExprHangingIndent(self): self.foobars.counters['db.cheeses'] != 1 or self.foobars.counters['db.marshmellow_skins'] != 1): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ if True: if True: @@ -193,7 +192,7 @@ def testIfExprHangingIndent(self): self.foobars.counters['db.marshmellow_skins'] != 1 ): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -201,13 +200,13 @@ def testSimpleDedenting(self): unformatted_code = textwrap.dedent("""\ if True: self.assertEqual(result.reason_not_added, "current preflight is still running") - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ if True: self.assertEqual( result.reason_not_added, "current preflight is still running" ) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -220,7 +219,7 @@ def baz(cls, clues_list, effect, constraints, constraint_manager): if clues_lists: return cls.single_constraint_not(clues_lists, effect, constraints[0], constraint_manager) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ class Foo: class Bar: @@ -230,7 +229,7 @@ def baz(cls, clues_list, effect, constraints, constraint_manager): return cls.single_constraint_not( clues_lists, effect, constraints[0], constraint_manager ) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -241,7 +240,7 @@ def _(): cls.effect_clues = { 'effect': Clue((cls.effect_time, 'apache_host'), effect_line, 40) } - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -283,7 +282,7 @@ def _pack_results_for_constraint_or(): ('localhost', os.path.join(path, 'node_1.log'), super_parser), ('localhost', os.path.join(path, 'node_2.log'), super_parser) ] - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ class Foo(): def _pack_results_for_constraint_or(): @@ -319,7 +318,7 @@ def _pack_results_for_constraint_or(): ('localhost', os.path.join(path, 'node_1.log'), super_parser), ('localhost', os.path.join(path, 'node_2.log'), super_parser) ] - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -331,7 +330,7 @@ def _(): effect_line_offset, line_content, LineSource('localhost', xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) ) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -345,7 +344,7 @@ def _(): self.foobars.counters['db.marshmellow_skins'] != 1 ): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -361,7 +360,7 @@ def _(): (2, 20, 200), ] ) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -374,7 +373,7 @@ def _pack_results_for_constraint_or(cls, combination, constraints): (clue for clue in combination if not clue == Verifier.UNMATCHED), constraints, InvestigationResult.OR ) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, reformatted_code) @@ -396,7 +395,7 @@ def foo(): print(foo()) - """) + """) expected_formatted_code = textwrap.dedent("""\ def foo(): if 0: @@ -408,22 +407,22 @@ def foo(): print(foo()) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testIfStmtClosingBracket(self): - unformatted_code = """\ -if (isinstance(value , (StopIteration , StopAsyncIteration )) and exc.__cause__ is value_asdfasdfasdfasdfsafsafsafdasfasdfs): - return False -""" # noqa - expected_formatted_code = """\ -if ( - isinstance(value, (StopIteration, StopAsyncIteration)) and - exc.__cause__ is value_asdfasdfasdfasdfsafsafsafdasfasdfs -): - return False -""" + unformatted_code = textwrap.dedent("""\ + if (isinstance(value , (StopIteration , StopAsyncIteration )) and exc.__cause__ is value_asdfasdfasdfasdfsafsafsafdasfasdfs): + return False + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + if ( + isinstance(value, (StopIteration, StopAsyncIteration)) and + exc.__cause__ is value_asdfasdfasdfasdfsafsafsafdasfasdfs + ): + return False + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index b6bf31164..a00e347c1 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -32,11 +32,11 @@ def testIndent4(self): unformatted_code = textwrap.dedent("""\ if a+b: pass - """) + """) expected_formatted_code = textwrap.dedent("""\ if a + b: pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -45,7 +45,7 @@ def testSingleLineIfStatements(self): if True: a = 42 elif False: b = 42 else: c = 42 - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -54,13 +54,13 @@ def testBlankBetweenClassAndDef(self): class Foo: def joe(): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ class Foo: def joe(): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -73,7 +73,7 @@ def run(self): """Override in subclass""" def is_running(self): return self.running - ''') + ''') expected_formatted_code = textwrap.dedent('''\ class TestClass: @@ -85,7 +85,7 @@ def run(self): def is_running(self): return self.running - ''') + ''') llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -93,11 +93,11 @@ def testSingleWhiteBeforeTrailingComment(self): unformatted_code = textwrap.dedent("""\ if a+b: # comment pass - """) + """) expected_formatted_code = textwrap.dedent("""\ if a + b: # comment pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -106,10 +106,10 @@ def testSpaceBetweenEndingCommandAndClosingBracket(self): a = ( 1, ) - """) + """) expected_formatted_code = textwrap.dedent("""\ a = (1, ) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -119,7 +119,7 @@ class eld(d): if str(geom.geom_type).upper( ) != self.geom_type and not self.geom_type == 'GEOMETRY': ror(code='om_type') - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -131,7 +131,7 @@ def f(): zzzzz = '%s-%s'.ww(xxxxxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxx.yyy + 1) zzzzz = '%s-%s' % (xxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxxxxxx + 1) zzzzz = '%s-%s'.ww(xxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxxxxxx + 1) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def f(): if True: @@ -143,7 +143,7 @@ def f(): xxxxxxxxxxxxxxxxxxxxx + 1) zzzzz = '%s-%s'.ww(xxxxxxxxxxxxxxxxxxxxxxx + 1, xxxxxxxxxxxxxxxxxxxxx + 1) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -152,14 +152,14 @@ def testAlignClosingBracketWithVisualIndentation(self): TEST_LIST = ('foo', 'bar', # first comment 'baz' # second comment ) - """) + """) expected_formatted_code = textwrap.dedent("""\ TEST_LIST = ( 'foo', 'bar', # first comment 'baz' # second comment ) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -171,7 +171,7 @@ def g(): xxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb' ): pass - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def f(): @@ -180,7 +180,7 @@ def g(): and xxxxxxxxxxxxxxxxxxxx( yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): pass - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -188,12 +188,12 @@ def testIndentSizeChanging(self): unformatted_code = textwrap.dedent("""\ if True: runtime_mins = (program_end_time - program_start_time).total_seconds() / 60.0 - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ if True: runtime_mins = (program_end_time - program_start_time).total_seconds() / 60.0 - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -211,7 +211,7 @@ def h(): for connection in itertools.chain(branch.contact, branch.address, morestuff.andmore.andmore.andmore.andmore.andmore.andmore.andmore): dosomething(connection) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ if (aaaaaaaaaaaaaa + bbbbbbbbbbbbbbbb == ccccccccccccccccc and xxxxxxxxxxxxx or yyyyyyyyyyyyyyyyy): @@ -232,7 +232,7 @@ def h(): branch.contact, branch.address, morestuff.andmore.andmore.andmore.andmore.andmore.andmore.andmore): dosomething(connection) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -249,7 +249,7 @@ def foo(): update.message.supergroup_chat_created or update.message.channel_chat_created or update.message.migrate_to_chat_id or update.message.migrate_from_chat_id or update.message.pinned_message) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def foo(): return bool( @@ -262,7 +262,7 @@ def foo(): or update.message.migrate_to_chat_id or update.message.migrate_from_chat_id or update.message.pinned_message) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -274,13 +274,13 @@ def testContiguousListEndingWithComment(self): if True: if True: keys.append(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) # may be unassigned. - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ if True: if True: keys.append( aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) # may be unassigned. - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -292,14 +292,14 @@ def testSplittingBeforeFirstArgument(self): unformatted_code = textwrap.dedent("""\ a_very_long_function_name(long_argument_name_1=1, long_argument_name_2=2, long_argument_name_3=3, long_argument_name_4=4) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ a_very_long_function_name( long_argument_name_1=1, long_argument_name_2=2, long_argument_name_3=3, long_argument_name_4=4) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -310,12 +310,12 @@ def testSplittingExpressionsInsideSubscripts(self): unformatted_code = textwrap.dedent("""\ def foo(): df = df[(df['campaign_status'] == 'LIVE') & (df['action_status'] == 'LIVE')] - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def foo(): df = df[(df['campaign_status'] == 'LIVE') & (df['action_status'] == 'LIVE')] - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -325,7 +325,7 @@ def testSplitListsAndDictSetMakersIfCommaTerminated(self): DJANGO_TEMPLATES_OPTIONS = {"context_processors": [],} x = ["context_processors"] x = ["context_processors",] - """) + """) expected_formatted_code = textwrap.dedent("""\ DJANGO_TEMPLATES_OPTIONS = {"context_processors": []} DJANGO_TEMPLATES_OPTIONS = { @@ -335,7 +335,7 @@ def testSplitListsAndDictSetMakersIfCommaTerminated(self): x = [ "context_processors", ] - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -345,7 +345,7 @@ class a(): def a(): return a( aaaaaaaaaa=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) - """) + """) # noqa expected_formatted_code = textwrap.dedent("""\ class a(): @@ -353,7 +353,7 @@ def a(): return a( aaaaaaaaaa=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ) - """) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -363,13 +363,13 @@ def testUnaryOperator(self): pass if -3 < x < 3: pass - """) + """) expected_formatted_code = textwrap.dedent("""\ if not -3 < x < 3: pass if -3 < x < 3: pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -389,7 +389,7 @@ def testNoSplitBeforeDictValue(self): 'description': _("Lorem ipsum dolor met sit amet elit, si vis pacem para bellum " "elites nihi very long string."), } - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ some_dict = { 'title': _("I am example data"), @@ -398,21 +398,21 @@ def testNoSplitBeforeDictValue(self): "elites nihi very long string." ), } - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ X = {'a': 1, 'b': 2, 'key': this_is_a_function_call_that_goes_over_the_column_limit_im_pretty_sure()} - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ X = { 'a': 1, 'b': 2, 'key': this_is_a_function_call_that_goes_over_the_column_limit_im_pretty_sure() } - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -422,7 +422,7 @@ def testNoSplitBeforeDictValue(self): 'category': category, 'role': forms.ModelChoiceField(label=_("Role"), required=False, queryset=category_roles, initial=selected_role, empty_label=_("No access"),), } - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ attrs = { 'category': category, @@ -434,7 +434,7 @@ def testNoSplitBeforeDictValue(self): empty_label=_("No access"), ), } - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -445,7 +445,7 @@ def testNoSplitBeforeDictValue(self): required=False, help_text=_("Optional CSS class used to customize this category appearance from templates."), ) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ css_class = forms.CharField( label=_("CSS class"), @@ -454,7 +454,7 @@ def testNoSplitBeforeDictValue(self): "Optional CSS class used to customize this category appearance from templates." ), ) - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -462,59 +462,59 @@ def testNoSplitBeforeDictValue(self): style.SetGlobalStyle(style.CreatePEP8Style()) def testBitwiseOperandSplitting(self): - unformatted_code = """\ -def _(): - include_values = np.where( - (cdffile['Quality_Flag'][:] >= 5) & ( - cdffile['Day_Night_Flag'][:] == 1) & ( - cdffile['Longitude'][:] >= select_lon - radius) & ( - cdffile['Longitude'][:] <= select_lon + radius) & ( - cdffile['Latitude'][:] >= select_lat - radius) & ( - cdffile['Latitude'][:] <= select_lat + radius)) -""" - expected_code = """\ -def _(): - include_values = np.where( - (cdffile['Quality_Flag'][:] >= 5) & (cdffile['Day_Night_Flag'][:] == 1) - & (cdffile['Longitude'][:] >= select_lon - radius) - & (cdffile['Longitude'][:] <= select_lon + radius) - & (cdffile['Latitude'][:] >= select_lat - radius) - & (cdffile['Latitude'][:] <= select_lat + radius)) -""" + unformatted_code = textwrap.dedent("""\ + def _(): + include_values = np.where( + (cdffile['Quality_Flag'][:] >= 5) & ( + cdffile['Day_Night_Flag'][:] == 1) & ( + cdffile['Longitude'][:] >= select_lon - radius) & ( + cdffile['Longitude'][:] <= select_lon + radius) & ( + cdffile['Latitude'][:] >= select_lat - radius) & ( + cdffile['Latitude'][:] <= select_lat + radius)) + """) # noqa + expected_code = textwrap.dedent("""\ + def _(): + include_values = np.where( + (cdffile['Quality_Flag'][:] >= 5) & (cdffile['Day_Night_Flag'][:] == 1) + & (cdffile['Longitude'][:] >= select_lon - radius) + & (cdffile['Longitude'][:] <= select_lon + radius) + & (cdffile['Latitude'][:] >= select_lat - radius) + & (cdffile['Latitude'][:] <= select_lat + radius)) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertEqual(expected_code, reformatter.Reformat(llines)) def testNoBlankLinesOnlyForFirstNestedObject(self): - unformatted_code = '''\ -class Demo: - """ - Demo docs - """ - def foo(self): - """ - foo docs - """ - def bar(self): - """ - bar docs - """ -''' - expected_code = '''\ -class Demo: - """ - Demo docs - """ - - def foo(self): - """ - foo docs - """ - - def bar(self): - """ - bar docs - """ -''' + unformatted_code = textwrap.dedent('''\ + class Demo: + """ + Demo docs + """ + def foo(self): + """ + foo docs + """ + def bar(self): + """ + bar docs + """ + ''') + expected_code = textwrap.dedent('''\ + class Demo: + """ + Demo docs + """ + + def foo(self): + """ + foo docs + """ + + def bar(self): + """ + bar docs + """ + ''') llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertEqual(expected_code, reformatter.Reformat(llines)) @@ -524,15 +524,15 @@ def testSplitBeforeArithmeticOperators(self): style.CreateStyleFromConfig( '{based_on_style: pep8, split_before_arithmetic_operator: true}')) - unformatted_code = """\ -def _(): - raise ValueError('This is a long message that ends with an argument: ' + str(42)) -""" # noqa - expected_formatted_code = """\ -def _(): - raise ValueError('This is a long message that ends with an argument: ' - + str(42)) -""" + unformatted_code = textwrap.dedent("""\ + def _(): + raise ValueError('This is a long message that ends with an argument: ' + str(42)) + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + def _(): + raise ValueError('This is a long message that ends with an argument: ' + + str(42)) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -540,16 +540,16 @@ def _(): style.SetGlobalStyle(style.CreatePEP8Style()) def testListSplitting(self): - unformatted_code = """\ -foo([(1,1), (1,1), (1,1), (1,1), (1,1), (1,1), (1,1), - (1,1), (1,1), (1,1), (1,1), (1,1), (1,1), (1,1), - (1,10), (1,11), (1, 10), (1,11), (10,11)]) -""" - expected_code = """\ -foo([(1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), - (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 10), (1, 11), (1, 10), - (1, 11), (10, 11)]) -""" + unformatted_code = textwrap.dedent("""\ + foo([(1,1), (1,1), (1,1), (1,1), (1,1), (1,1), (1,1), + (1,1), (1,1), (1,1), (1,1), (1,1), (1,1), (1,1), + (1,10), (1,11), (1, 10), (1,11), (10,11)]) + """) + expected_code = textwrap.dedent("""\ + foo([(1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), + (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 10), (1, 11), (1, 10), + (1, 11), (10, 11)]) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) @@ -560,34 +560,34 @@ def testNoBlankLineBeforeNestedFuncOrClass(self): '{based_on_style: pep8, ' 'blank_line_before_nested_class_or_def: false}')) - unformatted_code = '''\ -def normal_function(): - """Return the nested function.""" + unformatted_code = textwrap.dedent('''\ + def normal_function(): + """Return the nested function.""" - def nested_function(): - """Do nothing just nest within.""" + def nested_function(): + """Do nothing just nest within.""" - @nested(klass) - class nested_class(): - pass + @nested(klass) + class nested_class(): + pass - pass - - return nested_function -''' - expected_formatted_code = '''\ -def normal_function(): - """Return the nested function.""" - def nested_function(): - """Do nothing just nest within.""" - @nested(klass) - class nested_class(): - pass + pass + + return nested_function + ''') + expected_formatted_code = textwrap.dedent('''\ + def normal_function(): + """Return the nested function.""" + def nested_function(): + """Do nothing just nest within.""" + @nested(klass) + class nested_class(): + pass - pass + pass - return nested_function -''' + return nested_function + ''') llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -596,29 +596,29 @@ class nested_class(): def testParamListIndentationCollision1(self): unformatted_code = textwrap.dedent("""\ -class _(): - - def __init__(self, title: Optional[str], diffs: Collection[BinaryDiff] = (), charset: Union[Type[AsciiCharset], Type[LineCharset]] = AsciiCharset, preprocess: Callable[[str], str] = identity, - # TODO(somebody): Make this a Literal type. - justify: str = 'rjust'): - self._cs = charset - self._preprocess = preprocess - """) # noqa + class _(): + + def __init__(self, title: Optional[str], diffs: Collection[BinaryDiff] = (), charset: Union[Type[AsciiCharset], Type[LineCharset]] = AsciiCharset, preprocess: Callable[[str], str] = identity, + # TODO(somebody): Make this a Literal type. + justify: str = 'rjust'): + self._cs = charset + self._preprocess = preprocess + """) # noqa expected_formatted_code = textwrap.dedent("""\ -class _(): - - def __init__( - self, - title: Optional[str], - diffs: Collection[BinaryDiff] = (), - charset: Union[Type[AsciiCharset], - Type[LineCharset]] = AsciiCharset, - preprocess: Callable[[str], str] = identity, - # TODO(somebody): Make this a Literal type. - justify: str = 'rjust'): - self._cs = charset - self._preprocess = preprocess - """) + class _(): + + def __init__( + self, + title: Optional[str], + diffs: Collection[BinaryDiff] = (), + charset: Union[Type[AsciiCharset], + Type[LineCharset]] = AsciiCharset, + preprocess: Callable[[str], str] = identity, + # TODO(somebody): Make this a Literal type. + justify: str = 'rjust'): + self._cs = charset + self._preprocess = preprocess + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -627,7 +627,7 @@ def testParamListIndentationCollision2(self): def simple_pass_function_with_an_extremely_long_name_and_some_arguments( argument0, argument1): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -645,7 +645,7 @@ def func2( arg2, ): pass - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -653,13 +653,13 @@ def testTwoWordComparisonOperators(self): unformatted_code = textwrap.dedent("""\ _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl is not ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj) _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl not in {ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj}) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl is not ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj) _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl not in {ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj}) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -668,7 +668,7 @@ def testStableInlinedDictionaryFormatting(self): def _(): url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( value, urllib.urlencode({'action': 'update', 'parameter': value})) - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def _(): url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( @@ -676,7 +676,7 @@ def _(): 'action': 'update', 'parameter': value })) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) reformatted_code = reformatter.Reformat(llines) @@ -690,86 +690,12 @@ def _(): class TestsForSpacesInsideBrackets(yapf_test_helper.YAPFTest): """Test the SPACE_INSIDE_BRACKETS style option.""" unformatted_code = textwrap.dedent("""\ - foo() - foo(1) - foo(1,2) - foo((1,)) - foo((1, 2)) - foo((1, 2,)) - foo(bar['baz'][0]) - set1 = {1, 2, 3} - dict1 = {1: 1, foo: 2, 3: bar} - dict2 = { - 1: 1, - foo: 2, - 3: bar, - } - dict3[3][1][get_index(*args,**kwargs)] - dict4[3][1][get_index(**kwargs)] - x = dict5[4](foo(*args)) - a = list1[:] - b = list2[slice_start:] - c = list3[slice_start:slice_end] - d = list4[slice_start:slice_end:] - e = list5[slice_start:slice_end:slice_step] - # Print gets special handling - print(set2) - compound = ((10+3)/(5-2**(6+x))) - string_idx = "mystring"[3] - """) - - def testEnabled(self): - style.SetGlobalStyle( - style.CreateStyleFromConfig('{space_inside_brackets: True}')) - - expected_formatted_code = textwrap.dedent("""\ - foo() - foo( 1 ) - foo( 1, 2 ) - foo( ( 1, ) ) - foo( ( 1, 2 ) ) - foo( ( - 1, - 2, - ) ) - foo( bar[ 'baz' ][ 0 ] ) - set1 = { 1, 2, 3 } - dict1 = { 1: 1, foo: 2, 3: bar } - dict2 = { - 1: 1, - foo: 2, - 3: bar, - } - dict3[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] - dict4[ 3 ][ 1 ][ get_index( **kwargs ) ] - x = dict5[ 4 ]( foo( *args ) ) - a = list1[ : ] - b = list2[ slice_start: ] - c = list3[ slice_start:slice_end ] - d = list4[ slice_start:slice_end: ] - e = list5[ slice_start:slice_end:slice_step ] - # Print gets special handling - print( set2 ) - compound = ( ( 10 + 3 ) / ( 5 - 2**( 6 + x ) ) ) - string_idx = "mystring"[ 3 ] - """) - - llines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) - self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) - - def testDefault(self): - style.SetGlobalStyle(style.CreatePEP8Style()) - - expected_formatted_code = textwrap.dedent("""\ foo() foo(1) - foo(1, 2) - foo((1, )) + foo(1,2) + foo((1,)) foo((1, 2)) - foo(( - 1, - 2, - )) + foo((1, 2,)) foo(bar['baz'][0]) set1 = {1, 2, 3} dict1 = {1: 1, foo: 2, 3: bar} @@ -778,7 +704,7 @@ def testDefault(self): foo: 2, 3: bar, } - dict3[3][1][get_index(*args, **kwargs)] + dict3[3][1][get_index(*args,**kwargs)] dict4[3][1][get_index(**kwargs)] x = dict5[4](foo(*args)) a = list1[:] @@ -788,9 +714,83 @@ def testDefault(self): e = list5[slice_start:slice_end:slice_step] # Print gets special handling print(set2) - compound = ((10 + 3) / (5 - 2**(6 + x))) + compound = ((10+3)/(5-2**(6+x))) string_idx = "mystring"[3] - """) + """) + + def testEnabled(self): + style.SetGlobalStyle( + style.CreateStyleFromConfig('{space_inside_brackets: True}')) + + expected_formatted_code = textwrap.dedent("""\ + foo() + foo( 1 ) + foo( 1, 2 ) + foo( ( 1, ) ) + foo( ( 1, 2 ) ) + foo( ( + 1, + 2, + ) ) + foo( bar[ 'baz' ][ 0 ] ) + set1 = { 1, 2, 3 } + dict1 = { 1: 1, foo: 2, 3: bar } + dict2 = { + 1: 1, + foo: 2, + 3: bar, + } + dict3[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] + dict4[ 3 ][ 1 ][ get_index( **kwargs ) ] + x = dict5[ 4 ]( foo( *args ) ) + a = list1[ : ] + b = list2[ slice_start: ] + c = list3[ slice_start:slice_end ] + d = list4[ slice_start:slice_end: ] + e = list5[ slice_start:slice_end:slice_step ] + # Print gets special handling + print( set2 ) + compound = ( ( 10 + 3 ) / ( 5 - 2**( 6 + x ) ) ) + string_idx = "mystring"[ 3 ] + """) + + llines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) + + def testDefault(self): + style.SetGlobalStyle(style.CreatePEP8Style()) + + expected_formatted_code = textwrap.dedent("""\ + foo() + foo(1) + foo(1, 2) + foo((1, )) + foo((1, 2)) + foo(( + 1, + 2, + )) + foo(bar['baz'][0]) + set1 = {1, 2, 3} + dict1 = {1: 1, foo: 2, 3: bar} + dict2 = { + 1: 1, + foo: 2, + 3: bar, + } + dict3[3][1][get_index(*args, **kwargs)] + dict4[3][1][get_index(**kwargs)] + x = dict5[4](foo(*args)) + a = list1[:] + b = list2[slice_start:] + c = list3[slice_start:slice_end] + d = list4[slice_start:slice_end:] + e = list5[slice_start:slice_end:slice_step] + # Print gets special handling + print(set2) + compound = ((10 + 3) / (5 - 2**(6 + x))) + string_idx = "mystring"[3] + """) llines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -799,53 +799,51 @@ def testDefault(self): class TestsForSpacesAroundSubscriptColon(yapf_test_helper.YAPFTest): """Test the SPACES_AROUND_SUBSCRIPT_COLON style option.""" unformatted_code = textwrap.dedent("""\ - a = list1[ : ] - b = list2[ slice_start: ] - c = list3[ slice_start:slice_end ] - d = list4[ slice_start:slice_end: ] - e = list5[ slice_start:slice_end:slice_step ] - a1 = list1[ : ] - b1 = list2[ 1: ] - c1 = list3[ 1:20 ] - d1 = list4[ 1:20: ] - e1 = list5[ 1:20:3 ] + a = list1[ : ] + b = list2[ slice_start: ] + c = list3[ slice_start:slice_end ] + d = list4[ slice_start:slice_end: ] + e = list5[ slice_start:slice_end:slice_step ] + a1 = list1[ : ] + b1 = list2[ 1: ] + c1 = list3[ 1:20 ] + d1 = list4[ 1:20: ] + e1 = list5[ 1:20:3 ] """) def testEnabled(self): style.SetGlobalStyle( style.CreateStyleFromConfig('{spaces_around_subscript_colon: True}')) expected_formatted_code = textwrap.dedent("""\ - a = list1[:] - b = list2[slice_start :] - c = list3[slice_start : slice_end] - d = list4[slice_start : slice_end :] - e = list5[slice_start : slice_end : slice_step] - a1 = list1[:] - b1 = list2[1 :] - c1 = list3[1 : 20] - d1 = list4[1 : 20 :] - e1 = list5[1 : 20 : 3] + a = list1[:] + b = list2[slice_start :] + c = list3[slice_start : slice_end] + d = list4[slice_start : slice_end :] + e = list5[slice_start : slice_end : slice_step] + a1 = list1[:] + b1 = list2[1 :] + c1 = list3[1 : 20] + d1 = list4[1 : 20 :] + e1 = list5[1 : 20 : 3] """) llines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testWithSpaceInsideBrackets(self): style.SetGlobalStyle( - style.CreateStyleFromConfig('{' - 'spaces_around_subscript_colon: true, ' - 'space_inside_brackets: true,' - '}')) + style.CreateStyleFromConfig( + '{spaces_around_subscript_colon: true, space_inside_brackets: true,}')) # noqa expected_formatted_code = textwrap.dedent("""\ - a = list1[ : ] - b = list2[ slice_start : ] - c = list3[ slice_start : slice_end ] - d = list4[ slice_start : slice_end : ] - e = list5[ slice_start : slice_end : slice_step ] - a1 = list1[ : ] - b1 = list2[ 1 : ] - c1 = list3[ 1 : 20 ] - d1 = list4[ 1 : 20 : ] - e1 = list5[ 1 : 20 : 3 ] + a = list1[ : ] + b = list2[ slice_start : ] + c = list3[ slice_start : slice_end ] + d = list4[ slice_start : slice_end : ] + e = list5[ slice_start : slice_end : slice_step ] + a1 = list1[ : ] + b1 = list2[ 1 : ] + c1 = list3[ 1 : 20 ] + d1 = list4[ 1 : 20 : ] + e1 = list5[ 1 : 20 : 3 ] """) llines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -853,16 +851,16 @@ def testWithSpaceInsideBrackets(self): def testDefault(self): style.SetGlobalStyle(style.CreatePEP8Style()) expected_formatted_code = textwrap.dedent("""\ - a = list1[:] - b = list2[slice_start:] - c = list3[slice_start:slice_end] - d = list4[slice_start:slice_end:] - e = list5[slice_start:slice_end:slice_step] - a1 = list1[:] - b1 = list2[1:] - c1 = list3[1:20] - d1 = list4[1:20:] - e1 = list5[1:20:3] + a = list1[:] + b = list2[slice_start:] + c = list3[slice_start:slice_end] + d = list4[slice_start:slice_end:] + e = list5[slice_start:slice_end:slice_step] + a1 = list1[:] + b1 = list2[1:] + c1 = list3[1:20] + d1 = list4[1:20:] + e1 = list5[1:20:3] """) llines = yapf_test_helper.ParseAndUnwrap(self.unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index 17247cd08..b7f0de39f 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -41,7 +41,7 @@ def x(aaaaaaaaaaaaaaa: int, ccccccccccccccc: dict, eeeeeeeeeeeeee: set = {1, 2, 3}) -> bool: pass - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -62,11 +62,11 @@ def testKeywordOnlyArgSpecifier(self): unformatted_code = textwrap.dedent("""\ def foo(a, *, kw): return a+kw - """) # noqa + """) expected_formatted_code = textwrap.dedent("""\ def foo(a, *, kw): return a + kw - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -74,11 +74,11 @@ def testAnnotations(self): unformatted_code = textwrap.dedent("""\ def foo(a: list, b: "bar") -> dict: return a+b - """) # noqa + """) expected_formatted_code = textwrap.dedent("""\ def foo(a: list, b: "bar") -> dict: return a + b - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -104,17 +104,17 @@ async def main(): start = time.time() if (await get_html()): pass - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines, verify=False)) def testNoSpacesAroundPowerOperator(self): unformatted_code = textwrap.dedent("""\ a**b - """) # noqa + """) expected_formatted_code = textwrap.dedent("""\ a ** b - """) # noqa + """) try: style.SetGlobalStyle( @@ -130,10 +130,10 @@ def testNoSpacesAroundPowerOperator(self): def testSpacesAroundDefaultOrNamedAssign(self): unformatted_code = textwrap.dedent("""\ f(a=5) - """) # noqa + """) expected_formatted_code = textwrap.dedent("""\ f(a = 5) - """) # noqa + """) try: style.SetGlobalStyle( @@ -155,7 +155,7 @@ def foo(x: int=42): def foo2(x: 'int' =42): pass - """) # noqa + """) expected_formatted_code = textwrap.dedent("""\ def foo(x: int = 42): pass @@ -163,24 +163,24 @@ def foo(x: int = 42): def foo2(x: 'int' = 42): pass - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMatrixMultiplication(self): unformatted_code = textwrap.dedent("""\ a=b@c - """) # noqa + """) expected_formatted_code = textwrap.dedent("""\ a = b @ c - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoneKeyword(self): code = textwrap.dedent("""\ None.__ne__() - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -194,7 +194,7 @@ async def bar(): async def foo(): pass - """) # noqa + """) expected_formatted_code = textwrap.dedent("""\ import asyncio @@ -206,7 +206,7 @@ async def bar(): async def foo(): pass - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -216,7 +216,7 @@ async def outer(): async def inner(): pass - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -232,7 +232,7 @@ def _ReduceAbstractContainers( self, *args: Optional[automation_converter.PyiCollectionAbc] ) -> List[automation_converter.PyiCollectionAbc]: pass - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -242,13 +242,13 @@ async def start_websocket(): async with session.ws_connect( r"ws://a_really_long_long_long_long_long_long_url") as ws: pass - """) # noqa + """) expected_formatted_code = textwrap.dedent("""\ async def start_websocket(): async with session.ws_connect( r"ws://a_really_long_long_long_long_long_long_url") as ws: pass - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -301,7 +301,7 @@ def open_file( def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): pass - """) # noqa + """) try: style.SetGlobalStyle( @@ -329,7 +329,7 @@ def foo(self): **foofoofoo }) - """) # noqa + """) expected_formatted_code = textwrap.dedent("""\ class Foo: @@ -338,7 +338,7 @@ def foo(self): 'foo': 'foo', **foofoofoo }) - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -349,7 +349,7 @@ def testMultilineFormatString(self): (f''' ''') # yapf: enable - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -369,7 +369,7 @@ def _GenerateStatsEntries( timestamp: Optional[ffffffff.FFFFFFFFFFF] = None ) -> Sequence[ssssssssssss.SSSSSSSSSSSSSSS]: pass - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -392,7 +392,7 @@ async def fn(): pass else: pass - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -403,7 +403,7 @@ async def fn(): pass else: pass - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -431,7 +431,7 @@ def testTypeHintedYieldExpression(self): code = textwrap.dedent("""\ def my_coroutine(): x: int = yield - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -446,7 +446,7 @@ def testSyntaxMatch(self): b=1 case _ : b=2 - """) # noqa + """) expected_formatted_code = textwrap.dedent("""\ a = 3 b = 0 @@ -455,7 +455,7 @@ def testSyntaxMatch(self): b = 1 case _: b = 2 - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -466,12 +466,12 @@ def test_copy_dimension(self): with (Dataset() as target_ds, Dataset() as source_ds): do_something - """) # noqa + """) expected_formatted_code = textwrap.dedent("""\ def test_copy_dimension(self): with (Dataset() as target_ds, Dataset() as source_ds): do_something - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -483,13 +483,13 @@ def a(): t = (2,3) for i in range(5): yield i,*t - """) # noqa + """) expected_formatted_code = textwrap.dedent("""\ def a(): t = (2, 3) for i in range(5): yield i, *t - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -499,7 +499,7 @@ def testTypedTuple(self): code = textwrap.dedent("""\ t: tuple = 1, 2 args = tuple(x for x in [2], ) - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -510,14 +510,14 @@ def testWalrusOperator(self): a=[1,2,3,4] if (n:=len(a))>2: print() - """) # noqa + """) expected_formatted_code = textwrap.dedent("""\ import os a = [1, 2, 3, 4] if (n := len(a)) > 2: print() - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -535,7 +535,7 @@ def json(self) -> JSONTask: if x := getattr(self , i): result[i] = x # type: ignore return result - """) # noqa + """) expected_formatted_code = textwrap.dedent("""\ def json(self) -> JSONTask: result: JSONTask = { @@ -548,7 +548,7 @@ def json(self) -> JSONTask: if x := getattr(self, i): result[i] = x # type: ignore return result - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -560,7 +560,7 @@ def testCopyDictionary(self): a_dict_copy = {**a_dict} print('a_dict:', a_dict) print('a_dict_copy:', a_dict_copy) - """) # noqa + """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) diff --git a/yapftests/reformatter_style_config_test.py b/yapftests/reformatter_style_config_test.py index befd27b9e..6458a0afd 100644 --- a/yapftests/reformatter_style_config_test.py +++ b/yapftests/reformatter_style_config_test.py @@ -33,11 +33,11 @@ def testSetGlobalStyle(self): unformatted_code = textwrap.dedent("""\ for i in range(5): print('bar') - """) + """) expected_formatted_code = textwrap.dedent("""\ for i in range(5): print('bar') - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -48,11 +48,11 @@ def testSetGlobalStyle(self): unformatted_code = textwrap.dedent("""\ for i in range(5): print('bar') - """) + """) expected_formatted_code = textwrap.dedent("""\ for i in range(5): print('bar') - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) @@ -65,11 +65,11 @@ def testOperatorNoSpaceStyle(self): unformatted_code = textwrap.dedent("""\ a = 1+2 * 3 - 4 / 5 b = '0' * 1 - """) + """) expected_formatted_code = textwrap.dedent("""\ a = 1 + 2*3 - 4/5 b = '0'*1 - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, @@ -97,7 +97,7 @@ def testOperatorPrecedenceStyle(self): i = 1 * 2 / 3 * 4 j = (1 * 2 - 3) + 4 k = (1 * 2 * 3) + (4 * 5 * 6 * 7 * 8) - """) + """) expected_formatted_code = textwrap.dedent("""\ 1 + 2 (1+2) * (3 - (4/5)) @@ -112,7 +112,7 @@ def testOperatorPrecedenceStyle(self): i = 1 * 2 / 3 * 4 j = (1*2 - 3) + 4 k = (1*2*3) + (4*5*6*7*8) - """) + """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, @@ -155,7 +155,7 @@ def testNoSplitBeforeFirstArgumentStyle1(self): plt.plot(veryverylongvariablename, veryverylongvariablename, marker="x", color="r") - """) # noqa + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(formatted_code) self.assertCodeEqual(formatted_code, reformatter.Reformat(llines)) finally: @@ -186,7 +186,7 @@ def testNoSplitBeforeFirstArgumentStyle2(self): veryverylongvariablename, marker="x", color="r") - """) + """) llines = yapf_test_helper.ParseAndUnwrap(formatted_code) self.assertCodeEqual(formatted_code, reformatter.Reformat(llines)) finally: diff --git a/yapftests/split_penalty_test.py b/yapftests/split_penalty_test.py index 5f9a2189f..dd5d0598e 100644 --- a/yapftests/split_penalty_test.py +++ b/yapftests/split_penalty_test.py @@ -80,10 +80,10 @@ def FlattenRec(tree): def testUnbreakable(self): # Test function definitions. - code = textwrap.dedent(r""" - def foo(x): - pass - """) + code = textwrap.dedent("""\ + def foo(x): + pass + """) tree = self._ParseAndComputePenalties(code) self._CheckPenalties(tree, [ ('def', None), @@ -96,10 +96,10 @@ def foo(x): ]) # Test function definition with trailing comment. - code = textwrap.dedent(r""" - def foo(x): # trailing comment - pass - """) + code = textwrap.dedent("""\ + def foo(x): # trailing comment + pass + """) tree = self._ParseAndComputePenalties(code) self._CheckPenalties(tree, [ ('def', None), @@ -112,12 +112,12 @@ def foo(x): # trailing comment ]) # Test class definitions. - code = textwrap.dedent(r""" - class A: - pass - class B(A): - pass - """) + code = textwrap.dedent("""\ + class A: + pass + class B(A): + pass + """) tree = self._ParseAndComputePenalties(code) self._CheckPenalties(tree, [ ('class', None), @@ -134,9 +134,9 @@ class B(A): ]) # Test lambda definitions. - code = textwrap.dedent(r""" - lambda a, b: None - """) + code = textwrap.dedent("""\ + lambda a, b: None + """) tree = self._ParseAndComputePenalties(code) self._CheckPenalties(tree, [ ('lambda', None), @@ -148,9 +148,9 @@ class B(A): ]) # Test dotted names. - code = textwrap.dedent(r""" - import a.b.c - """) + code = textwrap.dedent("""\ + import a.b.c + """) tree = self._ParseAndComputePenalties(code) self._CheckPenalties(tree, [ ('import', None), @@ -163,12 +163,12 @@ class B(A): def testStronglyConnected(self): # Test dictionary keys. - code = textwrap.dedent(r""" - a = { - 'x': 42, - y(lambda a: 23): 37, - } - """) + code = textwrap.dedent("""\ + a = { + 'x': 42, + y(lambda a: 23): 37, + } + """) tree = self._ParseAndComputePenalties(code) self._CheckPenalties(tree, [ ('a', None), @@ -192,9 +192,9 @@ def testStronglyConnected(self): ]) # Test list comprehension. - code = textwrap.dedent(r""" - [a for a in foo if a.x == 37] - """) + code = textwrap.dedent("""\ + [a for a in foo if a.x == 37] + """) tree = self._ParseAndComputePenalties(code) self._CheckPenalties(tree, [ ('[', None), @@ -213,7 +213,9 @@ def testStronglyConnected(self): ]) def testFuncCalls(self): - code = 'foo(1, 2, 3)\n' + code = textwrap.dedent("""\ + foo(1, 2, 3) + """) tree = self._ParseAndComputePenalties(code) self._CheckPenalties(tree, [ ('foo', None), @@ -227,7 +229,9 @@ def testFuncCalls(self): ]) # Now a method call, which has more than one trailer - code = 'foo.bar.baz(1, 2, 3)\n' + code = textwrap.dedent("""\ + foo.bar.baz(1, 2, 3) + """) tree = self._ParseAndComputePenalties(code) self._CheckPenalties(tree, [ ('foo', None), @@ -245,7 +249,9 @@ def testFuncCalls(self): ]) # Test single generator argument. - code = 'max(i for i in xrange(10))\n' + code = textwrap.dedent("""\ + max(i for i in xrange(10)) + """) tree = self._ParseAndComputePenalties(code) self._CheckPenalties(tree, [ ('max', None), diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 12db72383..10c62edc6 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -136,55 +136,55 @@ def tearDownClass(cls): # pylint: disable=g-missing-super-call shutil.rmtree(cls.test_tmpdir) def testDefaultBasedOnStyle(self): - cfg = textwrap.dedent('''\ + cfg = textwrap.dedent("""\ [style] continuation_indent_width = 20 - ''') + """) with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikePEP8Style(cfg)) self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) def testDefaultBasedOnPEP8Style(self): - cfg = textwrap.dedent('''\ + cfg = textwrap.dedent("""\ [style] based_on_style = pep8 continuation_indent_width = 40 - ''') + """) with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikePEP8Style(cfg)) self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 40) def testDefaultBasedOnGoogleStyle(self): - cfg = textwrap.dedent('''\ + cfg = textwrap.dedent("""\ [style] based_on_style = google continuation_indent_width = 20 - ''') + """) with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikeGoogleStyle(cfg)) self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) def testDefaultBasedOnFacebookStyle(self): - cfg = textwrap.dedent('''\ + cfg = textwrap.dedent("""\ [style] based_on_style = facebook continuation_indent_width = 20 - ''') + """) with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikeFacebookStyle(cfg)) self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) def testBoolOptionValue(self): - cfg = textwrap.dedent('''\ + cfg = textwrap.dedent("""\ [style] based_on_style = pep8 SPLIT_BEFORE_NAMED_ASSIGNS=False split_before_logical_operator = true - ''') + """) with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikePEP8Style(cfg)) @@ -192,11 +192,11 @@ def testBoolOptionValue(self): self.assertEqual(cfg['SPLIT_BEFORE_LOGICAL_OPERATOR'], True) def testStringListOptionValue(self): - cfg = textwrap.dedent('''\ + cfg = textwrap.dedent("""\ [style] based_on_style = pep8 I18N_FUNCTION_CALL = N_, V_, T_ - ''') + """) with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikePEP8Style(cfg)) @@ -208,21 +208,21 @@ def testErrorNoStyleFile(self): style.CreateStyleFromConfig('/8822/xyznosuchfile') def testErrorNoStyleSection(self): - cfg = textwrap.dedent('''\ + cfg = textwrap.dedent("""\ [s] indent_width=2 - ''') + """) with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: with self.assertRaisesRegex(style.StyleConfigError, 'Unable to find section'): style.CreateStyleFromConfig(filepath) def testErrorUnknownStyleOption(self): - cfg = textwrap.dedent('''\ + cfg = textwrap.dedent("""\ [style] indent_width=2 hummus=2 - ''') + """) with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: with self.assertRaisesRegex(style.StyleConfigError, 'Unknown style option'): @@ -246,11 +246,11 @@ def testPyprojectTomlParseYapfSection(self): except ImportError: return - cfg = textwrap.dedent('''\ + cfg = textwrap.dedent("""\ [tool.yapf] based_on_style = "pep8" continuation_indent_width = 40 - ''') + """) filepath = os.path.join(self.test_tmpdir, 'pyproject.toml') with open(filepath, 'w') as f: f.write(cfg) @@ -300,8 +300,8 @@ def testDefaultBasedOnStyle(self): def testDefaultBasedOnStyleNotStrict(self): cfg = style.CreateStyleFromConfig( - '{based_on_style : pep8' - ' ,indent_width=2' + '{based_on_style : pep8,' + ' indent_width=2' ' blank_line_before_nested_class_or_def:True}') self.assertTrue(_LooksLikePEP8Style(cfg)) self.assertEqual(cfg['INDENT_WIDTH'], 2) diff --git a/yapftests/subtype_assigner_test.py b/yapftests/subtype_assigner_test.py index 3e632aa4f..01b371051 100644 --- a/yapftests/subtype_assigner_test.py +++ b/yapftests/subtype_assigner_test.py @@ -45,10 +45,10 @@ def _CheckFormatTokenSubtypes(self, llines, list_of_expected): def testFuncDefDefaultAssign(self): self.maxDiff = None # pylint: disable=invalid-name - code = textwrap.dedent(r""" + code = textwrap.dedent("""\ def foo(a=37, *b, **c): return -x[:42] - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(llines, [ [ @@ -106,9 +106,9 @@ def foo(a=37, *b, **c): ]) def testFuncCallWithDefaultAssign(self): - code = textwrap.dedent(r""" + code = textwrap.dedent("""\ foo(x, a='hello world') - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(llines, [ [ @@ -133,7 +133,7 @@ def testSetComprehension(self): code = textwrap.dedent("""\ def foo(value): return {value.lower()} - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(llines, [ [ @@ -163,7 +163,7 @@ def foo(value): code = textwrap.dedent("""\ def foo(strs): return {s.lower() for s in strs} - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(llines, [ [ @@ -200,7 +200,7 @@ def foo(strs): code = textwrap.dedent("""\ def foo(strs): return {s + s.lower() for s in strs} - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(llines, [ [ @@ -239,7 +239,7 @@ def foo(strs): code = textwrap.dedent("""\ def foo(strs): return {c.lower() for s in strs for c in s} - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(llines, [ [ @@ -285,7 +285,7 @@ def testDictComprehension(self): code = textwrap.dedent("""\ def foo(value): return {value: value.lower()} - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(llines, [ [ @@ -317,7 +317,7 @@ def foo(value): code = textwrap.dedent("""\ def foo(strs): return {s: s.lower() for s in strs} - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(llines, [ [ @@ -359,7 +359,7 @@ def foo(strs): code = textwrap.dedent("""\ def foo(strs): return {c: c.lower() for s in strs for c in s} - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(llines, [ [ @@ -409,7 +409,7 @@ def foo(strs): def testUnaryNotOperator(self): code = textwrap.dedent("""\ not a - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(llines, [[('not', {subtypes.UNARY_OPERATOR}), ('a', {subtypes.NONE})]]) @@ -446,7 +446,7 @@ def testBitwiseOperators(self): def testArithmeticOperators(self): code = textwrap.dedent("""\ x = ((a + (b - 3) * (1 % c) @ d) / 3) // 1 - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(llines, [ [ @@ -487,7 +487,7 @@ def testArithmeticOperators(self): def testSubscriptColon(self): code = textwrap.dedent("""\ x[0:42:1] - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(llines, [ [ @@ -505,7 +505,7 @@ def testSubscriptColon(self): def testFunctionCallWithStarExpression(self): code = textwrap.dedent("""\ [a, *b] - """) + """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(llines, [ [ diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 8a31623e1..04727e925 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -50,7 +50,7 @@ def _Check(self, unformatted_code, expected_formatted_code): def testSimple(self): unformatted_code = textwrap.dedent("""\ print('foo') - """) + """) self._Check(unformatted_code, unformatted_code) def testNoEndingNewline(self): @@ -60,11 +60,11 @@ def testNoEndingNewline(self): expected_formatted_code = textwrap.dedent("""\ if True: pass - """) + """) self._Check(unformatted_code, expected_formatted_code) -class FormatFileTest(unittest.TestCase): +class FormatFileTest(yapf_test_helper.YAPFTest): def setUp(self): # pylint: disable=g-missing-super-call self.test_tmpdir = tempfile.mkdtemp() @@ -72,29 +72,19 @@ def setUp(self): # pylint: disable=g-missing-super-call def tearDown(self): # pylint: disable=g-missing-super-call shutil.rmtree(self.test_tmpdir) - def assertCodeEqual(self, expected_code, code): - if code != expected_code: - msg = 'Code format mismatch:\n' - msg += 'Expected:\n >' - msg += '\n > '.join(expected_code.splitlines()) - msg += '\nActual:\n >' - msg += '\n > '.join(code.splitlines()) - # TODO(sbc): maybe using difflib here to produce easy to read deltas? - self.fail(msg) - def testFormatFile(self): unformatted_code = textwrap.dedent("""\ if True: pass - """) + """) expected_formatted_code_pep8 = textwrap.dedent("""\ if True: pass - """) + """) expected_formatted_code_yapf = textwrap.dedent("""\ if True: pass - """) + """) with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(expected_formatted_code_pep8, formatted_code) @@ -110,7 +100,7 @@ def testDisableLinesPattern(self): if f: g if h: i - """) + """) expected_formatted_code = textwrap.dedent("""\ if a: b @@ -118,7 +108,7 @@ def testDisableLinesPattern(self): if f: g if h: i - """) + """) with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(expected_formatted_code, formatted_code) @@ -132,7 +122,7 @@ def testDisableAndReenableLinesPattern(self): # yapf: enable if h: i - """) + """) expected_formatted_code = textwrap.dedent("""\ if a: b @@ -141,7 +131,7 @@ def testDisableAndReenableLinesPattern(self): # yapf: enable if h: i - """) + """) with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(expected_formatted_code, formatted_code) @@ -155,7 +145,7 @@ def testFmtOnOff(self): # fmt: on if h: i - """) + """) expected_formatted_code = textwrap.dedent("""\ if a: b @@ -164,7 +154,7 @@ def testFmtOnOff(self): # fmt: on if h: i - """) + """) with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(expected_formatted_code, formatted_code) @@ -180,8 +170,7 @@ def testDisablePartOfMultilineComment(self): # This is a multiline comment that enables YAPF. if h: i - """) - + """) expected_formatted_code = textwrap.dedent("""\ if a: b @@ -192,7 +181,7 @@ def testDisablePartOfMultilineComment(self): # This is a multiline comment that enables YAPF. if h: i - """) + """) with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(expected_formatted_code, formatted_code) @@ -208,7 +197,7 @@ def foo_function(): ) # yapf: enable - """) + """) with utils.TempFileContents(self.test_tmpdir, code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(code, formatted_code) @@ -221,7 +210,7 @@ def testEnabledDisabledSameComment(self): # yapf: disable a(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, ccccccccccccccccccccccccccccccc, ddddddddddddddddddddddd, eeeeeeeeeeeeeeeeeeeeeeeeeee) # yapf: enable - """) # noqa + """) # noqa with utils.TempFileContents(self.test_tmpdir, code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(code, formatted_code) @@ -233,21 +222,21 @@ def testFormatFileLinesSelection(self): if f: g if h: i - """) + """) expected_formatted_code_lines1and2 = textwrap.dedent("""\ if a: b if f: g if h: i - """) + """) expected_formatted_code_lines3 = textwrap.dedent("""\ if a: b if f: g if h: i - """) + """) with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: formatted_code, _, _ = yapf_api.FormatFile( filepath, style_config='pep8', lines=[(1, 2)]) @@ -260,7 +249,7 @@ def testFormatFileDiff(self): unformatted_code = textwrap.dedent("""\ if True: pass - """) + """) with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: diff, _, _ = yapf_api.FormatFile(filepath, print_diff=True) self.assertIn('+ pass', diff) @@ -296,7 +285,7 @@ def testCommentsUnformatted(self): 'one', # quark 'two'] # yapf: disable - """) + """) with utils.TempFileContents(self.test_tmpdir, code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(code, formatted_code) @@ -307,7 +296,7 @@ def testDisabledHorizontalFormattingOnNewLine(self): a = [ 1] # yapf: enable - """) + """) with utils.TempFileContents(self.test_tmpdir, code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(code, formatted_code) @@ -317,7 +306,7 @@ def testSplittingSemicolonStatements(self): def f(): x = y + 42 ; z = n * 42 if True: a += 1 ; b += 1; c += 1 - """) + """) expected_formatted_code = textwrap.dedent("""\ def f(): x = y + 42 @@ -326,7 +315,7 @@ def f(): a += 1 b += 1 c += 1 - """) + """) with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(expected_formatted_code, formatted_code) @@ -336,7 +325,7 @@ def testSemicolonStatementsDisabled(self): def f(): x = y + 42 ; z = n * 42 # yapf: disable if True: a += 1 ; b += 1; c += 1 - """) + """) expected_formatted_code = textwrap.dedent("""\ def f(): x = y + 42 ; z = n * 42 # yapf: disable @@ -344,7 +333,7 @@ def f(): a += 1 b += 1 c += 1 - """) + """) with utils.TempFileContents(self.test_tmpdir, unformatted_code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(expected_formatted_code, formatted_code) @@ -353,7 +342,7 @@ def testDisabledSemiColonSeparatedStatements(self): code = textwrap.dedent("""\ # yapf: disable if True: a ; b - """) + """) with utils.TempFileContents(self.test_tmpdir, code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='pep8') self.assertCodeEqual(code, formatted_code) @@ -372,7 +361,7 @@ def testDisabledMultilineStringInDictionary(self): ''', }, ] - """) + """) with utils.TempFileContents(self.test_tmpdir, code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='yapf') self.assertCodeEqual(code, formatted_code) @@ -391,7 +380,7 @@ def testDisabledWithPrecedingText(self): ''', }, ] - """) + """) with utils.TempFileContents(self.test_tmpdir, code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='yapf') self.assertCodeEqual(code, formatted_code) @@ -446,11 +435,11 @@ def testInPlaceReformatting(self): unformatted_code = textwrap.dedent("""\ def foo(): x = 37 - """) + """) expected_formatted_code = textwrap.dedent("""\ def foo(): x = 37 - """) + """) with utils.TempFileContents( self.test_tmpdir, unformatted_code, suffix='.py') as filepath: p = subprocess.Popen(YAPF_BINARY + ['--in-place', filepath]) @@ -486,7 +475,7 @@ def testInPlaceReformattingNoNewLine(self): expected_formatted_code = textwrap.dedent("""\ def foo(): x = 37 - """) + """) with utils.TempFileContents( self.test_tmpdir, unformatted_code, suffix='.py') as filepath: p = subprocess.Popen(YAPF_BINARY + ['--in-place', filepath]) @@ -520,31 +509,31 @@ def testReadFromStdin(self): unformatted_code = textwrap.dedent("""\ def foo(): x = 37 - """) + """) expected_formatted_code = textwrap.dedent("""\ def foo(): x = 37 - """) + """) self.assertYapfReformats(unformatted_code, expected_formatted_code) def testReadFromStdinWithEscapedStrings(self): unformatted_code = textwrap.dedent("""\ s = "foo\\nbar" - """) + """) expected_formatted_code = textwrap.dedent("""\ s = "foo\\nbar" - """) + """) self.assertYapfReformats(unformatted_code, expected_formatted_code) def testSetYapfStyle(self): unformatted_code = textwrap.dedent("""\ def foo(): # trail x = 37 - """) + """) expected_formatted_code = textwrap.dedent("""\ def foo(): # trail x = 37 - """) + """) self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -554,16 +543,16 @@ def testSetCustomStyleBasedOnYapf(self): unformatted_code = textwrap.dedent("""\ def foo(): # trail x = 37 - """) + """) expected_formatted_code = textwrap.dedent("""\ def foo(): # trail x = 37 - """) - style_file = textwrap.dedent('''\ + """) + style_file = textwrap.dedent("""\ [style] based_on_style = yapf spaces_before_comment = 4 - ''') + """) with utils.TempFileContents(self.test_tmpdir, style_file) as stylepath: self.assertYapfReformats( unformatted_code, @@ -574,15 +563,15 @@ def testSetCustomStyleSpacesBeforeComment(self): unformatted_code = textwrap.dedent("""\ a_very_long_statement_that_extends_way_beyond # Comment short # This is a shorter statement - """) + """) expected_formatted_code = textwrap.dedent("""\ a_very_long_statement_that_extends_way_beyond # Comment short # This is a shorter statement - """) # noqa - style_file = textwrap.dedent('''\ + """) # noqa + style_file = textwrap.dedent("""\ [style] spaces_before_comment = 15, 20 - ''') + """) with utils.TempFileContents(self.test_tmpdir, style_file) as stylepath: self.assertYapfReformats( unformatted_code, @@ -592,10 +581,10 @@ def testSetCustomStyleSpacesBeforeComment(self): def testReadSingleLineCodeFromStdin(self): unformatted_code = textwrap.dedent("""\ if True: pass - """) + """) expected_formatted_code = textwrap.dedent("""\ if True: pass - """) + """) self.assertYapfReformats(unformatted_code, expected_formatted_code) def testEncodingVerification(self): @@ -604,7 +593,7 @@ def testEncodingVerification(self): # -*- coding: utf-8 -*- def f(): x = 37 - """) + """) with utils.NamedTempFile( suffix='.py', dirname=self.test_tmpdir) as (out, _): @@ -637,7 +626,7 @@ def h(): def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass - """) # noqa + """) # noqa # TODO(ambv): the `expected_formatted_code` here is not PEP8 compliant, # raising "E129 visually indented line with same indent as next logical # line" with flake8. @@ -653,14 +642,14 @@ def testOmitFormattingLinesBeforeDisabledFunctionComment(self): # Comment def some_func(x): x = ["badly" , "formatted","line" ] - """) + """) expected_formatted_code = textwrap.dedent("""\ import sys # Comment def some_func(x): x = ["badly", "formatted", "line"] - """) + """) self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -677,7 +666,7 @@ def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass # yapf: enable - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and @@ -690,7 +679,7 @@ def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass # yapf: enable - """) # noqa + """) # noqa self.assertYapfReformats(unformatted_code, expected_formatted_code) def testReformattingSkippingToEndOfFile(self): @@ -710,7 +699,7 @@ def e(): xxxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): pass - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and @@ -729,7 +718,7 @@ def e(): xxxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): pass - """) # noqa + """) # noqa self.assertYapfReformats(unformatted_code, expected_formatted_code) def testReformattingSkippingSingleLine(self): @@ -741,7 +730,7 @@ def h(): def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): # yapf: disable pass - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and @@ -752,7 +741,7 @@ def h(): def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): # yapf: disable pass - """) # noqa + """) # noqa self.assertYapfReformats(unformatted_code, expected_formatted_code) def testDisableWholeDataStructure(self): @@ -761,13 +750,13 @@ def testDisableWholeDataStructure(self): 'hello', 'world', ]) # yapf: disable - """) + """) expected_formatted_code = textwrap.dedent("""\ A = set([ 'hello', 'world', ]) # yapf: disable - """) + """) self.assertYapfReformats(unformatted_code, expected_formatted_code) def testDisableButAdjustIndentations(self): @@ -777,14 +766,14 @@ class SplitPenaltyTest(unittest.TestCase): def testUnbreakable(self): self._CheckPenalties(tree, [ ]) # yapf: disable - """) + """) expected_formatted_code = textwrap.dedent("""\ class SplitPenaltyTest(unittest.TestCase): def testUnbreakable(self): self._CheckPenalties(tree, [ ]) # yapf: disable - """) + """) self.assertYapfReformats(unformatted_code, expected_formatted_code) def testRetainingHorizontalWhitespace(self): @@ -796,7 +785,7 @@ def h(): def g(): if (xxxxxxxxxxxx.yyyyyyyy (zzzzzzzzzzzzz [0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): # yapf: disable pass - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and @@ -807,7 +796,7 @@ def h(): def g(): if (xxxxxxxxxxxx.yyyyyyyy (zzzzzzzzzzzzz [0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): # yapf: disable pass - """) # noqa + """) # noqa self.assertYapfReformats(unformatted_code, expected_formatted_code) def testRetainingVerticalWhitespace(self): @@ -822,7 +811,7 @@ def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and @@ -835,7 +824,7 @@ def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass - """) # noqa + """) # noqa self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -857,7 +846,7 @@ def g(): #comment # trailing whitespace - """) + """) expected_formatted_code = textwrap.dedent("""\ if a: b @@ -872,7 +861,7 @@ def g(): #comment # trailing whitespace - """) + """) self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -885,28 +874,28 @@ def g(): ''' import blah - """) + """) self.assertYapfReformats( unformatted_code, unformatted_code, extra_options=['--lines', '2-2']) def testVerticalSpacingWithCommentWithContinuationMarkers(self): - unformatted_code = """\ -# \\ -# \\ -# \\ + unformatted_code = textwrap.dedent("""\ + # \\ + # \\ + # \\ -x = { -} -""" - expected_formatted_code = """\ -# \\ -# \\ -# \\ + x = { + } + """) + expected_formatted_code = textwrap.dedent("""\ + # \\ + # \\ + # \\ -x = { -} -""" + x = { + } + """) self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -918,13 +907,13 @@ def testRetainingSemicolonsWhenSpecifyingLines(self): def f(): x = y + 42; z = n * 42 if True: a += 1 ; b += 1 ; c += 1 - """) + """) expected_formatted_code = textwrap.dedent("""\ a = line_to_format def f(): x = y + 42; z = n * 42 if True: a += 1 ; b += 1 ; c += 1 - """) + """) self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -940,7 +929,7 @@ def f(): Residence: """+palace["Winter"]+"""
""" - ''') # noqa + ''') # noqa expected_formatted_code = textwrap.dedent('''\ foo = 42 def f(): @@ -950,7 +939,7 @@ def f(): Residence: """+palace["Winter"]+"""
""" - ''') # noqa + ''') # noqa self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -968,7 +957,7 @@ def testDisableWhenSpecifyingLines(self): 'hello', 'world', ]) # yapf: disable - """) + """) expected_formatted_code = textwrap.dedent("""\ # yapf: disable A = set([ @@ -980,7 +969,7 @@ def testDisableWhenSpecifyingLines(self): 'hello', 'world', ]) # yapf: disable - """) + """) self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -1005,7 +994,7 @@ def still_horrible(): 'that' ] - """) + """) expected_formatted_code = textwrap.dedent("""\ def horrible(): oh_god() @@ -1020,7 +1009,7 @@ def still_horrible(): oh_god() why_would_you() ['do', 'that'] - """) + """) self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -1037,7 +1026,7 @@ def aaaaaaaaaaaaa(self): c.ffffffffffff), gggggggggggg.hhhhhhhhh(c, c.ffffffffffff)) iiiii = jjjjjjjjjjjjjj.iiiii - """) + """) expected_formatted_code = textwrap.dedent("""\ class A(object): def aaaaaaaaaaaaa(self): @@ -1046,7 +1035,7 @@ def aaaaaaaaaaaaa(self): 'eeeeeeeeeeeeeeeeeeeeeeeee.%s' % c.ffffffffffff), gggggggggggg.hhhhhhhhh(c, c.ffffffffffff)) iiiii = jjjjjjjjjjjjjj.iiiii - """) # noqa + """) # noqa self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -1061,7 +1050,7 @@ def aaaaaaaaaaaaa(self): def bbbbbbbbbbbbb(self): # 5 pass - """) + """) expected_formatted_code = textwrap.dedent("""\ class A(object): def aaaaaaaaaaaaa(self): @@ -1070,7 +1059,7 @@ def aaaaaaaaaaaaa(self): def bbbbbbbbbbbbb(self): # 5 pass - """) + """) self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -1087,7 +1076,7 @@ def aaaaaaaaaaaaa(self): c.ffffffffffff), gggggggggggg.hhhhhhhhh(c, c.ffffffffffff)) iiiii = jjjjjjjjjjjjjj.iiiii - """) + """) expected_formatted_code = textwrap.dedent("""\ class A(object): def aaaaaaaaaaaaa(self): @@ -1096,7 +1085,7 @@ def aaaaaaaaaaaaa(self): 'eeeeeeeeeeeeeeeeeeeeeeeee.%s' % c.ffffffffffff), gggggggggggg.hhhhhhhhh(c, c.ffffffffffff)) iiiii = jjjjjjjjjjjjjj.iiiii - """) # noqa + """) # noqa self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -1110,7 +1099,7 @@ def foo(): ''' # comment x = '''hello world''' # second comment return 42 # another comment - """) + """) expected_formatted_code = textwrap.dedent("""\ def foo(): '''First line. @@ -1118,7 +1107,7 @@ def foo(): ''' # comment x = '''hello world''' # second comment return 42 # another comment - """) + """) self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -1127,15 +1116,15 @@ def foo(): def testDedentClosingBracket(self): # no line-break on the first argument, not dedenting closing brackets unformatted_code = textwrap.dedent("""\ - def overly_long_function_name(first_argument_on_the_same_line, - second_argument_makes_the_line_too_long): - pass - """) - expected_formatted_code = textwrap.dedent("""\ - def overly_long_function_name(first_argument_on_the_same_line, - second_argument_makes_the_line_too_long): + def overly_long_function_name(first_argument_on_the_same_line, + second_argument_makes_the_line_too_long): pass """) + expected_formatted_code = textwrap.dedent("""\ + def overly_long_function_name(first_argument_on_the_same_line, + second_argument_makes_the_line_too_long): + pass + """) # noqa self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -1150,10 +1139,10 @@ def overly_long_function_name(first_argument_on_the_same_line, # line-break before the first argument, dedenting closing brackets if set unformatted_code = textwrap.dedent("""\ - def overly_long_function_name( - first_argument_on_the_same_line, - second_argument_makes_the_line_too_long): - pass + def overly_long_function_name( + first_argument_on_the_same_line, + second_argument_makes_the_line_too_long): + pass """) # expected_formatted_pep8_code = textwrap.dedent("""\ # def overly_long_function_name( @@ -1162,10 +1151,10 @@ def overly_long_function_name( # pass # """) expected_formatted_fb_code = textwrap.dedent("""\ - def overly_long_function_name( - first_argument_on_the_same_line, second_argument_makes_the_line_too_long - ): - pass + def overly_long_function_name( + first_argument_on_the_same_line, second_argument_makes_the_line_too_long + ): + pass """) # noqa self.assertYapfReformats( unformatted_code, @@ -1185,20 +1174,20 @@ def testCoalesceBrackets(self): 'first_argument_of_the_thing': id, 'second_argument_of_the_thing': "some thing" } - )""") + ) + """) expected_formatted_code = textwrap.dedent("""\ some_long_function_name_foo({ 'first_argument_of_the_thing': id, 'second_argument_of_the_thing': "some thing" }) - """) + """) with utils.NamedTempFile(dirname=self.test_tmpdir, mode='w') as (f, name): - f.write( - textwrap.dedent('''\ + f.write(textwrap.dedent("""\ [style] column_limit=82 coalesce_brackets = True - ''')) + """)) f.flush() self.assertYapfReformats( unformatted_code, @@ -1210,12 +1199,12 @@ def testPseudoParenSpaces(self): def foo(): def bar(): return {msg_id: author for author, msg_id in reader} - """) + """) expected_formatted_code = textwrap.dedent("""\ def foo(): def bar(): return {msg_id: author for author, msg_id in reader} - """) + """) self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -1235,7 +1224,7 @@ def testMultilineCommentFormattingDisabled(self): ('yyyyy', zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz), '#': lambda x: x # do nothing } - """) + """) expected_formatted_code = textwrap.dedent("""\ # This is a comment FOO = { @@ -1249,7 +1238,7 @@ def testMultilineCommentFormattingDisabled(self): ('yyyyy', zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz), '#': lambda x: x # do nothing } - """) + """) self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -1262,36 +1251,36 @@ def testTrailingCommentsWithDisabledFormatting(self): SCOPES = [ 'hello world' # This is a comment. ] - """) + """) expected_formatted_code = textwrap.dedent("""\ import os SCOPES = [ 'hello world' # This is a comment. ] - """) + """) self.assertYapfReformats( unformatted_code, expected_formatted_code, extra_options=['--lines', '1-1', '--style', 'yapf']) def testUseTabs(self): - unformatted_code = """\ -def foo_function(): - if True: - pass -""" + unformatted_code = textwrap.dedent("""\ + def foo_function(): + if True: + pass + """) expected_formatted_code = """\ def foo_function(): if True: pass """ # noqa: W191,E101 - style_contents = """\ -[style] -based_on_style = yapf -USE_TABS = true -INDENT_WIDTH=1 -""" + style_contents = textwrap.dedent("""\ + [style] + based_on_style = yapf + use_tabs = true + indent_width = 1 + """) with utils.TempFileContents(self.test_tmpdir, style_contents) as stylepath: self.assertYapfReformats( unformatted_code, @@ -1310,12 +1299,12 @@ def f(): 'world', ] """ # noqa: W191,E101 - style_contents = """\ -[style] -based_on_style = yapf -USE_TABS = true -INDENT_WIDTH=1 -""" + style_contents = textwrap.dedent("""\ + [style] + based_on_style = yapf + use_tabs = true + indent_width = 1 + """) with utils.TempFileContents(self.test_tmpdir, style_contents) as stylepath: self.assertYapfReformats( unformatted_code, @@ -1335,15 +1324,15 @@ def foo_function( 'world', ] """ # noqa: W191,E101 - style_contents = """\ -[style] -based_on_style = yapf -USE_TABS = true -COLUMN_LIMIT=32 -INDENT_WIDTH=4 -CONTINUATION_INDENT_WIDTH=8 -CONTINUATION_ALIGN_STYLE = fixed -""" + style_contents = textwrap.dedent("""\ + [style] + based_on_style = yapf + use_tabs = true + column_limit=32 + indent_width=4 + continuation_indent_width=8 + continuation_align_style = fixed + """) with utils.TempFileContents(self.test_tmpdir, style_contents) as stylepath: self.assertYapfReformats( unformatted_code, @@ -1363,15 +1352,15 @@ def foo_function(arg1, arg2, 'world', ] """ # noqa: W191,E101 - style_contents = """\ -[style] -based_on_style = yapf -USE_TABS = true -COLUMN_LIMIT=32 -INDENT_WIDTH=4 -CONTINUATION_INDENT_WIDTH=8 -CONTINUATION_ALIGN_STYLE = valign-right -""" + style_contents = textwrap.dedent("""\ + [style] + based_on_style = yapf + use_tabs = true + column_limit = 32 + indent_width = 4 + continuation_indent_width = 8 + continuation_align_style = valign-right + """) with utils.TempFileContents(self.test_tmpdir, style_contents) as stylepath: self.assertYapfReformats( unformatted_code, @@ -1379,26 +1368,26 @@ def foo_function(arg1, arg2, extra_options=['--style={0}'.format(stylepath)]) def testUseSpacesContinuationAlignStyleFixed(self): - unformatted_code = """\ -def foo_function(arg1, arg2, arg3): - return ['hello', 'world',] -""" - expected_formatted_code = """\ -def foo_function( - arg1, arg2, arg3): - return [ - 'hello', - 'world', - ] -""" - style_contents = """\ -[style] -based_on_style = yapf -COLUMN_LIMIT=32 -INDENT_WIDTH=4 -CONTINUATION_INDENT_WIDTH=8 -CONTINUATION_ALIGN_STYLE = fixed -""" + unformatted_code = textwrap.dedent("""\ + def foo_function(arg1, arg2, arg3): + return ['hello', 'world',] + """) + expected_formatted_code = textwrap.dedent("""\ + def foo_function( + arg1, arg2, arg3): + return [ + 'hello', + 'world', + ] + """) + style_contents = textwrap.dedent("""\ + [style] + based_on_style = yapf + column_limit = 32 + indent_width = 4 + continuation_indent_width = 8 + continuation_align_style = fixed + """) with utils.TempFileContents(self.test_tmpdir, style_contents) as stylepath: self.assertYapfReformats( unformatted_code, @@ -1406,26 +1395,26 @@ def foo_function( extra_options=['--style={0}'.format(stylepath)]) def testUseSpacesContinuationAlignStyleVAlignRight(self): - unformatted_code = """\ -def foo_function(arg1, arg2, arg3): - return ['hello', 'world',] -""" - expected_formatted_code = """\ -def foo_function(arg1, arg2, - arg3): - return [ - 'hello', - 'world', - ] -""" - style_contents = """\ -[style] -based_on_style = yapf -COLUMN_LIMIT=32 -INDENT_WIDTH=4 -CONTINUATION_INDENT_WIDTH=8 -CONTINUATION_ALIGN_STYLE = valign-right -""" + unformatted_code = textwrap.dedent("""\ + def foo_function(arg1, arg2, arg3): + return ['hello', 'world',] + """) + expected_formatted_code = textwrap.dedent("""\ + def foo_function(arg1, arg2, + arg3): + return [ + 'hello', + 'world', + ] + """) + style_contents = textwrap.dedent("""\ + [style] + based_on_style = yapf + column_limit = 32 + indent_width = 4 + continuation_indent_width = 8 + continuation_align_style = valign-right + """) with utils.TempFileContents(self.test_tmpdir, style_contents) as stylepath: self.assertYapfReformats( unformatted_code, @@ -1436,11 +1425,11 @@ def testStyleOutputRoundTrip(self): unformatted_code = textwrap.dedent("""\ def foo_function(): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ def foo_function(): pass - """) + """) with utils.NamedTempFile(dirname=self.test_tmpdir) as (stylefile, stylepath): @@ -1466,7 +1455,7 @@ def x(): pass def _(): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ A = 42 @@ -1476,7 +1465,7 @@ def x(): pass def _(): pass - """) + """) self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -1497,7 +1486,7 @@ def testSpacingBeforeCommentsInDicts(self): BORKED: # Broken. 'BROKEN' } - """) + """) expected_formatted_code = textwrap.dedent("""\ A = 42 @@ -1512,7 +1501,7 @@ def testSpacingBeforeCommentsInDicts(self): BORKED: # Broken. 'BROKEN' } - """) + """) self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -1527,7 +1516,7 @@ def inner_func(): return return # yapf: enable - """) + """) expected_formatted_code = textwrap.dedent("""\ # yapf_lines_bug.py # yapf: disable @@ -1536,31 +1525,31 @@ def inner_func(): return return # yapf: enable - """) + """) self.assertYapfReformats( unformatted_code, expected_formatted_code, extra_options=['--lines', '1-8']) def testDisableWithLineRanges(self): - unformatted_code = """\ -# yapf: disable -a = [ - 1, - 2, + unformatted_code = textwrap.dedent("""\ + # yapf: disable + a = [ + 1, + 2, - 3 -] -""" - expected_formatted_code = """\ -# yapf: disable -a = [ - 1, - 2, + 3 + ] + """) + expected_formatted_code = textwrap.dedent("""\ + # yapf: disable + a = [ + 1, + 2, - 3 -] -""" + 3 + ] + """) self.assertYapfReformats( unformatted_code, expected_formatted_code, @@ -1597,11 +1586,11 @@ def testSimple(self): unformatted_code = textwrap.dedent("""\ for i in range(5): print('bar') - """) + """) expected_formatted_code = textwrap.dedent("""\ for i in range(5): print('bar') - """) + """) self._Check(unformatted_code, expected_formatted_code) @@ -1631,7 +1620,7 @@ def testSimple(self): foo = '3____________<25>' # Aligned at third list value foo = '4______________________<35>' # Aligned beyond list values - """) + """) expected_formatted_code = textwrap.dedent("""\ foo = '1' # Aligned at first list value @@ -1640,7 +1629,7 @@ def testSimple(self): foo = '3____________<25>' # Aligned at third list value foo = '4______________________<35>' # Aligned beyond list values - """) + """) self._Check(unformatted_code, expected_formatted_code) def testBlock(self): @@ -1651,7 +1640,7 @@ def testBlock(self): func(3) # Line 4 # Line 5 # Line 6 - """) + """) expected_formatted_code = textwrap.dedent("""\ func(1) # Line 1 func(2) # Line 2 @@ -1659,7 +1648,7 @@ def testBlock(self): func(3) # Line 4 # Line 5 # Line 6 - """) + """) self._Check(unformatted_code, expected_formatted_code) def testBlockWithLongLine(self): @@ -1670,7 +1659,7 @@ def testBlockWithLongLine(self): func(3) # Line 4 # Line 5 # Line 6 - """) + """) expected_formatted_code = textwrap.dedent("""\ func(1) # Line 1 func___________________(2) # Line 2 @@ -1678,7 +1667,7 @@ def testBlockWithLongLine(self): func(3) # Line 4 # Line 5 # Line 6 - """) + """) self._Check(unformatted_code, expected_formatted_code) def testBlockFuncSuffix(self): @@ -1692,7 +1681,7 @@ def testBlockFuncSuffix(self): def Func(): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ func(1) # Line 1 func(2) # Line 2 @@ -1704,7 +1693,7 @@ def Func(): def Func(): pass - """) + """) self._Check(unformatted_code, expected_formatted_code) def testBlockCommentSuffix(self): @@ -1717,7 +1706,7 @@ def testBlockCommentSuffix(self): # Line 6 # Aligned with prev comment block - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ func(1) # Line 1 func(2) # Line 2 @@ -1727,7 +1716,7 @@ def testBlockCommentSuffix(self): # Line 6 # Aligned with prev comment block - """) # noqa + """) # noqa self._Check(unformatted_code, expected_formatted_code) def testBlockIndentedFuncSuffix(self): @@ -1744,7 +1733,7 @@ def testBlockIndentedFuncSuffix(self): def Func(): pass - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ if True: func(1) # Line 1 @@ -1760,7 +1749,7 @@ def Func(): def Func(): pass - """) + """) self._Check(unformatted_code, expected_formatted_code) def testBlockIndentedCommentSuffix(self): @@ -1774,7 +1763,7 @@ def testBlockIndentedCommentSuffix(self): # Line 6 # Not aligned - """) + """) expected_formatted_code = textwrap.dedent("""\ if True: func(1) # Line 1 @@ -1785,7 +1774,7 @@ def testBlockIndentedCommentSuffix(self): # Line 6 # Not aligned - """) + """) self._Check(unformatted_code, expected_formatted_code) def testBlockMultiIndented(self): @@ -1801,7 +1790,7 @@ def testBlockMultiIndented(self): # Line 6 # Not aligned - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ if True: if True: @@ -1814,7 +1803,7 @@ def testBlockMultiIndented(self): # Line 6 # Not aligned - """) + """) self._Check(unformatted_code, expected_formatted_code) def testArgs(self): @@ -1828,7 +1817,7 @@ def MyFunc( arg6, ): pass - """) + """) expected_formatted_code = textwrap.dedent("""\ def MyFunc( arg1, # Desc 1 @@ -1839,7 +1828,7 @@ def MyFunc( arg6, ): pass - """) + """) self._Check(unformatted_code, expected_formatted_code) def testDisableBlock(self): @@ -1854,7 +1843,7 @@ def testDisableBlock(self): e() # comment 5 f() # comment 6 - """) + """) expected_formatted_code = textwrap.dedent("""\ a() # comment 1 b() # comment 2 @@ -1866,7 +1855,7 @@ def testDisableBlock(self): e() # comment 5 f() # comment 6 - """) + """) self._Check(unformatted_code, expected_formatted_code) def testDisabledLine(self): @@ -1875,13 +1864,13 @@ def testDisabledLine(self): do_not_touch1 # yapf: disable do_not_touch2 # yapf: disable a_longer_statement # comment 2 - """) + """) expected_formatted_code = textwrap.dedent("""\ short # comment 1 do_not_touch1 # yapf: disable do_not_touch2 # yapf: disable a_longer_statement # comment 2 - """) + """) self._Check(unformatted_code, expected_formatted_code) @@ -1915,40 +1904,39 @@ def _OwnStyle(cls): def testStandard(self): unformatted_code = textwrap.dedent("""\ - {1 : 2} - {k:v for k, v in other.items()} - {k for k in [1, 2, 3]} + {1 : 2} + {k:v for k, v in other.items()} + {k for k in [1, 2, 3]} - # The following statements should not change - {} - {1 : 2} # yapf: disable + # The following statements should not change + {} + {1 : 2} # yapf: disable - # yapf: disable - {1 : 2} - # yapf: enable + # yapf: disable + {1 : 2} + # yapf: enable - # Dict settings should not impact lists or tuples - [1, 2] - (3, 4) - """) + # Dict settings should not impact lists or tuples + [1, 2] + (3, 4) + """) expected_formatted_code = textwrap.dedent("""\ - { 1: 2 } - { k: v for k, v in other.items() } - { k for k in [1, 2, 3] } + { 1: 2 } + { k: v for k, v in other.items() } + { k for k in [1, 2, 3] } - # The following statements should not change - {} - {1 : 2} # yapf: disable + # The following statements should not change + {} + {1 : 2} # yapf: disable - # yapf: disable - {1 : 2} - # yapf: enable - - # Dict settings should not impact lists or tuples - [1, 2] - (3, 4) - """) + # yapf: disable + {1 : 2} + # yapf: enable + # Dict settings should not impact lists or tuples + [1, 2] + (3, 4) + """) self._Check(unformatted_code, expected_formatted_code) @@ -1963,48 +1951,47 @@ def _OwnStyle(cls): def testStandard(self): unformatted_code = textwrap.dedent("""\ - [a,b,c] - [4,5,] - [6, [7, 8], 9] - [v for v in [1,2,3] if v & 1] - - # The following statements should not change - index[0] - index[a, b] - [] - [v for v in [1,2,3] if v & 1] # yapf: disable - - # yapf: disable - [a,b,c] - [4,5,] - # yapf: enable - - # List settings should not impact dicts or tuples - {a: b} - (1, 2) - """) + [a,b,c] + [4,5,] + [6, [7, 8], 9] + [v for v in [1,2,3] if v & 1] + + # The following statements should not change + index[0] + index[a, b] + [] + [v for v in [1,2,3] if v & 1] # yapf: disable + + # yapf: disable + [a,b,c] + [4,5,] + # yapf: enable + + # List settings should not impact dicts or tuples + {a: b} + (1, 2) + """) expected_formatted_code = textwrap.dedent("""\ - [ a, b, c ] - [ 4, 5, ] - [ 6, [ 7, 8 ], 9 ] - [ v for v in [ 1, 2, 3 ] if v & 1 ] - - # The following statements should not change - index[0] - index[a, b] - [] - [v for v in [1,2,3] if v & 1] # yapf: disable - - # yapf: disable - [a,b,c] - [4,5,] - # yapf: enable - - # List settings should not impact dicts or tuples - {a: b} - (1, 2) - """) + [ a, b, c ] + [ 4, 5, ] + [ 6, [ 7, 8 ], 9 ] + [ v for v in [ 1, 2, 3 ] if v & 1 ] + + # The following statements should not change + index[0] + index[a, b] + [] + [v for v in [1,2,3] if v & 1] # yapf: disable + + # yapf: disable + [a,b,c] + [4,5,] + # yapf: enable + # List settings should not impact dicts or tuples + {a: b} + (1, 2) + """) self._Check(unformatted_code, expected_formatted_code) @@ -2019,52 +2006,51 @@ def _OwnStyle(cls): def testStandard(self): unformatted_code = textwrap.dedent("""\ - (0, 1) - (2, 3) - (4, 5, 6,) - func((7, 8), 9) + (0, 1) + (2, 3) + (4, 5, 6,) + func((7, 8), 9) - # The following statements should not change - func(1, 2) - (this_func or that_func)(3, 4) - if (True and False): pass - () + # The following statements should not change + func(1, 2) + (this_func or that_func)(3, 4) + if (True and False): pass + () - (0, 1) # yapf: disable + (0, 1) # yapf: disable - # yapf: disable - (0, 1) - (2, 3) - # yapf: enable + # yapf: disable + (0, 1) + (2, 3) + # yapf: enable - # Tuple settings should not impact dicts or lists - {a: b} - [3, 4] - """) + # Tuple settings should not impact dicts or lists + {a: b} + [3, 4] + """) expected_formatted_code = textwrap.dedent("""\ - ( 0, 1 ) - ( 2, 3 ) - ( 4, 5, 6, ) - func(( 7, 8 ), 9) + ( 0, 1 ) + ( 2, 3 ) + ( 4, 5, 6, ) + func(( 7, 8 ), 9) - # The following statements should not change - func(1, 2) - (this_func or that_func)(3, 4) - if (True and False): pass - () + # The following statements should not change + func(1, 2) + (this_func or that_func)(3, 4) + if (True and False): pass + () - (0, 1) # yapf: disable + (0, 1) # yapf: disable - # yapf: disable - (0, 1) - (2, 3) - # yapf: enable - - # Tuple settings should not impact dicts or lists - {a: b} - [3, 4] - """) + # yapf: disable + (0, 1) + (2, 3) + # yapf: enable + # Tuple settings should not impact dicts or lists + {a: b} + [3, 4] + """) self._Check(unformatted_code, expected_formatted_code) From 1cfdc167437e941aebe82f422169229dccf75fcf Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 23 Jun 2023 18:21:57 -0500 Subject: [PATCH 649/719] Remove the "verifier" module The verifier module isn't actively used. The one test that does use it has code that is unlikely to ever cause an issue. --- .coveragerc | 2 - CHANGELOG | 5 ++ yapf/__init__.py | 17 ++--- yapf/yapflib/reformatter.py | 10 +-- yapf/yapflib/verifier.py | 93 --------------------------- yapf/yapflib/yapf_api.py | 22 ++----- yapftests/reformatter_python3_test.py | 2 +- yapftests/yapf_test.py | 13 ++-- 8 files changed, 26 insertions(+), 138 deletions(-) delete mode 100644 yapf/yapflib/verifier.py diff --git a/.coveragerc b/.coveragerc index 3c3efd737..de8cf5fb1 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,5 +1,3 @@ [report] -# Verifier is used for testing only. omit = */__main__.py - */verifier.py diff --git a/CHANGELOG b/CHANGELOG index 9122fafd8..4dc2d1e4c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,11 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## [0.41.0] UNRELEASED +### Changes +- The verification module has been removed. NOTE: this changes the public APIs + by removing the "verify" parameter. + ## [0.40.1] 2023-06-20 ### Fixed - Corrected bad distribution v0.40.0 package. diff --git a/yapf/__init__.py b/yapf/__init__.py index a0406e260..e97ba3711 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -117,8 +117,7 @@ def main(argv): str('\n'.join(source) + '\n'), filename='', style_config=style_config, - lines=lines, - verify=args.verify) + lines=lines) except errors.YapfError: raise except Exception as e: @@ -144,7 +143,6 @@ def main(argv): no_local_style=args.no_local_style, in_place=args.in_place, print_diff=args.diff, - verify=args.verify, parallel=args.parallel, quiet=args.quiet, verbose=args.verbose, @@ -175,7 +173,6 @@ def FormatFiles(filenames, no_local_style=False, in_place=False, print_diff=False, - verify=False, parallel=False, quiet=False, verbose=False, @@ -194,7 +191,6 @@ def FormatFiles(filenames, in_place: (bool) Modify the files in place. print_diff: (bool) Instead of returning the reformatted source, return a diff that turns the formatted source into reformatter source. - verify: (bool) True if reformatted code should be verified for syntax. parallel: (bool) True if should format multiple files in parallel. quiet: (bool) True if should output nothing. verbose: (bool) True if should print out filenames while processing. @@ -211,16 +207,16 @@ def FormatFiles(filenames, with concurrent.futures.ProcessPoolExecutor(workers) as executor: future_formats = [ executor.submit(_FormatFile, filename, lines, style_config, - no_local_style, in_place, print_diff, verify, quiet, - verbose, print_modified) for filename in filenames + no_local_style, in_place, print_diff, quiet, verbose, + print_modified) for filename in filenames ] for future in concurrent.futures.as_completed(future_formats): changed |= future.result() else: for filename in filenames: changed |= _FormatFile(filename, lines, style_config, no_local_style, - in_place, print_diff, verify, quiet, verbose, - print_modified) + in_place, print_diff, quiet, verbose, + print_modified) return changed @@ -230,7 +226,6 @@ def _FormatFile(filename, no_local_style=False, in_place=False, print_diff=False, - verify=False, quiet=False, verbose=False, print_modified=False): @@ -249,7 +244,6 @@ def _FormatFile(filename, style_config=style_config, lines=lines, print_diff=print_diff, - verify=verify, logger=logging.warning) except errors.YapfError: raise @@ -360,7 +354,6 @@ def _BuildParser(): '--no-local-style', action='store_true', help="don't search for local style definition") - parser.add_argument('--verify', action='store_true', help=argparse.SUPPRESS) parser.add_argument( '-p', '--parallel', diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index a74b44f6b..319fc9cc0 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -31,15 +31,13 @@ from yapf.yapflib import format_token from yapf.yapflib import line_joiner from yapf.yapflib import style -from yapf.yapflib import verifier -def Reformat(llines, verify=False, lines=None): +def Reformat(llines, lines=None): """Reformat the logical lines. Arguments: llines: (list of logical_line.LogicalLine) Lines we want to format. - verify: (bool) True if reformatted code should be verified for syntax. lines: (set of int) The lines which can be modified or None if there is no line range restriction. @@ -101,7 +99,7 @@ def Reformat(llines, verify=False, lines=None): prev_line = lline _AlignTrailingComments(final_lines) - return _FormatFinalLines(final_lines, verify) + return _FormatFinalLines(final_lines) def _RetainHorizontalSpacing(line): @@ -392,7 +390,7 @@ def _AlignTrailingComments(final_lines): final_lines_index += 1 -def _FormatFinalLines(final_lines, verify): +def _FormatFinalLines(final_lines): """Compose the final output from the finalized lines.""" formatted_code = [] for line in final_lines: @@ -408,8 +406,6 @@ def _FormatFinalLines(final_lines, verify): formatted_line.append(' ') formatted_code.append(''.join(formatted_line)) - if verify: - verifier.VerifyCode(formatted_code[-1]) return ''.join(formatted_code) + '\n' diff --git a/yapf/yapflib/verifier.py b/yapf/yapflib/verifier.py deleted file mode 100644 index bcbe6fb6b..000000000 --- a/yapf/yapflib/verifier.py +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright 2015 Google Inc. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Verify that the generated code is valid code. - -This takes a line of code and "normalizes" it. I.e., it transforms the snippet -into something that has the potential to compile. - - VerifyCode(): the main function exported by this module. -""" - -import ast -import re -import sys -import textwrap - - -class InternalError(Exception): - """Internal error in verifying formatted code.""" - pass - - -def VerifyCode(code): - """Verify that the reformatted code is syntactically correct. - - Arguments: - code: (unicode) The reformatted code snippet. - - Raises: - SyntaxError if the code was reformatted incorrectly. - """ - try: - compile(textwrap.dedent(code).encode('UTF-8'), '', 'exec') - except SyntaxError: - try: - ast.parse(textwrap.dedent(code.lstrip('\n')).lstrip(), '', 'exec') - except SyntaxError: - try: - normalized_code = _NormalizeCode(code) - compile(normalized_code.encode('UTF-8'), '', 'exec') - except SyntaxError: - raise InternalError(sys.exc_info()[1]) - - -def _NormalizeCode(code): - """Make sure that the code snippet is compilable.""" - code = textwrap.dedent(code.lstrip('\n')).lstrip() - - # Split the code to lines and get rid of all leading full-comment lines as - # they can mess up the normalization attempt. - lines = code.split('\n') - i = 0 - for i, line in enumerate(lines): - line = line.strip() - if line and not line.startswith('#'): - break - code = '\n'.join(lines[i:]) + '\n' - - if re.match(r'(if|while|for|with|def|class|async|await)\b', code): - code += '\n pass' - elif re.match(r'(elif|else)\b', code): - try: - try_code = 'if True:\n pass\n' + code + '\n pass' - ast.parse( - textwrap.dedent(try_code.lstrip('\n')).lstrip(), '', 'exec') - code = try_code - except SyntaxError: - # The assumption here is that the code is on a single line. - code = 'if True: pass\n' + code - elif code.startswith('@'): - code += '\ndef _():\n pass' - elif re.match(r'try\b', code): - code += '\n pass\nexcept:\n pass' - elif re.match(r'(except|finally)\b', code): - code = 'try:\n pass\n' + code + '\n pass' - elif re.match(r'(return|yield)\b', code): - code = 'def _():\n ' + code - elif re.match(r'(continue|break)\b', code): - code = 'while True:\n ' + code - elif re.match(r'print\b', code): - code = 'from __future__ import print_function\n' + code - - return code + '\n' diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index cac62be52..53e45c124 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -29,7 +29,6 @@ than a whole file. print_diff: (bool) Instead of returning the reformatted source, return a diff that turns the formatted source into reformatter source. - verify: (bool) True if reformatted code should be verified for syntax. """ import codecs @@ -55,7 +54,6 @@ def FormatFile(filename, style_config=None, lines=None, print_diff=False, - verify=False, in_place=False, logger=None): """Format a single Python file and return the formatted code. @@ -71,7 +69,6 @@ def FormatFile(filename, than a whole file. print_diff: (bool) Instead of returning the reformatted source, return a diff that turns the formatted source into reformatter source. - verify: (bool) True if reformatted code should be verified for syntax. in_place: (bool) If True, write the reformatted code back to the file. logger: (io streamer) A stream to output logging. @@ -93,8 +90,7 @@ def FormatFile(filename, style_config=style_config, filename=filename, lines=lines, - print_diff=print_diff, - verify=verify) + print_diff=print_diff) if newline != '\n': reformatted_source = reformatted_source.replace('\n', newline) if in_place: @@ -106,7 +102,7 @@ def FormatFile(filename, return reformatted_source, encoding, changed -def FormatTree(tree, style_config=None, lines=None, verify=False): +def FormatTree(tree, style_config=None, lines=None): """Format a parsed lib2to3 pytree. This provides an alternative entry point to YAPF. @@ -120,7 +116,6 @@ def FormatTree(tree, style_config=None, lines=None, verify=False): that we want to format. The lines are 1-based indexed. It can be used by third-party code (e.g., IDEs) when reformatting a snippet of code rather than a whole file. - verify: (bool) True if reformatted code should be verified for syntax. Returns: The source formatted according to the given formatting style. @@ -141,10 +136,10 @@ def FormatTree(tree, style_config=None, lines=None, verify=False): lines = _LineRangesToSet(lines) _MarkLinesToFormat(llines, lines) - return reformatter.Reformat(_SplitSemicolons(llines), verify, lines) + return reformatter.Reformat(_SplitSemicolons(llines), lines) -def FormatAST(ast, style_config=None, lines=None, verify=False): +def FormatAST(ast, style_config=None, lines=None): """Format a parsed lib2to3 pytree. This provides an alternative entry point to YAPF. @@ -158,7 +153,6 @@ def FormatAST(ast, style_config=None, lines=None, verify=False): that we want to format. The lines are 1-based indexed. It can be used by third-party code (e.g., IDEs) when reformatting a snippet of code rather than a whole file. - verify: (bool) True if reformatted code should be verified for syntax. Returns: The source formatted according to the given formatting style. @@ -171,15 +165,14 @@ def FormatAST(ast, style_config=None, lines=None, verify=False): lines = _LineRangesToSet(lines) _MarkLinesToFormat(llines, lines) - return reformatter.Reformat(_SplitSemicolons(llines), verify, lines) + return reformatter.Reformat(_SplitSemicolons(llines), lines) def FormatCode(unformatted_source, filename='', style_config=None, lines=None, - print_diff=False, - verify=False): + print_diff=False): """Format a string of Python code. This provides an alternative entry point to YAPF. @@ -196,7 +189,6 @@ def FormatCode(unformatted_source, than a whole file. print_diff: (bool) Instead of returning the reformatted source, return a diff that turns the formatted source into reformatter source. - verify: (bool) True if reformatted code should be verified for syntax. Returns: Tuple of (reformatted_source, changed). reformatted_source conforms to the @@ -209,7 +201,7 @@ def FormatCode(unformatted_source, raise errors.YapfError(errors.FormatErrorMsg(e)) reformatted_source = FormatTree( - tree, style_config=style_config, lines=lines, verify=verify) + tree, style_config=style_config, lines=lines) if unformatted_source == reformatted_source: return '' if print_diff else reformatted_source, False diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index b7f0de39f..b2ec3353d 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -106,7 +106,7 @@ async def main(): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) - self.assertCodeEqual(code, reformatter.Reformat(llines, verify=False)) + self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSpacesAroundPowerOperator(self): unformatted_code = textwrap.dedent("""\ diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 04727e925..9c7f8b331 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -34,10 +34,7 @@ from yapftests import utils from yapftests import yapf_test_helper -ROOT_DIR = os.path.dirname(os.path.abspath(os.path.dirname(__file__))) - -# Verification is turned off by default, but want to enable it for testing. -YAPF_BINARY = [sys.executable, '-m', 'yapf', '--verify', '--no-local-style'] +YAPF_BINARY = [sys.executable, '-m', 'yapf', '--no-local-style'] class FormatCodeTest(yapf_test_helper.YAPFTest): @@ -392,7 +389,7 @@ def testCRLFLineEnding(self): self.assertCodeEqual(code, formatted_code) -class CommandLineTest(unittest.TestCase): +class CommandLineTest(yapf_test_helper.YAPFTest): """Test how calling yapf from the command line acts.""" @classmethod @@ -1556,7 +1553,7 @@ def testDisableWithLineRanges(self): extra_options=['--style', 'yapf', '--lines', '1-100']) -class BadInputTest(unittest.TestCase): +class BadInputTest(yapf_test_helper.YAPFTest): """Test yapf's behaviour when passed bad input.""" def testBadSyntax(self): @@ -1568,7 +1565,7 @@ def testBadCode(self): self.assertRaises(errors.YapfError, yapf_api.FormatCode, code) -class DiffIndentTest(unittest.TestCase): +class DiffIndentTest(yapf_test_helper.YAPFTest): @staticmethod def _OwnStyle(): @@ -1874,7 +1871,7 @@ def testDisabledLine(self): self._Check(unformatted_code, expected_formatted_code) -class _SpacesAroundDictListTupleTestImpl(unittest.TestCase): +class _SpacesAroundDictListTupleTestImpl(yapf_test_helper.YAPFTest): @staticmethod def _OwnStyle(): From 4cf2bab5c8093b9de391fda28f3d20301cff9a9a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 26 Jun 2023 15:38:49 -0500 Subject: [PATCH 650/719] Add fixer_base and do some minor reformatting --- .../yapf_third_party/_ylib2to3/fixer_base.py | 186 ++++++++++++++++++ .../yapf_third_party/_ylib2to3/fixer_util.py | 68 +++---- 2 files changed, 221 insertions(+), 33 deletions(-) create mode 100644 third_party/yapf_third_party/_ylib2to3/fixer_base.py diff --git a/third_party/yapf_third_party/_ylib2to3/fixer_base.py b/third_party/yapf_third_party/_ylib2to3/fixer_base.py new file mode 100644 index 000000000..d550aada3 --- /dev/null +++ b/third_party/yapf_third_party/_ylib2to3/fixer_base.py @@ -0,0 +1,186 @@ +# Copyright 2006 Google, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. +"""Base class for fixers (optional, but recommended).""" + +# Python imports +import itertools + +# Local imports +from .patcomp import PatternCompiler +from . import pygram +from .fixer_util import does_tree_import + + +class BaseFix(object): + """Optional base class for fixers. + + The subclass name must be FixFooBar where FooBar is the result of + removing underscores and capitalizing the words of the fix name. + For example, the class name for a fixer named 'has_key' should be + FixHasKey. + """ + + PATTERN = None # Most subclasses should override with a string literal + pattern = None # Compiled pattern, set by compile_pattern() + pattern_tree = None # Tree representation of the pattern + options = None # Options object passed to initializer + filename = None # The filename (set by set_filename) + numbers = itertools.count(1) # For new_name() + used_names = set() # A set of all used NAMEs + order = "post" # Does the fixer prefer pre- or post-order traversal + explicit = False # Is this ignored by refactor.py -f all? + run_order = 5 # Fixers will be sorted by run order before execution + # Lower numbers will be run first. + _accept_type = None # [Advanced and not public] This tells RefactoringTool + # which node type to accept when there's not a pattern. + + keep_line_order = False # For the bottom matcher: match with the + # original line order + BM_compatible = False # Compatibility with the bottom matching + # module; every fixer should set this + # manually + + # Shortcut for access to Python grammar symbols + syms = pygram.python_symbols + + def __init__(self, options, log): + """Initializer. Subclass may override. + + Args: + options: a dict containing the options passed to RefactoringTool + that could be used to customize the fixer through the command line. + log: a list to append warnings and other messages to. + """ + self.options = options + self.log = log + self.compile_pattern() + + def compile_pattern(self): + """Compiles self.PATTERN into self.pattern. + + Subclass may override if it doesn't want to use + self.{pattern,PATTERN} in .match(). + """ + if self.PATTERN is not None: + PC = PatternCompiler() + self.pattern, self.pattern_tree = PC.compile_pattern( + self.PATTERN, with_tree=True) + + def set_filename(self, filename): + """Set the filename. + + The main refactoring tool should call this. + """ + self.filename = filename + + def match(self, node): + """Returns match for a given parse tree node. + + Should return a true or false object (not necessarily a bool). + It may return a non-empty dict of matching sub-nodes as + returned by a matching pattern. + + Subclass may override. + """ + results = {"node": node} + return self.pattern.match(node, results) and results + + def transform(self, node, results): + """Returns the transformation for a given parse tree node. + + Args: + node: the root of the parse tree that matched the fixer. + results: a dict mapping symbolic names to part of the match. + + Returns: + None, or a node that is a modified copy of the + argument node. The node argument may also be modified in-place to + effect the same change. + + Subclass *must* override. + """ + raise NotImplementedError() + + def new_name(self, template="xxx_todo_changeme"): + """Return a string suitable for use as an identifier + + The new name is guaranteed not to conflict with other identifiers. + """ + name = template + while name in self.used_names: + name = template + str(next(self.numbers)) + self.used_names.add(name) + return name + + def log_message(self, message): + if self.first_log: + self.first_log = False + self.log.append("### In file %s ###" % self.filename) + self.log.append(message) + + def cannot_convert(self, node, reason=None): + """Warn the user that a given chunk of code is not valid Python 3, + but that it cannot be converted automatically. + + First argument is the top-level node for the code in question. + Optional second argument is why it can't be converted. + """ + lineno = node.get_lineno() + for_output = node.clone() + for_output.prefix = "" + msg = "Line %d: could not convert: %s" + self.log_message(msg % (lineno, for_output)) + if reason: + self.log_message(reason) + + def warning(self, node, reason): + """Used for warning the user about possible uncertainty in the translation. + + First argument is the top-level node for the code in question. + Optional second argument is why it can't be converted. + """ + lineno = node.get_lineno() + self.log_message("Line %d: %s" % (lineno, reason)) + + def start_tree(self, tree, filename): + """Some fixers need to maintain tree-wide state. + + This method is called once, at the start of tree fix-up. + + tree - the root node of the tree to be processed. + filename - the name of the file the tree came from. + """ + self.used_names = tree.used_names + self.set_filename(filename) + self.numbers = itertools.count(1) + self.first_log = True + + def finish_tree(self, tree, filename): + """Some fixers need to maintain tree-wide state. + + This method is called once, at the conclusion of tree fix-up. + + tree - the root node of the tree to be processed. + filename - the name of the file the tree came from. + """ + pass + + +class ConditionalFix(BaseFix): + """ Base class for fixers which not execute if an import is found. """ + + # This is the name of the import which, if found, will cause the test to be skipped + skip_on = None + + def start_tree(self, *args): + super(ConditionalFix, self).start_tree(*args) + self._should_skip = None + + def should_skip(self, node): + if self._should_skip is not None: + return self._should_skip + pkg = self.skip_on.split(".") + name = pkg[-1] + pkg = ".".join(pkg[:-1]) + self._should_skip = does_tree_import(pkg, name, node) + return self._should_skip diff --git a/third_party/yapf_third_party/_ylib2to3/fixer_util.py b/third_party/yapf_third_party/_ylib2to3/fixer_util.py index c8ff3ac9b..373b2be17 100644 --- a/third_party/yapf_third_party/_ylib2to3/fixer_util.py +++ b/third_party/yapf_third_party/_ylib2to3/fixer_util.py @@ -101,8 +101,8 @@ def String(string, prefix=None): def ListComp(xp, fp, it, test=None): """A list comprehension of the form [xp for fp in it if test]. - If test is None, the "if test" part is omitted. - """ + If test is None, the "if test" part is omitted. + """ xp.prefix = '' fp.prefix = ' ' it.prefix = ' ' @@ -124,7 +124,9 @@ def ListComp(xp, fp, it, test=None): def FromImport(package_name, name_leafs): """ Return an import statement in the form: - from package import name_leafs""" + + from package import name_leafs + """ # XXX: May not handle dotted imports properly (eg, package_name='foo.bar') # #assert package_name == '.' or '.' not in package_name, "FromImport has "\ # "not been tested with dotted package names -- use at your own "\ @@ -145,11 +147,11 @@ def FromImport(package_name, name_leafs): def ImportAndCall(node, results, names): - """Returns an import statement and calls a method - of the module: + """Returns an import statement and calls a method of the module: - import module - module.name()""" + import module + module.name() + """ obj = results['obj'].clone() if obj.type == syms.arglist: newarglist = obj.clone() @@ -210,17 +212,17 @@ def parenthesize(node): def attr_chain(obj, attr): """Follow an attribute chain. - If you have a chain of objects where a.foo -> b, b.foo-> c, etc, - use this to iterate over all objects in the chain. Iteration is - terminated by getattr(x, attr) is None. + If you have a chain of objects where a.foo -> b, b.foo-> c, etc, use this to + iterate over all objects in the chain. Iteration is terminated by getattr(x, + attr) is None. - Args: - obj: the starting object - attr: the name of the chaining attribute + Args: + obj: the starting object + attr: the name of the chaining attribute - Yields: - Each successive object in the chain. - """ + Yields: + Each successive object in the chain. + """ next = getattr(obj, attr) while next: yield next @@ -250,10 +252,10 @@ def attr_chain(obj, attr): def in_special_context(node): """ Returns true if node is in an environment where all that is required - of it is being iterable (ie, it doesn't matter if it returns a list - or an iterator). - See test_map_nochange in test_fixers.py for some examples and tests. - """ + of it is being iterable (ie, it doesn't matter if it returns a list + or an iterator). + See test_map_nochange in test_fixers.py for some examples and tests. + """ global p0, p1, p2, pats_built if not pats_built: p0 = patcomp.compile_pattern(p0) @@ -269,9 +271,7 @@ def in_special_context(node): def is_probably_builtin(node): - """ - Check that something isn't an attribute or function name etc. - """ + """Check that something isn't an attribute or function name etc.""" prev = node.prev_sibling if prev is not None and prev.type == token.DOT: # Attribute lookup. @@ -328,9 +328,10 @@ def find_root(node): def does_tree_import(package, name, node): """ Returns true if name is imported from package at the - top level of the tree which node belongs to. - To cover the case of an import like 'import foo', use - None for the package and 'foo' for the name. """ + top level of the tree which node belongs to. + To cover the case of an import like 'import foo', use + None for the package and 'foo' for the name. + """ binding = find_binding(name, find_root(node), package) return bool(binding) @@ -342,7 +343,7 @@ def is_import(node): def touch_import(package, name, node): """ Works like `does_tree_import` but adds an import statement - if it was not imported. """ + if it was not imported. """ def is_import_stmt(node): return (node.type == syms.simple_stmt and node.children and @@ -391,9 +392,10 @@ def is_import_stmt(node): def find_binding(name, node, package=None): """ Returns the node which binds variable name, otherwise None. - If optional argument package is supplied, only imports will - be returned. - See test cases for examples.""" + If optional argument package is supplied, only imports will + be returned. + See test cases for examples. + """ for child in node.children: ret = None if child.type == syms.for_stmt: @@ -451,9 +453,9 @@ def _find(name, node): def _is_import_binding(node, name, package=None): """ Will return node if node will import name, or node - will import * from package. None is returned otherwise. - See test cases for examples. """ - + will import * from package. None is returned otherwise. + See test cases for examples. + """ if node.type == syms.import_name and not package: imp = node.children[1] if imp.type == syms.dotted_as_names: From e44d5feeb9fb0c138b7fb43d5af58b2afdec8703 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 25 Jul 2023 22:11:40 -0500 Subject: [PATCH 651/719] Fix some precommit failures due to formatting --- .../yapf_third_party/_ylib2to3/fixer_base.py | 22 +++++++++---------- yapf/__init__.py | 8 +++---- yapf/yapflib/yapf_api.py | 3 +-- yapftests/format_token_test.py | 1 + yapftests/reformatter_basic_test.py | 2 +- yapftests/reformatter_pep8_test.py | 3 ++- yapftests/yapf_test.py | 3 ++- 7 files changed, 22 insertions(+), 20 deletions(-) diff --git a/third_party/yapf_third_party/_ylib2to3/fixer_base.py b/third_party/yapf_third_party/_ylib2to3/fixer_base.py index d550aada3..5214c023e 100644 --- a/third_party/yapf_third_party/_ylib2to3/fixer_base.py +++ b/third_party/yapf_third_party/_ylib2to3/fixer_base.py @@ -5,10 +5,10 @@ # Python imports import itertools -# Local imports -from .patcomp import PatternCompiler from . import pygram from .fixer_util import does_tree_import +# Local imports +from .patcomp import PatternCompiler class BaseFix(object): @@ -27,7 +27,7 @@ class BaseFix(object): filename = None # The filename (set by set_filename) numbers = itertools.count(1) # For new_name() used_names = set() # A set of all used NAMEs - order = "post" # Does the fixer prefer pre- or post-order traversal + order = 'post' # Does the fixer prefer pre- or post-order traversal explicit = False # Is this ignored by refactor.py -f all? run_order = 5 # Fixers will be sorted by run order before execution # Lower numbers will be run first. @@ -82,7 +82,7 @@ def match(self, node): Subclass may override. """ - results = {"node": node} + results = {'node': node} return self.pattern.match(node, results) and results def transform(self, node, results): @@ -101,7 +101,7 @@ def transform(self, node, results): """ raise NotImplementedError() - def new_name(self, template="xxx_todo_changeme"): + def new_name(self, template='xxx_todo_changeme'): """Return a string suitable for use as an identifier The new name is guaranteed not to conflict with other identifiers. @@ -115,7 +115,7 @@ def new_name(self, template="xxx_todo_changeme"): def log_message(self, message): if self.first_log: self.first_log = False - self.log.append("### In file %s ###" % self.filename) + self.log.append('### In file %s ###' % self.filename) self.log.append(message) def cannot_convert(self, node, reason=None): @@ -127,8 +127,8 @@ def cannot_convert(self, node, reason=None): """ lineno = node.get_lineno() for_output = node.clone() - for_output.prefix = "" - msg = "Line %d: could not convert: %s" + for_output.prefix = '' + msg = 'Line %d: could not convert: %s' self.log_message(msg % (lineno, for_output)) if reason: self.log_message(reason) @@ -140,7 +140,7 @@ def warning(self, node, reason): Optional second argument is why it can't be converted. """ lineno = node.get_lineno() - self.log_message("Line %d: %s" % (lineno, reason)) + self.log_message('Line %d: %s' % (lineno, reason)) def start_tree(self, tree, filename): """Some fixers need to maintain tree-wide state. @@ -179,8 +179,8 @@ def start_tree(self, *args): def should_skip(self, node): if self._should_skip is not None: return self._should_skip - pkg = self.skip_on.split(".") + pkg = self.skip_on.split('.') name = pkg[-1] - pkg = ".".join(pkg[:-1]) + pkg = '.'.join(pkg[:-1]) self._should_skip = does_tree_import(pkg, name, node) return self._should_skip diff --git a/yapf/__init__.py b/yapf/__init__.py index e97ba3711..d6cde95a0 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -207,16 +207,16 @@ def FormatFiles(filenames, with concurrent.futures.ProcessPoolExecutor(workers) as executor: future_formats = [ executor.submit(_FormatFile, filename, lines, style_config, - no_local_style, in_place, print_diff, quiet, verbose, - print_modified) for filename in filenames + no_local_style, in_place, print_diff, quiet, verbose, + print_modified) for filename in filenames ] for future in concurrent.futures.as_completed(future_formats): changed |= future.result() else: for filename in filenames: changed |= _FormatFile(filename, lines, style_config, no_local_style, - in_place, print_diff, quiet, verbose, - print_modified) + in_place, print_diff, quiet, verbose, + print_modified) return changed diff --git a/yapf/yapflib/yapf_api.py b/yapf/yapflib/yapf_api.py index 53e45c124..aa010bb8f 100644 --- a/yapf/yapflib/yapf_api.py +++ b/yapf/yapflib/yapf_api.py @@ -200,8 +200,7 @@ def FormatCode(unformatted_source, e.filename = filename raise errors.YapfError(errors.FormatErrorMsg(e)) - reformatted_source = FormatTree( - tree, style_config=style_config, lines=lines) + reformatted_source = FormatTree(tree, style_config=style_config, lines=lines) if unformatted_source == reformatted_source: return '' if print_diff else reformatted_source, False diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index 72b378430..0db5680ab 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -22,6 +22,7 @@ from yapftests import yapf_test_helper + class TabbedContinuationAlignPaddingTest(yapf_test_helper.YAPFTest): def testSpace(self): diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 0a05b3b1b..cf8cfe476 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -1376,7 +1376,7 @@ def timeout(seconds=1): pass except: pass - """) # noqa + """) # noqa expected_formatted_code = textwrap.dedent("""\ import signal diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index a00e347c1..a027d99e2 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -832,7 +832,8 @@ def testEnabled(self): def testWithSpaceInsideBrackets(self): style.SetGlobalStyle( style.CreateStyleFromConfig( - '{spaces_around_subscript_colon: true, space_inside_brackets: true,}')) # noqa + '{spaces_around_subscript_colon: true, space_inside_brackets: true,}' + )) # noqa expected_formatted_code = textwrap.dedent("""\ a = list1[ : ] b = list2[ slice_start : ] diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index 9c7f8b331..a9ca01188 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -1180,7 +1180,8 @@ def testCoalesceBrackets(self): }) """) with utils.NamedTempFile(dirname=self.test_tmpdir, mode='w') as (f, name): - f.write(textwrap.dedent("""\ + f.write( + textwrap.dedent("""\ [style] column_limit=82 coalesce_brackets = True From 93848deb25df9a867dbffce0405ccf06de2ea4cd Mon Sep 17 00:00:00 2001 From: ManiacDC Date: Tue, 25 Jul 2023 23:12:38 -0400 Subject: [PATCH 652/719] SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES and FORCE_MULTILINE_DICT interaction (#1103) * SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES and FORCE_MULTILINE_DICT interaction * explicitly defined FORCE_MULTILINE_DICT to override SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES * added tests to account for the interaction of these two knobs * * fix formatting * Updated changelog --- CHANGELOG | 1 + yapf/yapflib/format_decision_state.py | 4 +++ yapftests/reformatter_basic_test.py | 50 ++++++++++++++++++++++++--- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4dc2d1e4c..70b3c9b91 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,7 @@ ### Changes - The verification module has been removed. NOTE: this changes the public APIs by removing the "verify" parameter. +- Changed FORCE_MULTILINE_DICT to override SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES. ## [0.40.1] 2023-06-20 ### Fixed diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 0c8643f20..a0d7033a3 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -181,6 +181,10 @@ def MustSplit(self): if style.Get('SPLIT_ALL_COMMA_SEPARATED_VALUES') and previous.value == ',': return True + if (style.Get('FORCE_MULTILINE_DICT') and + subtypes.DICTIONARY_KEY in current.subtypes and not current.is_comment): + return True + if (style.Get('SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES') and previous.value == ','): # Avoid breaking in a container that fits in the current line if possible diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index cf8cfe476..aae46d6ff 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -110,10 +110,10 @@ def foo(long_arg, self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingTopLevelAllArgs(self): - style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{split_all_top_level_comma_separated_values: true, ' - 'column_limit: 40}')) + style_dict = style.CreateStyleFromConfig( + '{split_all_top_level_comma_separated_values: true, ' + 'column_limit: 40}') + style.SetGlobalStyle(style_dict) # Works the same way as split_all_comma_separated_values unformatted_code = textwrap.dedent("""\ responseDict = {"timestamp": timestamp, "someValue": value, "whatever": 120} @@ -193,6 +193,48 @@ def foo(long_arg, llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) + # This tests when there is an embedded dictionary that will fit in a line + original_multiline = style_dict['FORCE_MULTILINE_DICT'] + style_dict['FORCE_MULTILINE_DICT'] = False + style.SetGlobalStyle(style_dict) + unformatted_code = textwrap.dedent("""\ + someLongFunction(this_is_a_very_long_parameter, + abc={a: b, b: c}) + """) + expected_formatted_code = textwrap.dedent("""\ + someLongFunction( + this_is_a_very_long_parameter, + abc={ + a: b, b: c + }) + """) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + actual_formatted_code = reformatter.Reformat(llines) + self.assertCodeEqual(expected_formatted_code, actual_formatted_code) + + # This tests when there is an embedded dictionary that will fit in a line, + # but FORCE_MULTILINE_DICT is set + style_dict['FORCE_MULTILINE_DICT'] = True + style.SetGlobalStyle(style_dict) + unformatted_code = textwrap.dedent("""\ + someLongFunction(this_is_a_very_long_parameter, + abc={a: b, b: c}) + """) + expected_formatted_code = textwrap.dedent("""\ + someLongFunction( + this_is_a_very_long_parameter, + abc={ + a: b, + b: c + }) + """) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + actual_formatted_code = reformatter.Reformat(llines) + self.assertCodeEqual(expected_formatted_code, actual_formatted_code) + + style_dict['FORCE_MULTILINE_DICT'] = original_multiline + style.SetGlobalStyle(style_dict) + # Exercise the case where there's no opening bracket (for a, b) unformatted_code = textwrap.dedent("""\ a, b = f( From b4821f882ffa922be3eb62cc911b249898787e03 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 25 Jul 2023 22:19:45 -0500 Subject: [PATCH 653/719] Fix 'line-too-long' warnings --- third_party/yapf_third_party/_ylib2to3/fixer_base.py | 3 ++- yapftests/reformatter_buganizer_test.py | 6 +++--- yapftests/reformatter_pep8_test.py | 6 +++--- yapftests/reformatter_python3_test.py | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/third_party/yapf_third_party/_ylib2to3/fixer_base.py b/third_party/yapf_third_party/_ylib2to3/fixer_base.py index 5214c023e..92fd0f699 100644 --- a/third_party/yapf_third_party/_ylib2to3/fixer_base.py +++ b/third_party/yapf_third_party/_ylib2to3/fixer_base.py @@ -169,7 +169,8 @@ def finish_tree(self, tree, filename): class ConditionalFix(BaseFix): """ Base class for fixers which not execute if an import is found. """ - # This is the name of the import which, if found, will cause the test to be skipped + # This is the name of the import which, if found, will cause the test to be + # skipped. skip_on = None def start_tree(self, *args): diff --git a/yapftests/reformatter_buganizer_test.py b/yapftests/reformatter_buganizer_test.py index 1efa81b75..fcfd78e02 100644 --- a/yapftests/reformatter_buganizer_test.py +++ b/yapftests/reformatter_buganizer_test.py @@ -344,7 +344,7 @@ def testB80484938(self): ('eeeeeeeeeeeeeeeeeeeeee', 'eeeeeeeeeeeeeeeeeeeeeeeeeee'), ]: pass - """) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -393,7 +393,7 @@ def testB79462249(self): aaaaaaaaaaaaaaaaaaaaaa=1, bbbbbbbbbbbbbbbbbbbbb=2, ccccccccccccccccccc=3) - """) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) @@ -645,7 +645,7 @@ def _(): k.TimestampMicros() / 1000000L) - m.Cond(m.VAL['start'] != 0, m.VAL['start'], m.TimestampMicros() / 1000000L))) - """) + """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index a027d99e2..65e506b5f 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -831,9 +831,9 @@ def testEnabled(self): def testWithSpaceInsideBrackets(self): style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{spaces_around_subscript_colon: true, space_inside_brackets: true,}' - )) # noqa + style.CreateStyleFromConfig("""\ + {spaces_around_subscript_colon: true, space_inside_brackets: true,} + """)) # noqa expected_formatted_code = textwrap.dedent("""\ a = list1[ : ] b = list2[ slice_start : ] diff --git a/yapftests/reformatter_python3_test.py b/yapftests/reformatter_python3_test.py index b2ec3353d..f5741b313 100644 --- a/yapftests/reformatter_python3_test.py +++ b/yapftests/reformatter_python3_test.py @@ -301,7 +301,7 @@ def open_file( def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None): pass - """) + """) # noqa try: style.SetGlobalStyle( From fa6ecd4f4d2f852870d0ba126a724a77f73d4a20 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 25 Jul 2023 22:33:17 -0500 Subject: [PATCH 654/719] Fix invalid style line syntax. --- yapftests/reformatter_pep8_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 65e506b5f..9f1ed4609 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -831,9 +831,9 @@ def testEnabled(self): def testWithSpaceInsideBrackets(self): style.SetGlobalStyle( - style.CreateStyleFromConfig("""\ - {spaces_around_subscript_colon: true, space_inside_brackets: true,} - """)) # noqa + style.CreateStyleFromConfig( + '{spaces_around_subscript_colon: true, ' + 'space_inside_brackets: true,}')) expected_formatted_code = textwrap.dedent("""\ a = list1[ : ] b = list2[ slice_start : ] From 9e090ddb8b8f63dfffb44af25bac96ba1687d858 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 26 Jul 2023 16:04:55 -0500 Subject: [PATCH 655/719] Fix formatting --- yapftests/reformatter_pep8_test.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/yapftests/reformatter_pep8_test.py b/yapftests/reformatter_pep8_test.py index 9f1ed4609..1cf7820e2 100644 --- a/yapftests/reformatter_pep8_test.py +++ b/yapftests/reformatter_pep8_test.py @@ -831,9 +831,8 @@ def testEnabled(self): def testWithSpaceInsideBrackets(self): style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{spaces_around_subscript_colon: true, ' - 'space_inside_brackets: true,}')) + style.CreateStyleFromConfig('{spaces_around_subscript_colon: true, ' + 'space_inside_brackets: true,}')) expected_formatted_code = textwrap.dedent("""\ a = list1[ : ] b = list2[ slice_start : ] From 2a539ea2dd4f4ffd207afdb98a07ea4fe99faf28 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Jul 2023 21:20:21 -0700 Subject: [PATCH 656/719] Actions(deps): Bump actions/setup-python from 4.6.1 to 4.7.0 (#1122) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4.6.1 to 4.7.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/bd6b4b6205c4dbad673328db7b31b7fab9e241c0...61a6322f88396a6271a6ee3565807d608ecaddd1) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/pre-commit-autoupdate.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79580d23f..6d0b3bc7d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.0 + uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.6.0 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index 15621c802..4bbb3a0a3 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: Set up Python 3.11 - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: 3.11 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index acf4d8a04..560999fd3 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: 3.11 From beb58770810987ba5ca5e999f0e2103712b3ad21 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Aug 2023 13:13:50 -0700 Subject: [PATCH 657/719] Actions(deps): Bump actions/checkout from 3.5.3 to 3.6.0 (#1128) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.3 to 3.6.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/c85c95e3d7251135ab7dc9ce3241c5835cc595a9...f43a0e5ff2bd294095638e18286ca9a3d1956744) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/pre-commit-autoupdate.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6d0b3bc7d..e3707b039 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: python-version: ["3.7", "3.8", "3.11"] # no particular need for 3.9 or 3.10 os: [macos-latest, ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.6.0 with: diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index 4bbb3a0a3..205e782de 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -19,7 +19,7 @@ jobs: name: Detect outdated pre-commit hooks runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - name: Set up Python 3.11 uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 560999fd3..ed0d8029a 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -19,7 +19,7 @@ jobs: name: Run pre-commit runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: From 16a1c36d854e8146d0f229768c2a4d0532dad289 Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Thu, 31 Aug 2023 15:59:51 -0400 Subject: [PATCH 658/719] Migrate to pyproject.toml (#1131) Migrate away from setuptools to pyproject.toml --- CHANGELOG => CHANGELOG.md | 1 + MANIFEST.in | 2 +- pyproject.toml | 61 ++++++++++++++++++++++ setup.py | 105 -------------------------------------- 4 files changed, 63 insertions(+), 106 deletions(-) rename CHANGELOG => CHANGELOG.md (99%) create mode 100644 pyproject.toml delete mode 100644 setup.py diff --git a/CHANGELOG b/CHANGELOG.md similarity index 99% rename from CHANGELOG rename to CHANGELOG.md index 70b3c9b91..eb5df20f3 100644 --- a/CHANGELOG +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - The verification module has been removed. NOTE: this changes the public APIs by removing the "verify" parameter. - Changed FORCE_MULTILINE_DICT to override SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES. +- Adopt pyproject.toml (PEP 517) for build system ## [0.40.1] 2023-06-20 ### Fixed diff --git a/MANIFEST.in b/MANIFEST.in index c88aedecb..26bd40ec3 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ -include HACKING.md LICENSE AUTHORS CHANGELOG CONTRIBUTING.md CONTRIBUTORS +include HACKING.md LICENSE AUTHORS CHANGELOG.md CONTRIBUTING.md CONTRIBUTORS include .coveragerc .editorconfig .flake8 plugins/README.md include plugins/vim/autoload/yapf.vim plugins/vim/plugin/yapf.vim pylintrc include .style.yapf tox.ini .travis.yml .vimrc diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..afc9ccc26 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,61 @@ +[build-system] +requires = ["setuptools>=58.5.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "yapf" +description = "A formatter for Python code" +authors = [{ name = "Google Inc." }] +maintainers = [{ name = "Bill Wendling", email = "morbo@google.com" }] +license = { file = "LICENSE" } +readme = "README.md" +requires-python = ">=3.7" +version = "0.40.1" +classifiers = [ + 'Development Status :: 4 - Beta', + 'Environment :: Console', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: Apache Software License', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3 :: Only', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Topic :: Software Development :: Libraries :: Python Modules', + 'Topic :: Software Development :: Quality Assurance', +] +dependencies = [ + 'importlib-metadata>=6.6.0', + 'platformdirs>=3.5.1', + 'tomli>=2.0.1', +] + +[project.scripts] +yapf = "yapf:run_main" +yapf-diff = "yapf_third_party.yapf_diff.yapf_diff:main" + +[project.urls] +url = 'https://github.com/google/yapf' +changelog = "https://github.com/google/yapf/blob/main/CHANGELOG.md" + +[tool.distutils.bdist_wheel] +python_tag = "py3" + +[tool.setuptools] +include-package-data = true +package-dir = { yapf_third_party = 'third_party/yapf_third_party' } + +[tool.setuptools.packages.find] +where = [".", 'third_party'] +include = ["yapf*", 'yapftests*'] + +[tool.setuptools.package-data] +yapf_third_party = [ + 'yapf_diff/LICENSE', + '_ylib2to3/Grammar.txt', + '_ylib2to3/PatternGrammar.txt', + '_ylib2to3/LICENSE', +] diff --git a/setup.py b/setup.py deleted file mode 100644 index 605b78a37..000000000 --- a/setup.py +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env python -# Copyright 2015 Google Inc. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import codecs -import sys -import unittest - -from setuptools import Command -from setuptools import find_packages -from setuptools import setup - - -class RunTests(Command): - user_options = [] - - def initialize_options(self): - pass - - def finalize_options(self): - pass - - def run(self): - loader = unittest.TestLoader() - tests = loader.discover('yapftests', pattern='*_test.py', top_level_dir='.') - runner = unittest.TextTestRunner() - results = runner.run(tests) - sys.exit(0 if results.wasSuccessful() else 1) - - -with codecs.open('README.md', 'r', 'utf-8') as fd: - setup( - name='yapf', - version='0.40.1', - description='A formatter for Python code.', - url='https://github.com/google/yapf', - long_description=fd.read(), - license='Apache License, Version 2.0', - author='Google Inc.', - maintainer='Bill Wendling', - maintainer_email='morbo@google.com', - options={'bdist_wheel': { - 'python_tag': 'py3' - }}, - packages=find_packages(where='.', include=['yapf*', 'yapftests*']) + - find_packages(where='third_party'), - package_dir={'yapf_third_party': 'third_party/yapf_third_party'}, - project_urls={ - 'Source': 'https://github.com/google/yapf', - }, - classifiers=[ - 'Development Status :: 4 - Beta', - 'Environment :: Console', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: Apache Software License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3 :: Only', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', - 'Topic :: Software Development :: Libraries :: Python Modules', - 'Topic :: Software Development :: Quality Assurance', - ], - entry_points={ - 'console_scripts': [ - 'yapf = yapf:run_main', - 'yapf-diff = yapf_third_party.yapf_diff.yapf_diff:main', - ], - }, - cmdclass={ - 'test': RunTests, - }, - package_data={ - 'yapf_third_party': [ - 'yapf_diff/LICENSE', - '_ylib2to3/Grammar.txt', - '_ylib2to3/PatternGrammar.txt', - '_ylib2to3/LICENSE', - ] - }, - include_package_data=True, - python_requires='>=3.7', - setup_requires=[ - 'setuptools>=58.5.0', # for include_package_data fix (issue #1107) - ], - install_requires=[ - 'importlib-metadata>=6.6.0', - 'platformdirs>=3.5.1', - 'tomli>=2.0.1', - ], - ) From 3b1d3dc5419865e7cca59ba473401769632b5f32 Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Thu, 31 Aug 2023 16:01:36 -0400 Subject: [PATCH 659/719] Add default workspace recommendations for vscode (#1130) Add default workspace recommendations for working on the YAPF project when using VSCode. This picks up @EeyoreLee's https://marketplace.visualstudio.com/items?itemName=eeyore.yapf as YAPF support is being dropped by VSCode's built-in python extension. This also uses @dangmai's https://marketplace.visualstudio.com/items?itemName=dangmai.workspace-default-settings to avoid messing with contributor's personal changes to settings.json. --- .vscode/extensions.json | 15 +++++++++++++++ .vscode/settings.default.json | 30 ++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.default.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000..f3f2fe836 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,15 @@ +{ + "recommendations": [ + "eeyore.yapf", + "dangmai.workspace-default-settings", + "ms-python.flake8", + "ms-python.isort", + "ms-python.python", + ], + // These are remarked as extenstions you should disable for this workspace. + // VSCode does not support disabling extensions via workspace config files. + "unwantedRecommendations": [ + "ms-python.black-formatter", + "ms-python.pylint" + ] +} diff --git a/.vscode/settings.default.json b/.vscode/settings.default.json new file mode 100644 index 000000000..002dd29e7 --- /dev/null +++ b/.vscode/settings.default.json @@ -0,0 +1,30 @@ +{ + "editor.codeActionsOnSave": { + "source.organizeImports": true + }, + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true, + "[python]": { + "diffEditor.ignoreTrimWhitespace": false, + "editor.defaultFormatter": "eeyore.yapf", + "editor.formatOnSaveMode": "file", + "editor.formatOnSave": true, + "editor.wordBasedSuggestions": false, + "files.trimTrailingWhitespace": true, + }, + "python.analysis.typeCheckingMode": "basic", + "python.languageServer": "Pylance", + "files.exclude": { + "**/*$py.class": true + }, + "json.schemas": [ + { + "fileMatch": [ + "/.vscode/settings.default.json" + ], + "url": "vscode://schemas/settings/folder" + } + ], + "workspace-default-settings.runOnActivation": true, + "workspace-default-settings.jsonIndentation": 4 +} From 6a7ba5a9a1dd504e124e1988004090ab5e58c18b Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Fri, 1 Sep 2023 18:40:13 -0400 Subject: [PATCH 660/719] Call unittest directly from tox.ini (#1133) Since moving to pyproject.toml tox began failing since the setup module had been removed. Instead we'll unittest directly from tox. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index e2e67a65a..3fcea7ed2 100644 --- a/tox.ini +++ b/tox.ini @@ -3,4 +3,4 @@ envlist=py37,py38,py39,py310 [testenv] commands= - python setup.py test + python -m unittest discover -p '*_test.py' yapftests/ From 61be4e8fbd77604a131e8a0813928a8fae0e7d48 Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Mon, 4 Sep 2023 06:09:40 -0400 Subject: [PATCH 661/719] Do not match keywords named 'match' (#1111) Closes #1110 , do not match variable names named 'match'. --------- Signed-off-by: Kyle Gottfried Co-authored-by: Charles Co-authored-by: Bill Wendling --- CHANGELOG.md | 1 + yapf/yapflib/format_decision_state.py | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb5df20f3..73911fb48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ by removing the "verify" parameter. - Changed FORCE_MULTILINE_DICT to override SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES. - Adopt pyproject.toml (PEP 517) for build system +- Do not treat variables named `match` as the match keyword ## [0.40.1] 2023-06-20 ### Fixed diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index a0d7033a3..bc7f977a7 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -27,6 +27,7 @@ """ from yapf.pytree import split_penalty +from yapf.pytree.pytree_utils import NodeName from yapf.yapflib import logical_line from yapf.yapflib import object_state from yapf.yapflib import style @@ -1101,15 +1102,26 @@ def _ContainerFitsOnStartLine(self, opening): _COMPOUND_STMTS = frozenset({ - 'for', 'while', 'if', 'elif', 'with', 'except', 'def', 'class', 'match', - 'case' + 'for', + 'while', + 'if', + 'elif', + 'with', + 'except', + 'def', + 'class', }) def _IsCompoundStatement(token): - if token.value == 'async': + value = token.value + if value == 'async': token = token.next_token - return token.value in _COMPOUND_STMTS + if token.value in _COMPOUND_STMTS: + return True + parent_name = NodeName(token.node.parent) + return value == 'match' and parent_name == 'match_stmt' or \ + value == 'case' and parent_name == 'case_stmt' def _IsFunctionDef(token): From 7c72e0b2c4a1bc00378fa5132bf3f863f595bb9e Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Mon, 18 Sep 2023 17:31:44 -0400 Subject: [PATCH 662/719] Add `Editor support.md` (#1135) Add instructions for common editors. Closes #1124 and #1125 --- EDITOR SUPPORT.md | 82 +++++++++++++++++++++++++++++++++++++++++++++++ README.md | 3 ++ 2 files changed, 85 insertions(+) create mode 100644 EDITOR SUPPORT.md diff --git a/EDITOR SUPPORT.md b/EDITOR SUPPORT.md new file mode 100644 index 000000000..b6f7acb2e --- /dev/null +++ b/EDITOR SUPPORT.md @@ -0,0 +1,82 @@ +# Using YAPF with your editor + +YAPF is supported by multiple editors via community extensions or plugins. + +- [IntelliJ/PyCharm](#intellijpycharm) +- [IPython](#ipython) +- [VSCode](#vscode) + +## IntelliJ/PyCharm + +Use the `File Watchers` plugin to run YAPF against a file when you perform a save. + +1. Install the [File Watchers](https://www.jetbrains.com/help/idea/using-file-watchers.html) Plugin +1. Add the following `.idea/watcherTasks.xml` to your project. If you already have this file just add the `TaskOptions` section from below. This example uses Windows and a virtual environment, modify the `program` option as appropriate. + ```xml + + + + + + + + + ``` + +## IPython + +IPython supports formatting lines automatically when you press the `` button to submit the current code block. + +Make sure that the YAPF module is available to the IPython runtime: + +```shell +pip install ipython yapf +``` + +pipx example: + +```shell +pipx install ipython +pipx inject ipython yapf +``` + +Add following to `~/.ipython/profile_default/ipython_config.py`: + +```python +c.TerminalInteractiveShell.autoformatter = 'yapf' +``` + +## VSCode + +VSCode has deprecated support for YAPF in its official Python extension [in favor of dedicated formatter extensions](https://github.com/microsoft/vscode-python/wiki/Migration-to-Python-Tools-Extensions). + +1. Install EeyoreLee's [yapf](https://marketplace.visualstudio.com/items?itemName=eeyore.yapf) extension. +1. Install the yapf package from pip. + ``` + pip install yapf + ``` +1. Add the following to VSCode's `settings.json`: + ```jsonc + "[python]": { + "editor.formatOnSaveMode": "file", + "editor.formatOnSave": true, + "editor.defaultFormatter": "eeyore.yapf" # choose this extension + }, + ``` diff --git a/README.md b/README.md index bd03fd284..34ee8b02b 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,9 @@ optional arguments: -vv, --verbose print out file names while processing ``` +### Using YAPF within your favorite editor +YAPF is supported by multiple editors via community extensions or plugins. See [Editor Support](EDITOR%20SUPPORT.md) for more info. + ### Return Codes Normally YAPF returns zero on successful program termination and non-zero From 1323865c15e1c476d227fc56b672154a6de8345b Mon Sep 17 00:00:00 2001 From: Alexey Pelykh Date: Tue, 19 Sep 2023 23:26:34 +0200 Subject: [PATCH 663/719] Fix SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED for one-item argument lists (#1142) Turn r = f0(1,) into r = f0( 1, ) in case SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED is enabled --- CHANGELOG.md | 2 ++ yapf/yapflib/reformatter.py | 9 +++++++-- yapftests/reformatter_basic_test.py | 6 ++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73911fb48..9beed29f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,9 @@ by removing the "verify" parameter. - Changed FORCE_MULTILINE_DICT to override SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES. - Adopt pyproject.toml (PEP 517) for build system +### Fixed - Do not treat variables named `match` as the match keyword +- Fix SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED for one-item argument lists. ## [0.40.1] 2023-06-20 ### Fixed diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 319fc9cc0..ff0952543 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -245,8 +245,13 @@ def _CanPlaceOnSingleLine(line): Returns: True if the line can or should be added to a single line. False otherwise. """ - token_names = [x.name for x in line.tokens] - if (style.Get('FORCE_MULTILINE_DICT') and 'LBRACE' in token_names): + token_types = [x.type for x in line.tokens] + if (style.Get('SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED') and + any(token_types[token_index - 1] == token.COMMA + for token_index, token_type in enumerate(token_types[1:], start=1) + if token_type == token.RPAR)): + return False + if (style.Get('FORCE_MULTILINE_DICT') and token.LBRACE in token_types): return False indent_amt = style.Get('INDENT_WIDTH') * line.depth last = line.last diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index aae46d6ff..c2200a95e 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2275,6 +2275,8 @@ def testSplittingArgumentsTerminatedByComma(self): a_very_long_function_name(long_argument_name_1, long_argument_name_2, long_argument_name_3, long_argument_name_4,) r =f0 (1, 2,3,) + + r =f0 (1,) """) # noqa expected_formatted_code = textwrap.dedent("""\ function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3) @@ -2303,6 +2305,10 @@ def testSplittingArgumentsTerminatedByComma(self): 2, 3, ) + + r = f0( + 1, + ) """) try: From bc6772d0d89d9ab7f2db4702fd95ec2b582e401e Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Thu, 21 Sep 2023 15:57:41 -0400 Subject: [PATCH 664/719] pyproject.toml updates to HACKING.md (#1134) Setup module is missing, use build instead. Run tests with tox. --- .gitattributes | 1 + .python-version | 5 ++++ HACKING.md | 69 +++++++++++++++++++++++++++++++------------------ tox.ini | 19 +++++++++++--- 4 files changed, 66 insertions(+), 28 deletions(-) create mode 100644 .gitattributes create mode 100644 .python-version diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..5bb982c51 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +.python-version eol=lf diff --git a/.python-version b/.python-version new file mode 100644 index 000000000..f4bd916f2 --- /dev/null +++ b/.python-version @@ -0,0 +1,5 @@ +3.7.9 +3.8.10 +3.9.13 +3.10.11 +3.11.5 diff --git a/HACKING.md b/HACKING.md index 7499c8657..c970d3cdb 100644 --- a/HACKING.md +++ b/HACKING.md @@ -12,45 +12,64 @@ $ PYTHONPATH=$PWD/yapf python -m yapf -i -r . $ PYTHONPATH=$PWD/yapf python -m yapf -i $(git diff --name-only @{upstream}) ``` -## Releasing a new version +## Testing and building redistributables locally + +YAPF uses tox 3 to test against multiple python versions and to build redistributables. -- Run tests with Python 3.7 and 3.11: +Tox will opportunistically use pyenv environments when available. +To configure pyenv run the following in bash: ```bash -$ python setup.py test +$ xargs -t -n1 pyenv install < .python-version ``` -- Bump version in `setup.py`. - -- Build source distribution: +Test against all supported Python versions that are currently installed: +```bash +$ pipx run --spec='tox<4' tox +``` +Build and test the sdist and wheel against your default Python environment. The redistributables will be in the `dist` directory. ```bash -$ python setup.py sdist +$ tox -e bdist_wheel -e sdist ``` -- Check that it looks OK. - - Install it onto a virtualenv, - - run tests, and - - run yapf as a tool. +## Releasing a new version -- Build release: +1. Install all expected pyenv environements + ```bash + $ xargs -t -n1 pyenv install < .python-version + ``` -```bash -$ python setup.py sdist bdist_wheel -``` +1. Run tests against Python 3.7 - 3.11 with + ```bash + $ pipx run --spec='tox<4' tox + ``` -- Push to PyPI: +1. Bump version in `pyproject.toml`. -```bash -$ twine upload dist/* -``` +1. Build and test redistributables + + ```bash + $ pipx run --spec='tox<4' tox -e bdist_wheel -e sdist + ``` + +1. Check that it looks OK. + 1. Install it onto a virtualenv, + 1. run tests, and + 1. run yapf as a tool. -- Test in a clean virtualenv that 'pip install yapf' works with the new +1. Push to PyPI: + + ```bash + $ pipx run twine upload dist/* + ``` + +1. Test in a clean virtualenv that 'pip install yapf' works with the new version. -- Commit the version bump and add tag with: +1. Commit the version bump and add tag with: -```bash -$ git tag v$(VERSION_NUM) -$ git push --tags -``` + ```bash + $ git tag v$(VERSION_NUM) + $ git push --tags + ``` diff --git a/tox.ini b/tox.ini index 3fcea7ed2..ebf2d030e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,19 @@ [tox] -envlist=py37,py38,py39,py310 +requires = + tox<4 + tox-pyenv + tox-wheel +envlist = py37,py38,py39,py310,py311 +# tox-wheel alias for `wheel_pep517 = true` +isolated_build = True +distshare = ./dist [testenv] -commands= - python -m unittest discover -p '*_test.py' yapftests/ +wheel = True +wheel_build_env = bdist_wheel +commands = python -m unittest discover -p '*_test.py' yapftests/ + +[testenv:bdist_wheel] + +[testenv:sdist] +wheel = False From 1c714b931fc1b7e17caea298a8adcd00e0891840 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Sep 2023 13:23:11 -0700 Subject: [PATCH 665/719] pre-commit: Autoupdate (#1123) Co-authored-by: pre-commit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 324807931..53ddc1692 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,7 +16,7 @@ repos: args: [-i] types: [python] - repo: https://github.com/pycqa/flake8 - rev: 6.0.0 + rev: 6.1.0 hooks: - id: flake8 - repo: https://github.com/pre-commit/pre-commit-hooks From 1e2171ac569721936709c78741a458df3d1b26cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Sep 2023 17:08:14 -0700 Subject: [PATCH 666/719] Actions(deps): Bump actions/checkout from 3.6.0 to 4.0.0 (#1141) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.6.0 to 4.0.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/f43a0e5ff2bd294095638e18286ca9a3d1956744...3df4ab11eba7bda6032a0b82a6bb43b11571feac) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/pre-commit-autoupdate.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e3707b039..ed99c16b8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: python-version: ["3.7", "3.8", "3.11"] # no particular need for 3.9 or 3.10 os: [macos-latest, ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.6.0 with: diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index 205e782de..23eeed1f2 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -19,7 +19,7 @@ jobs: name: Detect outdated pre-commit hooks runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - name: Set up Python 3.11 uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index ed0d8029a..22097c6a4 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -19,7 +19,7 @@ jobs: name: Run pre-commit runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: From 4eb9e1a433c3f4e598097e6c2c1823d643d4911b Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 21 Sep 2023 17:22:13 -0700 Subject: [PATCH 667/719] Use 'isinstance' to avoid PEP error --- third_party/yapf_third_party/_ylib2to3/pytree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/yapf_third_party/_ylib2to3/pytree.py b/third_party/yapf_third_party/_ylib2to3/pytree.py index 0fcdf4b2c..ea9767be9 100644 --- a/third_party/yapf_third_party/_ylib2to3/pytree.py +++ b/third_party/yapf_third_party/_ylib2to3/pytree.py @@ -32,7 +32,7 @@ def type_repr(type_num): # printing tokens is possible but not as useful # from .pgen2 import token // token.__dict__.items(): for name, val in python_symbols.__dict__.items(): - if type(val) == int: + if isinstance(val, int): _type_reprs[val] = name return _type_reprs.setdefault(type_num, type_num) From 250e4ebcb2e595a2a234c49b4cab062d29d0d4a4 Mon Sep 17 00:00:00 2001 From: Earlee Date: Sat, 23 Sep 2023 01:42:15 +0800 Subject: [PATCH 668/719] fix trailing backslash stripped cause windows linesep (#1140) Fix trailing backslash stripped because of Windows line separator. Closes #1139 --- yapf/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/__init__.py b/yapf/__init__.py index d6cde95a0..ebbc75862 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -114,7 +114,7 @@ def main(argv): try: reformatted_source, _ = yapf_api.FormatCode( - str('\n'.join(source) + '\n'), + str('\n'.join(source).replace('\r\n', '\n') + '\n'), filename='', style_config=style_config, lines=lines) From 5428012fe91c8c9da251227d7c58c96c4af7473b Mon Sep 17 00:00:00 2001 From: Bill Wendling <5993918+bwendling@users.noreply.github.com> Date: Fri, 22 Sep 2023 10:44:51 -0700 Subject: [PATCH 669/719] Update CHANGELOG.md Add comment for b8fd5a4. --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9beed29f3..60eab7824 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,15 +2,16 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.41.0] UNRELEASED +## [0.41.2] UNRELEASED ### Changes - The verification module has been removed. NOTE: this changes the public APIs by removing the "verify" parameter. - Changed FORCE_MULTILINE_DICT to override SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES. - Adopt pyproject.toml (PEP 517) for build system ### Fixed -- Do not treat variables named `match` as the match keyword +- Do not treat variables named `match` as the match keyword. - Fix SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED for one-item argument lists. +- Fix trailing backslash-newline on Windows when using stdin. ## [0.40.1] 2023-06-20 ### Fixed From 5fc2b7a73726a90e285bcbdba313e2ece99eafc9 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Fri, 22 Sep 2023 11:34:58 -0700 Subject: [PATCH 670/719] Bump version to 0.40.2 --- CHANGELOG.md | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60eab7824..25c36347b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## [0.41.2] UNRELEASED +## [0.40.2] 2023-09-22 ### Changes - The verification module has been removed. NOTE: this changes the public APIs by removing the "verify" parameter. diff --git a/pyproject.toml b/pyproject.toml index afc9ccc26..7d0366fe4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ maintainers = [{ name = "Bill Wendling", email = "morbo@google.com" }] license = { file = "LICENSE" } readme = "README.md" requires-python = ">=3.7" -version = "0.40.1" +version = "0.40.2" classifiers = [ 'Development Status :: 4 - Beta', 'Environment :: Console', From e6b591675aa7496418c991266e9305394940a14e Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Fri, 22 Sep 2023 17:49:34 -0400 Subject: [PATCH 671/719] Add additional project URLs (#1147) Using https://daniel.feldroy.com/posts/2023-08-pypi-project-urls-cheatsheet and https://github.com/pypi/warehouse/blob/70eac9796fa1eae24741525688a112586eab9010/warehouse/templates/packaging/detail.html#L20-L62 as a reference add additional project URLs. --- pyproject.toml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7d0366fe4..04519ae24 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,8 +38,11 @@ yapf = "yapf:run_main" yapf-diff = "yapf_third_party.yapf_diff.yapf_diff:main" [project.urls] -url = 'https://github.com/google/yapf' -changelog = "https://github.com/google/yapf/blob/main/CHANGELOG.md" +# https://daniel.feldroy.com/posts/2023-08-pypi-project-urls-cheatsheet +Home = 'https://github.com/google/yapf' +Changelog = 'https://github.com/google/yapf/blob/main/CHANGELOG.md' +Docs = 'https://github.com/google/yapf/blob/main/README.md#yapf' +Issues = 'https://github.com/google/yapf/issues' [tool.distutils.bdist_wheel] python_tag = "py3" From 107bd1a8904d5f54467083485108e528f9cf345b Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Fri, 22 Sep 2023 17:54:58 -0400 Subject: [PATCH 672/719] Update CONTRIBUTING.md -- add Getting started section (#1148) --- CONTRIBUTING.md | 8 ++++++++ CONTRIBUTORS | 1 + HACKING.md | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a15c350fe..4c0273cd4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -35,6 +35,14 @@ with two exceptions: The rationale for this is that YAPF was initially developed at Google where these two exceptions are still part of the internal Python style guide. +## Getting started +YAPF supports using tox 3 for creating a local dev environment, testing, and +building redistributables. See [HACKING.md](HACKING.md) for more info. + +```bash +$ pipx run --spec='tox<4' tox --devenv .venv +``` + ## Small print Contributions made by corporations are covered by a different agreement than diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 054ef2652..fe6f13d3b 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -15,3 +15,4 @@ Sam Clegg Ɓukasz Langa Oleg Butuzov Mauricio Herrera Cuadra +Kyle Gottfried diff --git a/HACKING.md b/HACKING.md index c970d3cdb..336b234bd 100644 --- a/HACKING.md +++ b/HACKING.md @@ -30,7 +30,7 @@ $ pipx run --spec='tox<4' tox Build and test the sdist and wheel against your default Python environment. The redistributables will be in the `dist` directory. ```bash -$ tox -e bdist_wheel -e sdist +$ pipx run --spec='tox<4' tox -e bdist_wheel -e sdist ``` ## Releasing a new version From 7ef32ce2bf82c6b81ee30e786aa681e9ebf00cca Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Mon, 25 Sep 2023 04:19:21 -0400 Subject: [PATCH 673/719] copy globals() (#1150) Fixes #1118. Use a copy of globals() rather than a direct reference. This did not appear to impact the time of tests --- third_party/yapf_third_party/_ylib2to3/pgen2/token.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/third_party/yapf_third_party/_ylib2to3/pgen2/token.py b/third_party/yapf_third_party/_ylib2to3/pgen2/token.py index 5d099707e..fbcd15525 100644 --- a/third_party/yapf_third_party/_ylib2to3/pgen2/token.py +++ b/third_party/yapf_third_party/_ylib2to3/pgen2/token.py @@ -69,10 +69,11 @@ NT_OFFSET = 256 # --end constants-- -tok_name = {} -for _name, _value in list(globals().items()): - if isinstance(_value, int): - tok_name[_value] = _name +tok_name = { + _value: _name + for _name, _value in globals().copy().items() + if isinstance(_value, int) +} def ISTERMINAL(x): From ce7f970b40d380647bc69ef02b01e0afe91a11ff Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Tue, 26 Sep 2023 16:23:47 -0400 Subject: [PATCH 674/719] =?UTF-8?q?Move=20=E2=80=9Cuse=20within=20your=20f?= =?UTF-8?q?avorite=20editor=E2=80=9D=20to=20an=20earlier=20section=20in=20?= =?UTF-8?q?README.md=20(#1153)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This section’s current place between Usage and Return codes doesn’t make much sense. Better off front loading as early as reasonable how to YAPF editor integrations. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 34ee8b02b..f1d9e368d 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,8 @@ possible to run: $ PYTHONPATH=DIR python DIR/yapf [options] ... ``` +## Using YAPF within your favorite editor +YAPF is supported by multiple editors via community extensions or plugins. See [Editor Support](EDITOR%20SUPPORT.md) for more info. ## Required Python versions @@ -92,8 +94,6 @@ optional arguments: -vv, --verbose print out file names while processing ``` -### Using YAPF within your favorite editor -YAPF is supported by multiple editors via community extensions or plugins. See [Editor Support](EDITOR%20SUPPORT.md) for more info. ### Return Codes From 3490693654dcbc16f1718fc538a34e333615ae14 Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Fri, 29 Sep 2023 17:19:09 -0400 Subject: [PATCH 675/719] Update CHANGELOG.md - mark YANKED versions (#1157) Both 0.33.0 and 0.40.0 were yanked due to packaging issues. Caused by #1107 and #1154 --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25c36347b..3daffcc6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ ### Fixed - Corrected bad distribution v0.40.0 package. -## [0.40.0] 2023-06-13 +## [0.40.0] 2023-06-13 [YANKED - [#1107](https://github.com/google/yapf/issues/1107)] ### Added - Support for Python 3.11 - Add the `--print-modified` flag to print out file names of modified files when @@ -28,7 +28,7 @@ ### Removed - Support for Python versions < 3.7 are no longer supported. -## [0.33.0] 2023-04-18 +## [0.33.0] 2023-04-18 [YANKED - [#1154](https://github.com/google/yapf/issues/1154)] ### Added - Add a new Python parser to generate logical lines. - Added support for `# fmt: on` and `# fmt: off` pragmas. From 90ffbbd02016693a051ed63846d47b39b79df7d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Sep 2023 14:23:58 -0700 Subject: [PATCH 676/719] Actions(deps): Bump actions/checkout from 4.0.0 to 4.1.0 (#1156) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.0.0 to 4.1.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/3df4ab11eba7bda6032a0b82a6bb43b11571feac...8ade135a41bc03ea155e62e844d188df1ea18608) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/pre-commit-autoupdate.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed99c16b8..9dfd38db3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: python-version: ["3.7", "3.8", "3.11"] # no particular need for 3.9 or 3.10 os: [macos-latest, ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.6.0 with: diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index 23eeed1f2..ffc4bb5f0 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -19,7 +19,7 @@ jobs: name: Detect outdated pre-commit hooks runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - name: Set up Python 3.11 uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 22097c6a4..be90b7acd 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -19,7 +19,7 @@ jobs: name: Run pre-commit runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: From b31a4b55b57cafb0661448a07749a931300a69c5 Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Tue, 10 Oct 2023 17:19:00 -0400 Subject: [PATCH 677/719] #1131 fix for #1121 did not fix vscode behavior on ubuntu (#1149) So while migrating to pyproject.toml fixed editable installation behavior on Ubuntu, Pylance was still unable to figure out imports as vscode does not understand the import script .venv/lib/python3.10/site-packages/__editable___yapf_0_40_2_finder.py created by an editable install triggered by pip install -m venv .venv Using https://microsoft.github.io/pyright/#/import-resolution?id=setuptools suggestions of compat and strict mode did not resolve issues either. So instead I revert to manually adding third_party to the python.analysis.extraPaths setting in settings.json --- .vscode/settings.default.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.vscode/settings.default.json b/.vscode/settings.default.json index 002dd29e7..502f59d95 100644 --- a/.vscode/settings.default.json +++ b/.vscode/settings.default.json @@ -12,6 +12,9 @@ "editor.wordBasedSuggestions": false, "files.trimTrailingWhitespace": true, }, + "python.analysis.extraPaths": [ + "./third_party" + ], "python.analysis.typeCheckingMode": "basic", "python.languageServer": "Pylance", "files.exclude": { From 4632ddfd6a9b1a1309f4612168b665102f094071 Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Tue, 10 Oct 2023 17:26:17 -0400 Subject: [PATCH 678/719] Feature/no import third party provided by stdlib (#1158) Remove dependency on importlib-metadata. Remove dependency on tomli when using >= py311 --- CHANGELOG.md | 6 ++++++ HACKING.md | 6 +++--- pyproject.toml | 11 +++++------ .../yapf_third_party/_ylib2to3/pgen2/driver.py | 10 +++------- yapf/__init__.py | 5 +---- yapf/_version.py | 1 + yapf/yapflib/file_resources.py | 18 +++++------------- yapf/yapflib/style.py | 13 ++++++------- yapftests/file_resources_test.py | 18 ------------------ yapftests/style_test.py | 9 --------- 10 files changed, 30 insertions(+), 67 deletions(-) create mode 100644 yapf/_version.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 3daffcc6b..14f671fb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). +## (0.40.3) UNRELEASED +### Changes +- Remove dependency on importlib-metadata +- Remove dependency on tomli when using >= py311 + + ## [0.40.2] 2023-09-22 ### Changes - The verification module has been removed. NOTE: this changes the public APIs diff --git a/HACKING.md b/HACKING.md index 336b234bd..1c03e8008 100644 --- a/HACKING.md +++ b/HACKING.md @@ -3,13 +3,13 @@ - To run YAPF on all of YAPF: ```bash -$ PYTHONPATH=$PWD/yapf python -m yapf -i -r . +$ pipx run --spec=${PWD} --no-cache yapf -m -i -r yapf/ yapftests/ third_party/ ``` - To run YAPF on just the files changed in the current git branch: ```bash -$ PYTHONPATH=$PWD/yapf python -m yapf -i $(git diff --name-only @{upstream}) +$ pipx run --spec=${PWD} --no-cache yapf -m -i $(git diff --name-only @{upstream}) ``` ## Testing and building redistributables locally @@ -45,7 +45,7 @@ $ pipx run --spec='tox<4' tox -e bdist_wheel -e sdist $ pipx run --spec='tox<4' tox ``` -1. Bump version in `pyproject.toml`. +1. Bump version in `yapf/_version.py`. 1. Build and test redistributables diff --git a/pyproject.toml b/pyproject.toml index 04519ae24..0b4bde36c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,10 +7,10 @@ name = "yapf" description = "A formatter for Python code" authors = [{ name = "Google Inc." }] maintainers = [{ name = "Bill Wendling", email = "morbo@google.com" }] +dynamic = ["version"] license = { file = "LICENSE" } readme = "README.md" requires-python = ">=3.7" -version = "0.40.2" classifiers = [ 'Development Status :: 4 - Beta', 'Environment :: Console', @@ -27,11 +27,7 @@ classifiers = [ 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Quality Assurance', ] -dependencies = [ - 'importlib-metadata>=6.6.0', - 'platformdirs>=3.5.1', - 'tomli>=2.0.1', -] +dependencies = ['platformdirs>=3.5.1', 'tomli>=2.0.1; python_version<"3.11"'] [project.scripts] yapf = "yapf:run_main" @@ -51,6 +47,9 @@ python_tag = "py3" include-package-data = true package-dir = { yapf_third_party = 'third_party/yapf_third_party' } +[tool.setuptools.dynamic] +version = { attr = "yapf._version.__version__" } + [tool.setuptools.packages.find] where = [".", 'third_party'] include = ["yapf*", 'yapftests*'] diff --git a/third_party/yapf_third_party/_ylib2to3/pgen2/driver.py b/third_party/yapf_third_party/_ylib2to3/pgen2/driver.py index 9345fe5aa..76b31a11c 100644 --- a/third_party/yapf_third_party/_ylib2to3/pgen2/driver.py +++ b/third_party/yapf_third_party/_ylib2to3/pgen2/driver.py @@ -20,20 +20,19 @@ import pkgutil import sys # Python imports -from configparser import ConfigParser from contextlib import contextmanager from dataclasses import dataclass from dataclasses import field from pathlib import Path -from pkgutil import get_data from typing import Any from typing import Iterator from typing import List from typing import Optional -from importlib_metadata import metadata from platformdirs import user_cache_dir +from yapf._version import __version__ as yapf_version + # Pgen imports from . import grammar from . import parse @@ -207,10 +206,7 @@ def _generate_pickle_name(gt): if tail == '.txt': tail = '' cache_dir = user_cache_dir( - appname=metadata('yapf')['Name'].upper(), - appauthor=metadata('yapf')['Author'].split(' ')[0], - version=metadata('yapf')['Version'], - ) + appname='YAPF', appauthor='Google', version=yapf_version) return cache_dir + os.sep + head + tail + '-py' + '.'.join( map(str, sys.version_info)) + '.pickle' diff --git a/yapf/__init__.py b/yapf/__init__.py index ebbc75862..cf4be9379 100644 --- a/yapf/__init__.py +++ b/yapf/__init__.py @@ -33,15 +33,12 @@ import os import sys -from importlib_metadata import metadata - +from yapf._version import __version__ from yapf.yapflib import errors from yapf.yapflib import file_resources from yapf.yapflib import style from yapf.yapflib import yapf_api -__version__ = metadata('yapf')['Version'] - def _raw_input(): wrapper = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8') diff --git a/yapf/_version.py b/yapf/_version.py new file mode 100644 index 000000000..ccd8b38ef --- /dev/null +++ b/yapf/_version.py @@ -0,0 +1 @@ +__version__ = '0.42.0' diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 977a2568f..66ab707ac 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -28,6 +28,11 @@ from yapf.yapflib import errors from yapf.yapflib import style +if sys.version_info >= (3, 11): + import tomllib +else: + import tomli as tomllib + CR = '\r' LF = '\n' CRLF = '\r\n' @@ -51,12 +56,6 @@ def _GetExcludePatternsFromYapfIgnore(filename): def _GetExcludePatternsFromPyprojectToml(filename): """Get a list of file patterns to ignore from pyproject.toml.""" ignore_patterns = [] - try: - import tomli as tomllib - except ImportError: - raise errors.YapfError( - 'tomli package is needed for using pyproject.toml as a ' - 'configuration file') if os.path.isfile(filename) and os.access(filename, os.R_OK): with open(filename, 'rb') as fd: @@ -136,13 +135,6 @@ def GetDefaultStyleForDir(dirname, default_style=style.DEFAULT_STYLE): pass # It's okay if it's not there. else: with fd: - try: - import tomli as tomllib - except ImportError: - raise errors.YapfError( - 'tomli package is needed for using pyproject.toml as a ' - 'configuration file') - pyproject_toml = tomllib.load(fd) style_dict = pyproject_toml.get('tool', {}).get('yapf', None) if style_dict is not None: diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index 72f277b25..b43437ee0 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -15,11 +15,17 @@ import os import re +import sys import textwrap from configparser import ConfigParser from yapf.yapflib import errors +if sys.version_info >= (3, 11): + import tomllib +else: + import tomli as tomllib + class StyleConfigError(errors.YapfError): """Raised when there's a problem reading the style configuration.""" @@ -791,13 +797,6 @@ def _CreateConfigParserFromConfigFile(config_filename): config = ConfigParser() if config_filename.endswith(PYPROJECT_TOML): - try: - import tomli as tomllib - except ImportError: - raise errors.YapfError( - 'tomli package is needed for using pyproject.toml as a ' - 'configuration file') - with open(config_filename, 'rb') as style_file: pyproject_toml = tomllib.load(style_file) style_dict = pyproject_toml.get('tool', {}).get('yapf', None) diff --git a/yapftests/file_resources_test.py b/yapftests/file_resources_test.py index c55333f9d..e71742c6a 100644 --- a/yapftests/file_resources_test.py +++ b/yapftests/file_resources_test.py @@ -76,10 +76,6 @@ def test_get_exclude_file_patterns_from_yapfignore_with_wrong_syntax(self): file_resources.GetExcludePatternsForDir(self.test_tmpdir) def test_get_exclude_file_patterns_from_pyproject(self): - try: - import tomli - except ImportError: - return local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') ignore_patterns = ['temp/**/*.py', 'temp2/*.py'] with open(local_ignore_file, 'w') as f: @@ -93,10 +89,6 @@ def test_get_exclude_file_patterns_from_pyproject(self): sorted(ignore_patterns)) def test_get_exclude_file_patterns_from_pyproject_no_ignore_section(self): - try: - import tomli - except ImportError: - return local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') ignore_patterns = [] open(local_ignore_file, 'w').close() @@ -106,10 +98,6 @@ def test_get_exclude_file_patterns_from_pyproject_no_ignore_section(self): sorted(ignore_patterns)) def test_get_exclude_file_patterns_from_pyproject_ignore_section_empty(self): - try: - import tomli - except ImportError: - return local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') ignore_patterns = [] with open(local_ignore_file, 'w') as f: @@ -175,12 +163,6 @@ def test_setup_config(self): file_resources.GetDefaultStyleForDir(test_dir)) def test_pyproject_toml(self): - # An empty pyproject.toml file should not be used - try: - import tomli - except ImportError: - return - pyproject_toml = os.path.join(self.test_tmpdir, 'pyproject.toml') open(pyproject_toml, 'w').close() diff --git a/yapftests/style_test.py b/yapftests/style_test.py index 10c62edc6..64e64a5be 100644 --- a/yapftests/style_test.py +++ b/yapftests/style_test.py @@ -229,11 +229,6 @@ def testErrorUnknownStyleOption(self): style.CreateStyleFromConfig(filepath) def testPyprojectTomlNoYapfSection(self): - try: - import tomli # noqa: F401 - except ImportError: - return - filepath = os.path.join(self.test_tmpdir, 'pyproject.toml') _ = open(filepath, 'w') with self.assertRaisesRegex(style.StyleConfigError, @@ -241,10 +236,6 @@ def testPyprojectTomlNoYapfSection(self): style.CreateStyleFromConfig(filepath) def testPyprojectTomlParseYapfSection(self): - try: - import tomli # noqa: F401 - except ImportError: - return cfg = textwrap.dedent("""\ [tool.yapf] From ce36a8e0aaf9c3f51b7bf8f903198a7d54abd679 Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Tue, 10 Oct 2023 17:28:21 -0400 Subject: [PATCH 679/719] using ylib2to3 means we can test <=py311 on any python version supported by YAPF (#1162) Since we're using ylib2to3 instead of lib2to3 this means we can test <=py311 on any python version supported by YAPF. [] remove language in Readme that says YAPF must run as the same version of Python as the code you're formatting. --- .github/workflows/ci.yml | 2 +- yapftests/reformatter_basic_test.py | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9dfd38db3..58b946441 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: ["3.7", "3.8", "3.11"] # no particular need for 3.9 or 3.10 + python-version: ["3.7", "3.11", "3.12"] # no particular need for 3.9 or 3.10 os: [macos-latest, ubuntu-latest, windows-latest] steps: - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index c2200a95e..ebc2cd3ee 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -22,9 +22,6 @@ from yapftests import yapf_test_helper -PY38 = sys.version_info[0] >= 3 and sys.version_info[1] >= 8 -PY310 = sys.version_info[0] >= 3 and sys.version_info[1] >= 10 - class BasicReformatterTest(yapf_test_helper.YAPFTest): @@ -3217,7 +3214,6 @@ def testForceMultilineDict_False(self): finally: style.SetGlobalStyle(style.CreateYapfStyle()) - @unittest.skipUnless(PY38, 'Requires Python 3.8') def testWalrus(self): unformatted_code = textwrap.dedent("""\ if (x := len([1]*1000)>100): @@ -3230,7 +3226,6 @@ def testWalrus(self): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected, reformatter.Reformat(llines)) - @unittest.skipUnless(PY310, 'Requires Python 3.10') def testStructuredPatternMatching(self): unformatted_code = textwrap.dedent("""\ match command.split(): @@ -3249,7 +3244,6 @@ def testStructuredPatternMatching(self): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected, reformatter.Reformat(llines)) - @unittest.skipUnless(PY310, 'Requires Python 3.10') def testParenthesizedContextManagers(self): unformatted_code = textwrap.dedent("""\ with (cert_authority.cert_pem.tempfile() as ca_temp_path, patch.object(os, 'environ', os.environ | {'REQUESTS_CA_BUNDLE': ca_temp_path}),): From 31b3e5f86d303fe010e1513c855ecb75f89323a0 Mon Sep 17 00:00:00 2001 From: Alexey Pelykh Date: Tue, 10 Oct 2023 23:48:12 +0200 Subject: [PATCH 680/719] Fix SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED for one-item named argument lists by taking precedence over SPLIT_BEFORE_NAMED_ASSIGNS (#1160) By taking precedence over SPLIT_BEFORE_NAMED_ASSIGNS, turn r = f0(a=1,) into r = f0( a=1, ) --- CHANGELOG.md | 4 +++- yapf/yapflib/format_decision_state.py | 19 ++++++++++--------- yapftests/reformatter_basic_test.py | 6 ++++++ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14f671fb7..d8127cf62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,9 @@ ### Changes - Remove dependency on importlib-metadata - Remove dependency on tomli when using >= py311 - +### Fixed +- Fix SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED for one-item named argument lists + by taking precedence over SPLIT_BEFORE_NAMED_ASSIGNS. ## [0.40.2] 2023-09-22 ### Changes diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index bc7f977a7..ce743139a 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -373,6 +373,16 @@ def SurroundedByParens(token): ########################################################################### # Argument List Splitting + + if style.Get('SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED'): + # Split before arguments in a function call or definition if the + # arguments are terminated by a comma. + opening = _GetOpeningBracket(current) + if opening and opening.previous_token and opening.previous_token.is_name: + if previous.value in '(,': + if opening.matching_bracket.previous_token.value == ',': + return True + if (style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and not current.is_comment and subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in current.subtypes): if (previous.value not in {'=', ':', '*', '**'} and @@ -409,15 +419,6 @@ def SurroundedByParens(token): self._ArgumentListHasDictionaryEntry(current)): return True - if style.Get('SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED'): - # Split before arguments in a function call or definition if the - # arguments are terminated by a comma. - opening = _GetOpeningBracket(current) - if opening and opening.previous_token and opening.previous_token.is_name: - if previous.value in '(,': - if opening.matching_bracket.previous_token.value == ',': - return True - if ((current.is_name or current.value in {'*', '**'}) and previous.value == ','): # If we have a function call within an argument list and it won't fit on diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index ebc2cd3ee..24f34a694 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2274,6 +2274,8 @@ def testSplittingArgumentsTerminatedByComma(self): r =f0 (1, 2,3,) r =f0 (1,) + + r =f0 (a=1,) """) # noqa expected_formatted_code = textwrap.dedent("""\ function_name(argument_name_1=1, argument_name_2=2, argument_name_3=3) @@ -2306,6 +2308,10 @@ def testSplittingArgumentsTerminatedByComma(self): r = f0( 1, ) + + r = f0( + a=1, + ) """) try: From db2d731263319cfb6f610aa9a77aca0e516050cb Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Tue, 10 Oct 2023 18:34:57 -0400 Subject: [PATCH 681/719] Use python 3.12 for CI (#1132) Drop 3.11 for 3.12 --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index ebf2d030e..5e5b11e79 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,7 @@ requires = tox<4 tox-pyenv tox-wheel -envlist = py37,py38,py39,py310,py311 +envlist = py37,py38,py39,py310,py311,py312 # tox-wheel alias for `wheel_pep517 = true` isolated_build = True distshare = ./dist From e2d55ed4c769b82c05dc58e3f3db19abb2bd4198 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Oct 2023 15:35:54 -0700 Subject: [PATCH 682/719] Actions(deps): Bump actions/setup-python from 4.7.0 to 4.7.1 (#1163) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4.7.0 to 4.7.1. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/61a6322f88396a6271a6ee3565807d608ecaddd1...65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/pre-commit-autoupdate.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 58b946441..548f31f7f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.6.0 + uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236 # v4.6.0 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index ffc4bb5f0..ae63bd859 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - name: Set up Python 3.11 - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 + uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236 # v4.7.1 with: python-version: 3.11 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index be90b7acd..72f6e2fde 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 + - uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236 # v4.7.1 with: python-version: 3.11 From 56f7a5483ba56e01feaac2f0a960b9da0365478d Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Fri, 13 Oct 2023 15:21:58 -0400 Subject: [PATCH 683/719] Update README.md - cleanup for #1162 (#1171) Cleanup for #1162 - YAPF running under Python 3.7 against 3.11 code will work now that it's based on ylib2to3 instead of lib2to3. --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index f1d9e368d..c798165a2 100644 --- a/README.md +++ b/README.md @@ -51,10 +51,6 @@ YAPF is supported by multiple editors via community extensions or plugins. See [ YAPF supports Python 3.7+. -> **Note** -> YAPF requires the code it formats to be valid Python for the version YAPF -> itself runs under. - ## Usage From 9afa48e5b92f997928018c0fe7e25a0abf2b7690 Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Fri, 13 Oct 2023 15:57:08 -0400 Subject: [PATCH 684/719] Update README.md - remark unsupported Python features (#1161) Since Python 3.12 is officially released it seems appropriate to remark that YAPF does not support it currently. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c798165a2..5ce50b764 100644 --- a/README.md +++ b/README.md @@ -347,6 +347,8 @@ optional arguments: --binary BINARY location of binary to use for YAPF ``` +## Unsupported Python features +* Python 3.12 – [PEP 701 – Syntactic formalization of f-strings](https://peps.python.org/pep-0701/) – [YAPF #1136](https://github.com/google/yapf/issues/1136) ## Knobs From a7ff83af72eb5bcade934cf234a983f15167eeed Mon Sep 17 00:00:00 2001 From: Alexey Pelykh Date: Tue, 17 Oct 2023 13:04:28 +0200 Subject: [PATCH 685/719] Fix SPLIT_ALL_COMMA_SEPARATED_VALUES and SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES being too agressive for lambdas and unpacking. (#1173) Co-authored-by: Bill Wendling --- CHANGELOG.md | 2 ++ yapf/pytree/subtype_assigner.py | 5 +++ yapf/yapflib/format_decision_state.py | 9 +++++ yapf/yapflib/subtypes.py | 1 + yapftests/reformatter_basic_test.py | 50 +++++++++++++++++++++++++++ 5 files changed, 67 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8127cf62..ca880fb0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ ### Fixed - Fix SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED for one-item named argument lists by taking precedence over SPLIT_BEFORE_NAMED_ASSIGNS. +- Fix SPLIT_ALL_COMMA_SEPARATED_VALUES and SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES + being too agressive for lambdas and unpacking. ## [0.40.2] 2023-09-22 ### Changes diff --git a/yapf/pytree/subtype_assigner.py b/yapf/pytree/subtype_assigner.py index 05d88b0fc..e3b32777a 100644 --- a/yapf/pytree/subtype_assigner.py +++ b/yapf/pytree/subtype_assigner.py @@ -222,6 +222,11 @@ def Visit_power(self, node): # pylint: disable=invalid-name if isinstance(child, pytree.Leaf) and child.value == '**': _AppendTokenSubtype(child, subtypes.BINARY_OPERATOR) + def Visit_lambdef(self, node): # pylint: disable=invalid-name + # trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME + _AppendSubtypeRec(node, subtypes.LAMBDEF) + self.DefaultNodeVisit(node) + def Visit_trailer(self, node): # pylint: disable=invalid-name for child in node.children: self.Visit(child) diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index ce743139a..06f3455d9 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -180,6 +180,10 @@ def MustSplit(self): return False if style.Get('SPLIT_ALL_COMMA_SEPARATED_VALUES') and previous.value == ',': + if (subtypes.COMP_FOR in current.subtypes or + subtypes.LAMBDEF in current.subtypes): + return False + return True if (style.Get('FORCE_MULTILINE_DICT') and @@ -188,6 +192,11 @@ def MustSplit(self): if (style.Get('SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES') and previous.value == ','): + + if (subtypes.COMP_FOR in current.subtypes or + subtypes.LAMBDEF in current.subtypes): + return False + # Avoid breaking in a container that fits in the current line if possible opening = _GetOpeningBracket(current) diff --git a/yapf/yapflib/subtypes.py b/yapf/yapflib/subtypes.py index b4b7efe75..3c234fbfb 100644 --- a/yapf/yapflib/subtypes.py +++ b/yapf/yapflib/subtypes.py @@ -38,3 +38,4 @@ SIMPLE_EXPRESSION = 22 PARAMETER_START = 23 PARAMETER_STOP = 24 +LAMBDEF = 25 diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 24f34a694..d58343e7c 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -91,6 +91,30 @@ def foo(long_arg, """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) + unformatted_code = textwrap.dedent("""\ + values = [ lambda arg1, arg2: arg1 + arg2 ] + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + values = [ + lambda arg1, arg2: arg1 + arg2 + ] + """) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) + unformatted_code = textwrap.dedent("""\ + values = [ + (some_arg1, some_arg2) for some_arg1, some_arg2 in values + ] + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + values = [ + (some_arg1, + some_arg2) + for some_arg1, some_arg2 in values + ] + """) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # There is a test for split_all_top_level_comma_separated_values, with # different expected value unformatted_code = textwrap.dedent("""\ @@ -161,6 +185,32 @@ def foo(long_arg, """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) + # Works the same way as split_all_comma_separated_values + unformatted_code = textwrap.dedent("""\ + values = [ lambda arg1, arg2: arg1 + arg2 ] + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + values = [ + lambda arg1, arg2: arg1 + arg2 + ] + """) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) + # There is a test for split_all_comma_separated_values, with different + # expected value + unformatted_code = textwrap.dedent("""\ + values = [ + (some_arg1, some_arg2) for some_arg1, some_arg2 in values + ] + """) # noqa + expected_formatted_code = textwrap.dedent("""\ + values = [ + (some_arg1, some_arg2) + for some_arg1, some_arg2 in values + ] + """) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) # There is a test for split_all_comma_separated_values, with different # expected value unformatted_code = textwrap.dedent("""\ From 1f0f6ca710b5eac5363914dd17ea815d26ef1d41 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Oct 2023 11:00:01 -0700 Subject: [PATCH 686/719] Actions(deps): Bump actions/checkout from 4.1.0 to 4.1.1 (#1175) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.0 to 4.1.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/8ade135a41bc03ea155e62e844d188df1ea18608...b4ffde65f46336ab88eb53be808477a3936bae11) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/pre-commit-autoupdate.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 548f31f7f..6a951cd41 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: python-version: ["3.7", "3.11", "3.12"] # no particular need for 3.9 or 3.10 os: [macos-latest, ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236 # v4.6.0 with: diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index ae63bd859..e155c3a26 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -19,7 +19,7 @@ jobs: name: Detect outdated pre-commit hooks runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Set up Python 3.11 uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236 # v4.7.1 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 72f6e2fde..212680d4c 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -19,7 +19,7 @@ jobs: name: Run pre-commit runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236 # v4.7.1 with: From 4e6ce49c7dff272f29411a2447988bf08b6be655 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 00:42:17 -0800 Subject: [PATCH 687/719] pre-commit: Autoupdate (#1172) Co-authored-by: pre-commit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 53ddc1692..b62a0574f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,7 +20,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: trailing-whitespace - id: check-docstring-first From 755afdfa183425bf9b044dfed5d42ad68575246c Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 6 Nov 2023 11:38:01 -0800 Subject: [PATCH 688/719] Format '.pyi' type stub files. Closes #1151 --- CHANGELOG.md | 1 + yapf/yapflib/file_resources.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca880fb0e..a70d29677 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ### Changes - Remove dependency on importlib-metadata - Remove dependency on tomli when using >= py311 +- Format '.pyi' type sub files. ### Fixed - Fix SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED for one-item named argument lists by taking precedence over SPLIT_BEFORE_NAMED_ASSIGNS. diff --git a/yapf/yapflib/file_resources.py b/yapf/yapflib/file_resources.py index 66ab707ac..87b6d863b 100644 --- a/yapf/yapflib/file_resources.py +++ b/yapf/yapflib/file_resources.py @@ -252,7 +252,7 @@ def IsIgnored(path, exclude): def IsPythonFile(filename): """Return True if filename is a Python file.""" - if os.path.splitext(filename)[1] == '.py': + if os.path.splitext(filename)[1] in frozenset({'.py', '.pyi'}): return True try: From 63c13eb1614911c2e0c2575f8c6efb596178c709 Mon Sep 17 00:00:00 2001 From: Justin Lebar Date: Wed, 8 Nov 2023 13:37:02 -0800 Subject: [PATCH 689/719] Add new DISABLE_SPLIT_LIST_WITH_COMMENT flag. (#1177) `DISABLE_SPLIT_LIST_WITH_COMMENT` is a new knob that changes the behavior of splitting a list when a comment is present inside the list. Before, we split a list containing a comment just like we split a list containing a trailing comma: Each element goes on its own line (unless `DISABLE_ENDING_COMMA_HEURISTIC` is true). Now, if `DISABLE_SPLIT_LIST_WITH_COMMENT` is true, we do not split every element of the list onto a new line just because there's a comment somewhere in the list. This mirrors the behavior of clang-format, and is useful for e.g. forming "logical groups" of elements in a list. Note: Upgrading will result in a behavioral change if you have `DISABLE_ENDING_COMMA_HEURISTIC` in your config. Before this version, this flag caused us not to split lists with a trailing comma *and* lists that contain comments. Now, if you set only that flag, we *will* split lists that contain comments. Set the new `DISABLE_SPLIT_LIST_WITH_COMMENT` flag to true to preserve the old behavior. --- CHANGELOG.md | 65 ++++++++++++++++++++++++++++- README.md | 35 ++++++++++++++++ yapf/pytree/pytree_unwrapper.py | 21 +++++++--- yapf/yapflib/style.py | 12 ++++++ yapftests/reformatter_basic_test.py | 23 ++++++++++ 5 files changed, 150 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a70d29677..ccc8726c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,70 @@ # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). -## (0.40.3) UNRELEASED +## (0.41.0) UNRELEASED +### Added +- New `DISABLE_SPLIT_LIST_WITH_COMMENT` flag. + `DISABLE_SPLIT_LIST_WITH_COMMENT` is a new knob that changes the + behavior of splitting a list when a comment is present inside the list. + + Before, we split a list containing a comment just like we split a list + containing a trailing comma: Each element goes on its own line (unless + `DISABLE_ENDING_COMMA_HEURISTIC` is true). + + This new flag allows you to control the behavior of a list with a comment + *separately* from the behavior when the list contains a trailing comma. + + This mirrors the behavior of clang-format, and is useful for e.g. forming + "logical groups" of elements in a list. + + Without this flag: + + ``` + [ + a, + b, # + c + ] + ``` + + With this flag: + + ``` + [ + a, b, # + c + ] + ``` + + Before we had one flag that controlled two behaviors. + + - `DISABLE_ENDING_COMMA_HEURISTIC=false` (default): + - Split a list that has a trailing comma. + - Split a list that contains a comment. + - `DISABLE_ENDING_COMMA_HEURISTIC=true`: + - Don't split on trailing comma. + - Don't split on comment. + + Now we have two flags. + + - `DISABLE_ENDING_COMMA_HEURISTIC=false` and `DISABLE_SPLIT_LIST_WITH_COMMENT=false` (default): + - Split a list that has a trailing comma. + - Split a list that contains a comment. + Behavior is unchanged from the default before. + - `DISABLE_ENDING_COMMA_HEURISTIC=true` and `DISABLE_SPLIT_LIST_WITH_COMMENT=false` : + - Don't split on trailing comma. + - Do split on comment. **This is a change in behavior from before.** + - `DISABLE_ENDING_COMMA_HEURISTIC=false` and `DISABLE_SPLIT_LIST_WITH_COMMENT=true` : + - Split on trailing comma. + - Don't split on comment. + - `DISABLE_ENDING_COMMA_HEURISTIC=true` and `DISABLE_SPLIT_LIST_WITH_COMMENT=true` : + - Don't split on trailing comma. + - Don't split on comment. + **You used to get this behavior just by setting one flag, but now you have to set both.** + + Note the behavioral change above; if you set + `DISABLE_ENDING_COMMA_HEURISTIC=true` and want to keep the old behavior, you + now also need to set `DISABLE_SPLIT_LIST_WITH_COMMENT=true`. ### Changes - Remove dependency on importlib-metadata - Remove dependency on tomli when using >= py311 diff --git a/README.md b/README.md index 5ce50b764..0e4282f65 100644 --- a/README.md +++ b/README.md @@ -512,6 +512,41 @@ optional arguments: > Disable the heuristic which places each list element on a separate line if > the list is comma-terminated. +> +> Note: The behavior of this flag changed in v0.40.3. Before, if this flag +> was true, we would split lists that contained a trailing comma or a +> comment. Now, we have a separate flag, `DISABLE_SPLIT_LIST_WITH_COMMENT`, +> that controls splitting when a list contains a comment. To get the old +> behavior, set both flags to true. More information in +> [CHANGELOG.md](CHANGELOG.md#new-disable_split_list_with_comment-flag). + +#### `DISABLE_DISABLE_SPLIT_LIST_WITH_COMMENT` (new in 0.40.3) + +> Don't put every element on a new line within a list that contains +> interstitial comments. +> +> Without this flag (default): +> +> ``` +> [ +> a, +> b, # +> c +> ] +> ``` +> +> With this flag: +> +> ``` +> [ +> a, b, # +> c +> ] +> ``` +> +> This mirrors the behavior of clang-format and is useful for forming +> "logical groups" of elements in a list. It also works in function +> declarations. #### `EACH_DICT_ENTRY_ON_SEPARATE_LINE` diff --git a/yapf/pytree/pytree_unwrapper.py b/yapf/pytree/pytree_unwrapper.py index 4b84cd54c..80e050fbd 100644 --- a/yapf/pytree/pytree_unwrapper.py +++ b/yapf/pytree/pytree_unwrapper.py @@ -407,16 +407,27 @@ def _AdjustSplitPenalty(line): def _DetermineMustSplitAnnotation(node): """Enforce a split in the list if the list ends with a comma.""" - if style.Get('DISABLE_ENDING_COMMA_HEURISTIC'): - return - if not _ContainsComments(node): + + def SplitBecauseTrailingComma(): + if style.Get('DISABLE_ENDING_COMMA_HEURISTIC'): + return False token = next(node.parent.leaves()) if token.value == '(': if sum(1 for ch in node.children if ch.type == grammar_token.COMMA) < 2: - return + return False if (not isinstance(node.children[-1], pytree.Leaf) or node.children[-1].value != ','): - return + return False + return True + + def SplitBecauseListContainsComment(): + return (not style.Get('DISABLE_SPLIT_LIST_WITH_COMMENT') and + _ContainsComments(node)) + + if (not SplitBecauseTrailingComma() and + not SplitBecauseListContainsComment()): + return + num_children = len(node.children) index = 0 _SetMustSplitOnFirstLeaf(node.children[0]) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index b43437ee0..7642c01f4 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -179,6 +179,16 @@ def method(): DISABLE_ENDING_COMMA_HEURISTIC=textwrap.dedent("""\ Disable the heuristic which places each list element on a separate line if the list is comma-terminated. + + Note: The behavior of this flag changed in v0.40.3. Before, if this flag + was true, we would split lists that contained a trailing comma or a + comment. Now, we have a separate flag, `DISABLE_SPLIT_LIT_WITH_COMMENT`, + that controls splitting when a list contains a comment. To get the old + behavior, set both flags to true. More information in CHANGELOG.md. + """), + DISABLE_SPLIT_LIST_WITH_COMMENT=textwrap.dedent(""" + Don't put every element on a new line within a list that contains + interstitial comments. """), EACH_DICT_ENTRY_ON_SEPARATE_LINE=textwrap.dedent("""\ Place each dictionary entry onto its own line. @@ -483,6 +493,7 @@ def CreatePEP8Style(): CONTINUATION_INDENT_WIDTH=4, DEDENT_CLOSING_BRACKETS=False, DISABLE_ENDING_COMMA_HEURISTIC=False, + DISABLE_SPLIT_LIST_WITH_COMMENT=False, EACH_DICT_ENTRY_ON_SEPARATE_LINE=True, FORCE_MULTILINE_DICT=False, I18N_COMMENT='', @@ -671,6 +682,7 @@ def _IntOrIntListConverter(s): CONTINUATION_INDENT_WIDTH=int, DEDENT_CLOSING_BRACKETS=_BoolConverter, DISABLE_ENDING_COMMA_HEURISTIC=_BoolConverter, + DISABLE_SPLIT_LIST_WITH_COMMENT=_BoolConverter, EACH_DICT_ENTRY_ON_SEPARATE_LINE=_BoolConverter, FORCE_MULTILINE_DICT=_BoolConverter, I18N_COMMENT=str, diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index d58343e7c..74b1ba405 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -345,6 +345,29 @@ def f( # Intermediate comment llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) + def testParamListWithTrailingComments(self): + unformatted_code = textwrap.dedent("""\ + def f(a, + b, # + c): + pass + """) + expected_formatted_code = textwrap.dedent("""\ + def f(a, b, # + c): + pass + """) + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{based_on_style: yapf,' + ' disable_split_list_with_comment: True}')) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) + def testBlankLinesBetweenTopLevelImportsAndVariables(self): unformatted_code = textwrap.dedent("""\ import foo as bar From ade5aef74e1ed787d69930d1b47975419c10e1b9 Mon Sep 17 00:00:00 2001 From: Bill Wendling <5993918+bwendling@users.noreply.github.com> Date: Wed, 8 Nov 2023 13:41:39 -0800 Subject: [PATCH 690/719] Update README.md (#1178) Fix typo. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0e4282f65..dcaa494e4 100644 --- a/README.md +++ b/README.md @@ -520,7 +520,7 @@ optional arguments: > behavior, set both flags to true. More information in > [CHANGELOG.md](CHANGELOG.md#new-disable_split_list_with_comment-flag). -#### `DISABLE_DISABLE_SPLIT_LIST_WITH_COMMENT` (new in 0.40.3) +#### `DISABLE_SPLIT_LIST_WITH_COMMENT` > Don't put every element on a new line within a list that contains > interstitial comments. From afd7271e1518de5ac58a23316572871f84f85f69 Mon Sep 17 00:00:00 2001 From: Kyle Gottfried Date: Wed, 8 Nov 2023 16:44:38 -0500 Subject: [PATCH 691/719] Update README.md - remark PEP 695 as unsupported feature (#1179) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index dcaa494e4..f3cfe0e75 100644 --- a/README.md +++ b/README.md @@ -348,6 +348,7 @@ optional arguments: ``` ## Unsupported Python features +* Python 3.12 – [PEP 695 – Type Parameter Syntax](https://peps.python.org/pep-0695/) – [YAPF #1170](https://github.com/google/yapf/issues/1170) * Python 3.12 – [PEP 701 – Syntactic formalization of f-strings](https://peps.python.org/pep-0701/) – [YAPF #1136](https://github.com/google/yapf/issues/1136) ## Knobs From e6d8685581af14f9debd9700730f61388b6adad5 Mon Sep 17 00:00:00 2001 From: Garrett Reynolds Date: Mon, 22 Jan 2024 21:52:49 +0000 Subject: [PATCH 692/719] Clarify Python features will be supported (#1196) This is following a suggestion by @Spitfire1900 here: https://github.com/google/yapf/pull/1179#issuecomment-1838892837 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f3cfe0e75..48d5a62e8 100644 --- a/README.md +++ b/README.md @@ -347,7 +347,7 @@ optional arguments: --binary BINARY location of binary to use for YAPF ``` -## Unsupported Python features +## Python features not yet supported * Python 3.12 – [PEP 695 – Type Parameter Syntax](https://peps.python.org/pep-0695/) – [YAPF #1170](https://github.com/google/yapf/issues/1170) * Python 3.12 – [PEP 701 – Syntactic formalization of f-strings](https://peps.python.org/pep-0701/) – [YAPF #1136](https://github.com/google/yapf/issues/1136) From 0e363260778c21f61f35c6b06e7f99b95382556c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Feb 2024 22:30:20 +0000 Subject: [PATCH 693/719] Actions(deps): Bump peter-evans/create-pull-request from 5.0.2 to 6.0.0 (#1199) Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 5.0.2 to 6.0.0. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/153407881ec5c347639a548ade7d8ad1d6740e38...b1ddad2c994a25fbc81a28b3ec0e368bb2021c50) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit-autoupdate.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index e155c3a26..57cbde1e6 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -42,7 +42,7 @@ jobs: - name: Create pull request from changes (if any) id: create-pull-request - uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38 # v5.0.2 + uses: peter-evans/create-pull-request@b1ddad2c994a25fbc81a28b3ec0e368bb2021c50 # v6.0.0 with: author: 'pre-commit ' base: main From 3af688e6ca94eebc56bd88b281d2b62b4c66bf15 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 20:28:18 +0000 Subject: [PATCH 694/719] Actions(deps): Bump pre-commit/action from 3.0.0 to 3.0.1 (#1202) Bumps [pre-commit/action](https://github.com/pre-commit/action) from 3.0.0 to 3.0.1. - [Release notes](https://github.com/pre-commit/action/releases) - [Commits](https://github.com/pre-commit/action/compare/646c83fcd040023954eafda54b4db0192ce70507...2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd) --- updated-dependencies: - dependency-name: pre-commit/action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 212680d4c..ad75199e9 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -34,4 +34,4 @@ jobs: . echo "PATH=${HOME}/.local/bin:${PATH}" >> "${GITHUB_ENV}" - - uses: pre-commit/action@646c83fcd040023954eafda54b4db0192ce70507 # v3.0.0 + - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 From be6db55af2a3a46937dde8a0a529b96000e4c3bd Mon Sep 17 00:00:00 2001 From: Carissa Bleker Date: Sat, 17 Feb 2024 01:55:54 +0100 Subject: [PATCH 695/719] Add instruction for installing with pip from GitHub directly. (#1186) --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 48d5a62e8..337fa8e71 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,11 @@ $ pip install yapf YAPF is still considered in "beta" stage, and the released version may change often; therefore, the best way to keep up-to-date with the latest development -is to clone this repository. +is to clone this repository or install directly from github: + +```bash +$ pip install git+https://github.com/google/yapf.git +``` Note that if you intend to use YAPF as a command-line tool rather than as a library, installation is not necessary. YAPF supports being run as a directory From 43bf1e42d0a66a2374817a0be9a4947d5cf60772 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 17 Feb 2024 00:56:23 +0000 Subject: [PATCH 696/719] Actions(deps): Bump actions/setup-python from 4.7.1 to 5.0.0 (#1188) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4.7.1 to 5.0.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236...0a5c61591373683505ea898e09a3ea4f39ef2b9c) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/pre-commit-autoupdate.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a951cd41..b8a33079e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236 # v4.6.0 + uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v4.6.0 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index 57cbde1e6..f8b84b10d 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Set up Python 3.11 - uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236 # v4.7.1 + uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0 with: python-version: 3.11 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index ad75199e9..c1fe46ecb 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236 # v4.7.1 + - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0 with: python-version: 3.11 From 22b8f62b81bebb113a7be6b5b304460dc4824eaf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 17 Feb 2024 00:58:05 +0000 Subject: [PATCH 697/719] pre-commit: Autoupdate (#1191) Co-authored-by: pre-commit --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b62a0574f..906b8cf68 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ repos: - repo: https://github.com/pycqa/isort - rev: 5.12.0 + rev: 5.13.2 hooks: - id: isort name: isort (python) @@ -16,7 +16,7 @@ repos: args: [-i] types: [python] - repo: https://github.com/pycqa/flake8 - rev: 6.1.0 + rev: 7.0.0 hooks: - id: flake8 - repo: https://github.com/pre-commit/pre-commit-hooks From 63ac90a9eca3f72e77eb592e0cdb31e83fba4ef8 Mon Sep 17 00:00:00 2001 From: Akash Kumar Singh Date: Wed, 20 Mar 2024 00:10:23 +0530 Subject: [PATCH 698/719] Grammer correction (#1206) Grammer correction --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 337fa8e71..7bb6b2277 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ ## Introduction -YAPF is a Python formatter based off of [`clang-format`](https://clang.llvm.org/docs/ClangFormat.html) +YAPF is a Python formatter based on [`clang-format`](https://clang.llvm.org/docs/ClangFormat.html) (developed by Daniel Jasper). In essence, the algorithm takes the code and calculates the best formatting that conforms to the configured style. It takes away a lot of the drudgery of maintaining your code. From 12de16ed0f27c8d18c2191f763447285eaeaf78e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Mar 2024 18:52:02 +0000 Subject: [PATCH 699/719] Actions(deps): Bump actions/checkout from 4.1.1 to 4.1.2 (#1212) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.1 to 4.1.2. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/b4ffde65f46336ab88eb53be808477a3936bae11...9bb56186c3b09b4f86b1c65136769dd318469633) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/pre-commit-autoupdate.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b8a33079e..b0d8dd9e2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: python-version: ["3.7", "3.11", "3.12"] # no particular need for 3.9 or 3.10 os: [macos-latest, ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v4.6.0 with: diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index f8b84b10d..5bb4b2581 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -19,7 +19,7 @@ jobs: name: Detect outdated pre-commit hooks runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Set up Python 3.11 uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index c1fe46ecb..7af20718b 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -19,7 +19,7 @@ jobs: name: Run pre-commit runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0 with: From f501adf7024abeaa52e25cb27ec286c7ad6c345a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Mar 2024 18:55:19 +0000 Subject: [PATCH 700/719] Actions(deps): Bump peter-evans/create-pull-request from 6.0.0 to 6.0.2 (#1213) Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 6.0.0 to 6.0.2. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/b1ddad2c994a25fbc81a28b3ec0e368bb2021c50...70a41aba780001da0a30141984ae2a0c95d8704e) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit-autoupdate.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index 5bb4b2581..3f4d0b1c7 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -42,7 +42,7 @@ jobs: - name: Create pull request from changes (if any) id: create-pull-request - uses: peter-evans/create-pull-request@b1ddad2c994a25fbc81a28b3ec0e368bb2021c50 # v6.0.0 + uses: peter-evans/create-pull-request@70a41aba780001da0a30141984ae2a0c95d8704e # v6.0.2 with: author: 'pre-commit ' base: main From 9e873dcf612b809942e294089d15bf0c968f9061 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 20:13:38 +0000 Subject: [PATCH 701/719] Actions(deps): Bump actions/setup-python from 5.0.0 to 5.1.0 (#1218) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5.0.0 to 5.1.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/0a5c61591373683505ea898e09a3ea4f39ef2b9c...82c7e631bb3cdc910f68e0081d67478d79c6982d) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/pre-commit-autoupdate.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0d8dd9e2..af2b9b310 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v4.6.0 + uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v4.6.0 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index 3f4d0b1c7..5593e4ff8 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Set up Python 3.11 - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0 + uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 with: python-version: 3.11 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 7af20718b..a96a8093b 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0 + - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 with: python-version: 3.11 From bfab2e8fd1053e8fa0195cca37ee511dc0534570 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Fri, 4 Oct 2024 00:04:41 +0200 Subject: [PATCH 702/719] Fix CI (#1242) * ci.yml: Disable "fail fast" .. to better see if failure depends on architecture and/or Python version only * ci.yml: Stop CI from trying Python 3.7 on arm64 macOS Symptom was this error: > Error: The version '3.7' with architecture 'arm64' was not found for macOS 14.6.1. > The list of all available versions can be found here: https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json Note that Python 3.7 is end-of life since 2023-06-27. --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index af2b9b310..92891dcf1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,8 +11,9 @@ jobs: build: runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: - python-version: ["3.7", "3.11", "3.12"] # no particular need for 3.9 or 3.10 + python-version: ["3.8", "3.11", "3.12"] # no particular need for 3.9 or 3.10 os: [macos-latest, ubuntu-latest, windows-latest] steps: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 From 9b5e9a5b6970029c89a8925e295e25d94273f494 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2024 22:59:50 +0000 Subject: [PATCH 703/719] Actions(deps): Bump actions/checkout from 4.1.2 to 4.2.0 (#1241) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.2 to 4.2.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/9bb56186c3b09b4f86b1c65136769dd318469633...d632683dd7b4114ad314bca15554477dd762a938) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/pre-commit-autoupdate.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 92891dcf1..f4fb6a4dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: python-version: ["3.8", "3.11", "3.12"] # no particular need for 3.9 or 3.10 os: [macos-latest, ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v4.6.0 with: diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index 5593e4ff8..ae23be7cb 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -19,7 +19,7 @@ jobs: name: Detect outdated pre-commit hooks runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set up Python 3.11 uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index a96a8093b..4f11ae798 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -19,7 +19,7 @@ jobs: name: Run pre-commit runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 with: From 9ab5d76c2ee0f1050fda2fd0dedcfd31cc7b77a3 Mon Sep 17 00:00:00 2001 From: Antoni Duda <46002716+avalanche-pwn@users.noreply.github.com> Date: Sat, 5 Oct 2024 02:20:05 +0200 Subject: [PATCH 704/719] pre-commit: Add hook for yapf-diff (#1246) --- .pre-commit-hooks.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index 3eba1f2e7..e834fc4db 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -7,3 +7,15 @@ args: [-i] #inplace language: python types: [python] + +- id: yapf-diff + name: yapf-diff + description: "A formatter for Python files. (formats only changes included in commit)" + always_run: true + language: python + pass_filenames: false + stages: [pre-commit] + entry: | + bash -c "git diff -U0 --no-color --relative HEAD \ + | yapf-diff \ + | tee >(git apply --allow-empty -p0)" From 32966de012a58615e8d49ee71b39319957ec247a Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 7 Oct 2024 22:59:15 +0200 Subject: [PATCH 705/719] ylib2to3/pgen2/grammar: Fix Grammar.dump for parallel use with Grammar.load (#1243) Previously, bad timing could make another process run into reading a half-written pickle cache file, and thus fail like this: > Traceback (most recent call last): > File "[..]/bin/yapf", line 5, in > from yapf import run_main > File "[..]/lib/python3.11/site-packages/yapf/__init__.py", line 41, in > from yapf.yapflib import yapf_api > File "[..]/lib/python3.11/site-packages/yapf/yapflib/yapf_api.py", line 38, in > from yapf.pyparser import pyparser > File "[..]/lib/python3.11/site-packages/yapf/pyparser/pyparser.py", line 44, in > from yapf.yapflib import format_token > File "[..]/lib/python3.11/site-packages/yapf/yapflib/format_token.py", line 23, in > from yapf.pytree import pytree_utils > File "[..]/lib/python3.11/site-packages/yapf/pytree/pytree_utils.py", line 30, in > from yapf_third_party._ylib2to3 import pygram > File "[..]/lib/python3.11/site-packages/yapf_third_party/_ylib2to3/pygram.py", line 29, in > python_grammar = driver.load_grammar(_GRAMMAR_FILE) > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > File "[..]/lib/python3.11/site-packages/yapf_third_party/_ylib2to3/pgen2/driver.py", line 252, in load_grammar > g.load(gp) > File "[..]/lib/python3.11/site-packages/yapf_third_party/_ylib2to3/pgen2/grammar.py", line 95, in load > d = pickle.load(f) > ^^^^^^^^^^^^^^ > EOFError: Ran out of input --- .../_ylib2to3/pgen2/grammar.py | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/third_party/yapf_third_party/_ylib2to3/pgen2/grammar.py b/third_party/yapf_third_party/_ylib2to3/pgen2/grammar.py index 0840c3c71..3825ce7e5 100644 --- a/third_party/yapf_third_party/_ylib2to3/pgen2/grammar.py +++ b/third_party/yapf_third_party/_ylib2to3/pgen2/grammar.py @@ -12,7 +12,9 @@ """ # Python imports +import os import pickle +import tempfile # Local imports from . import token @@ -86,8 +88,39 @@ def __init__(self): def dump(self, filename): """Dump the grammar tables to a pickle file.""" - with open(filename, 'wb') as f: - pickle.dump(self.__dict__, f, pickle.HIGHEST_PROTOCOL) + # NOTE: + # - We're writing a tempfile first so that there is no chance + # for someone to read a half-written file from this very spot + # while we're were not done writing. + # - We're using ``os.rename`` to sure not copy data around (which + # would get us back to square one with a reading-half-written file + # race condition). + # - We're making the tempfile go to the same directory as the eventual + # target ``filename`` so that there is no chance of failing from + # cross-file-system renames in ``os.rename``. + # - We're using the same prefix and suffix for the tempfile so if we + # ever have to leave a tempfile around for failure of deletion, + # it will have a reasonable filename extension and its name will help + # explain is nature. + tempfile_dir = os.path.dirname(filename) + tempfile_prefix, tempfile_suffix = os.path.splitext(filename) + with tempfile.NamedTemporaryFile( + mode='wb', + suffix=tempfile_suffix, + prefix=tempfile_prefix, + dir=tempfile_dir, + delete=False) as f: + pickle.dump(self.__dict__, f.file, pickle.HIGHEST_PROTOCOL) + try: + os.rename(f.name, filename) + except OSError: + # This makes sure that we do not leave the tempfile around + # unless we have to... + try: + os.remove(f.name) + except OSError: + pass + raise def load(self, filename): """Load the grammar tables from a pickle file.""" From a7a81b60d254e4c61343bbd998eef37e8a64d435 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 20:59:49 +0000 Subject: [PATCH 706/719] Actions(deps): Bump peter-evans/create-pull-request from 6.0.2 to 7.0.5 (#1239) Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 6.0.2 to 7.0.5. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/70a41aba780001da0a30141984ae2a0c95d8704e...5e914681df9dc83aa4e4905692ca88beb2f9e91f) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit-autoupdate.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index ae23be7cb..c426f64da 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -42,7 +42,7 @@ jobs: - name: Create pull request from changes (if any) id: create-pull-request - uses: peter-evans/create-pull-request@70a41aba780001da0a30141984ae2a0c95d8704e # v6.0.2 + uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7.0.5 with: author: 'pre-commit ' base: main From e3f83eaa5ff191983477edaf894435e0ea0cab86 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 21:19:53 +0000 Subject: [PATCH 707/719] Actions(deps): Bump actions/checkout from 4.2.0 to 4.2.1 (#1249) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.0 to 4.2.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/d632683dd7b4114ad314bca15554477dd762a938...eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/pre-commit-autoupdate.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f4fb6a4dd..754ff1555 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: python-version: ["3.8", "3.11", "3.12"] # no particular need for 3.9 or 3.10 os: [macos-latest, ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v4.6.0 with: diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index c426f64da..91b8e4614 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -19,7 +19,7 @@ jobs: name: Detect outdated pre-commit hooks runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Set up Python 3.11 uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 4f11ae798..c01223a6d 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -19,7 +19,7 @@ jobs: name: Run pre-commit runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 with: From fb3ed087eb098d98931d8621a28d2716c1e15420 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 13 Nov 2024 15:55:03 -0800 Subject: [PATCH 708/719] Bump version to v0.43.0 --- yapf/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yapf/_version.py b/yapf/_version.py index ccd8b38ef..1e79165d5 100644 --- a/yapf/_version.py +++ b/yapf/_version.py @@ -1 +1 @@ -__version__ = '0.42.0' +__version__ = '0.43.0' From aa7e3d1f6255bea5f0408cdcba6efdd1a3159d3f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 16:50:32 +0000 Subject: [PATCH 709/719] pre-commit: Autoupdate (#1220) Co-authored-by: pre-commit --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 906b8cf68..f8c100c27 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,11 +16,11 @@ repos: args: [-i] types: [python] - repo: https://github.com/pycqa/flake8 - rev: 7.0.0 + rev: 7.1.1 hooks: - id: flake8 - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v5.0.0 hooks: - id: trailing-whitespace - id: check-docstring-first From 55be1fbc6ea6e66257b86e6495768b9af05e81b9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 10 Feb 2025 12:44:26 -0800 Subject: [PATCH 710/719] pre-commit: Autoupdate (#1259) Co-authored-by: pre-commit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f8c100c27..75be82045 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ repos: - repo: https://github.com/pycqa/isort - rev: 5.13.2 + rev: 6.0.0 hooks: - id: isort name: isort (python) From c180ca34c0b155d739e51849dbc42b4608b94e52 Mon Sep 17 00:00:00 2001 From: Andrea-Oliveri Date: Tue, 12 Aug 2025 14:28:09 +0200 Subject: [PATCH 711/719] Started addressing PR #1030. Easy format fixes applied. --- CHANGELOG | 3 ++- CONTRIBUTORS | 3 ++- README.rst | 42 ++++----------------------------- yapf/pytree/split_penalty.py | 2 +- yapf/pytree/subtype_assigner.py | 1 - yapf/yapflib/format_token.py | 22 +++++++++++++---- 6 files changed, 26 insertions(+), 47 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9004d6da0..557161ec7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,7 +4,8 @@ ## [0.41.1] 2022-08-30 ### Added -- Add 4 new knobs to align assignment operators and dictionary colons. They are align_assignment, align_argument_assignment, align_dict_colon and new_alignment_after_commentline. +- Add 2 new knobs to align assignment operators. They are align_assignment, +align_assignment_commentline. ## [0.40.0] UNRELEASED ### Added diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 1852a9133..238bbd8f9 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -15,4 +15,5 @@ Sam Clegg Ɓukasz Langa Oleg Butuzov Mauricio Herrera Cuadra -Xiao Wang \ No newline at end of file +Xiao Wang +Andrea Oliveri \ No newline at end of file diff --git a/README.rst b/README.rst index c54801650..9a7da959b 100644 --- a/README.rst +++ b/README.rst @@ -391,7 +391,7 @@ Knobs ===== ``ALIGN_ASSIGNMENT`` - Align assignment or augmented assignment operators. + Align assignment and augmented assignment operators. If there is a blank line or a newline comment or a multiline object (e.g. a dictionary, a list, a function call) in between, it will start new block alignment. Lines in the same block have the same @@ -407,43 +407,9 @@ Knobs b = 3 bc = 4 -``ALIGN_ARGUMENT_ASSIGNMENT`` - Align assignment operators in the argument list if they are all split on newlines. - Arguments without assignment in between will initiate new block alignment calulation; - for example, a comment line. - Multiline objects in between will also initiate a new alignment block. - - .. code-block:: python - - rglist = test( - var_first = 0, - var_second = '', - var_dict = { - "key_1" : '', - "key_2" : 2, - "key_3" : True, - }, - var_third = 1, - var_very_long = None ) - -``ALIGN_DICT_COLON`` - Align the colons in the dictionary if all entries in dictionay are split on newlines - or 'EACH_DICT_ENTRY_ON_SEPERATE_LINE' is set True. - A commentline or multi-line object in between will start new alignment block. - - .. code-block:: python - - fields = - { - "field" : "ediid", - "type" : "text", - # key: value - "required" : True, - } - -``NEW_ALIGNMENT_AFTER_COMMENTLINE`` - Make it optional to start a new alignmetn block for assignment - alignment and colon alignment after a comment line. +``ALIGN_ASSIGNMENT_RESTART_AFTER_COMMENTS`` + Choose whether to start a new block for assignment alignment after a + comment line. ``ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT`` Align closing bracket with visual indentation. diff --git a/yapf/pytree/split_penalty.py b/yapf/pytree/split_penalty.py index f51fe1b73..b53ffbf85 100644 --- a/yapf/pytree/split_penalty.py +++ b/yapf/pytree/split_penalty.py @@ -89,7 +89,7 @@ def Visit_classdef(self, node): # pylint: disable=invalid-name if len(node.children) > 4: # opening '(' _SetUnbreakable(node.children[2]) - # ':' + # ':' _SetUnbreakable(node.children[-2]) self.DefaultNodeVisit(node) diff --git a/yapf/pytree/subtype_assigner.py b/yapf/pytree/subtype_assigner.py index 5cd0aea37..dd3ea3d1e 100644 --- a/yapf/pytree/subtype_assigner.py +++ b/yapf/pytree/subtype_assigner.py @@ -240,7 +240,6 @@ def Visit_argument(self, node): # pylint: disable=invalid-name # argument ::= # test [comp_for] | test '=' test self._ProcessArgLists(node) - #TODO add a subtype to each argument? def Visit_arglist(self, node): # pylint: disable=invalid-name # arglist ::= diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index 549271705..abb36f75b 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -29,6 +29,7 @@ _CLOSING_BRACKETS = frozenset({')', ']', '}'}) + def _TabbedContinuationAlignPadding(spaces, align_style, tab_width): """Build padding string for continuation alignment in tabbed indentation. @@ -328,9 +329,20 @@ def is_assign(self): return subtypes.ASSIGN_OPERATOR in self.subtypes @property + @py3compat.lru_cache() def is_augassign(self): - augassigns = { - '+=', '-=', '*=', '@=', '/=', '%=', '&=', '|=', '^=', '<<=', '>>=', - '**=', '//=' - } - return self.value in augassigns + return self.value in frozenset({ + '+=', + '-=', + '*=', + '@=', + '/=', + '//=', + '%=', + '<<=', + '>>=', + '|=', + '&=', + '^=', + '**=', + }) \ No newline at end of file From d4696fcf750dbfe9ecba4664a47751d143359046 Mon Sep 17 00:00:00 2001 From: Andrea-Oliveri Date: Tue, 12 Aug 2025 14:28:38 +0200 Subject: [PATCH 712/719] Added new tests for alignment edge cases --- yapftests/reformatter_basic_test.py | 50 ++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 798dbab9a..3e9d1597a 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -3193,7 +3193,7 @@ def testAlignAssignCommentLineInbetween(self): style.SetGlobalStyle( style.CreateStyleFromConfig( '{align_assignment: true,' - 'new_alignment_after_commentline = true}')) + 'align_assignment_restart_after_comments: true}')) unformatted_code = textwrap.dedent("""\ val_first = 1 val_second += 2 @@ -3212,6 +3212,30 @@ def testAlignAssignCommentLineInbetween(self): finally: style.SetGlobalStyle(style.CreateYapfStyle()) + def testAlignAssignContinueWithCommentLineInbetween(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{align_assignment: true,' + 'align_assignment_restart_after_comments: false}')) + unformatted_code = textwrap.dedent("""\ + val_first = 1 + val_second += 2 + # comment + val_third = 3 + """) + expected_formatted_code = textwrap.dedent("""\ + val_first = 1 + val_second += 2 + # comment + val_third = 3 + """) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) + def testAlignAssignDefLineInbetween(self): try: style.SetGlobalStyle( @@ -3242,6 +3266,30 @@ def fun(): finally: style.SetGlobalStyle(style.CreateYapfStyle()) + def testAlignAssignMultipleDepths(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{align_assignment: true}')) + unformatted_code = textwrap.dedent("""\ + if True: + val_first = 1 + val_second += 2 + val_third = 3 + val_fourth = 4 + """) + expected_formatted_code = textwrap.dedent("""\ + if True: + val_first = 1 + val_second += 2 + val_third = 3 + val_fourth = 4 + """) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) + def testAlignAssignObjectWithNewLineInbetween(self): try: style.SetGlobalStyle( From 7cf32286fb83f505719e7cfd813561120b14748b Mon Sep 17 00:00:00 2001 From: Andrea-Oliveri Date: Tue, 12 Aug 2025 17:03:51 +0200 Subject: [PATCH 713/719] Refactored _AlignTrailingComments to reuse logic in _AlignAssignment --- yapf/yapflib/reformatter.py | 195 +++++++++++++++++++++--------------- 1 file changed, 115 insertions(+), 80 deletions(-) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 90823aed7..dd2499ec1 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -22,7 +22,6 @@ from __future__ import unicode_literals import collections -from distutils.errors import LinkError import heapq import re @@ -268,9 +267,15 @@ def _CanPlaceOnSingleLine(line): return (last.total_length + indent_amt <= style.Get('COLUMN_LIMIT') and not any(tok.is_comment for tok in line.tokens[:last_index])) - -def _AlignTrailingComments(final_lines): - """Align trailing comments to the same column.""" +def _AlignGeneric(final_lines, + func_is_tok_to_align_current_line, + func_calculate_pre_token_line_lengths, + func_calculate_column_to_align_on, + func_is_tok_to_align_following_lines, + func_get_val_after_align): + """Implements generic alignement logic which needs to be complemented for + needed purpose by passing suitable functions as parameters. + """ final_lines_index = 0 while final_lines_index < len(final_lines): line = final_lines[final_lines_index] @@ -279,123 +284,153 @@ def _AlignTrailingComments(final_lines): processed_content = False for tok in line.tokens: - if (tok.is_comment and isinstance(tok.spaces_required_before, list) and - tok.value.startswith('#')): - # All trailing comments and comments that appear on a line by themselves - # in this block should be indented at the same level. The block is - # terminated by an empty line or EOF. Enumerate through each line in - # the block and calculate the max line length. Once complete, use the - # first col value greater than that value and create the necessary for - # each line accordingly. - all_pc_line_lengths = [] # All pre-comment line lengths + + if func_is_tok_to_align_current_line(tok): + all_pt_line_lengths = [] # All pre-tok line lengths max_line_length = 0 + stop_align_block = False while True: + if stop_align_block: + break + # EOF - if final_lines_index + len(all_pc_line_lengths) == len(final_lines): + if final_lines_index + len(all_pt_line_lengths) == len(final_lines): break - this_line = final_lines[final_lines_index + len(all_pc_line_lengths)] + this_line = final_lines[final_lines_index + len(all_pt_line_lengths)] # Blank line - note that content is preformatted so we don't need to # worry about spaces/tabs; a blank line will always be '\n\n'. assert this_line.tokens - if (all_pc_line_lengths and + if (all_pt_line_lengths and this_line.tokens[0].formatted_whitespace_prefix.startswith('\n\n') - ): + ): break if this_line.disable: - all_pc_line_lengths.append([]) + all_pt_line_lengths.append([]) continue # Calculate the length of each line in this logical line. - line_content = '' - pc_line_lengths = [] + pt_line_lengths, max_line_length, stop_align_block = func_calculate_pre_token_line_lengths(this_line, max_line_length) + + if pt_line_lengths: + max_line_length = max(max_line_length, max(pt_line_lengths)) - for line_tok in this_line.tokens: - whitespace_prefix = line_tok.formatted_whitespace_prefix + all_pt_line_lengths.append(pt_line_lengths) - newline_index = whitespace_prefix.rfind('\n') - if newline_index != -1: - max_line_length = max(max_line_length, len(line_content)) - line_content = '' + # Calculate the aligned column value + max_line_length += 2 + aligned_col = func_calculate_column_to_align_on(tok, max_line_length) + assert isinstance(aligned_col, int) - whitespace_prefix = whitespace_prefix[newline_index + 1:] + # Update the token values based on the aligned values + for all_pt_line_lengths_index, pt_line_lengths in enumerate( + all_pt_line_lengths): + if not pt_line_lengths: + continue - if line_tok.is_comment: - pc_line_lengths.append(len(line_content)) - else: - line_content += '{}{}'.format(whitespace_prefix, line_tok.value) + this_line = final_lines[final_lines_index + all_pt_line_lengths_index] - if pc_line_lengths: - max_line_length = max(max_line_length, max(pc_line_lengths)) + pt_line_length_index = 0 + for line_tok in this_line.tokens: + if func_is_tok_to_align_following_lines(line_tok): + assert pt_line_length_index < len(pt_line_lengths) + assert pt_line_lengths[pt_line_length_index] < aligned_col + line_tok.value = func_get_val_after_align(line_tok, aligned_col, pt_line_lengths[pt_line_length_index]) + pt_line_length_index += 1 - all_pc_line_lengths.append(pc_line_lengths) + assert pt_line_length_index == len(pt_line_lengths) - # Calculate the aligned column value - max_line_length += 2 + final_lines_index += len(all_pt_line_lengths) - aligned_col = None - for potential_col in tok.spaces_required_before: - if potential_col > max_line_length: - aligned_col = potential_col - break + processed_content = True + break - if aligned_col is None: - aligned_col = max_line_length + if not processed_content: + final_lines_index += 1 - # Update the comment token values based on the aligned values - for all_pc_line_lengths_index, pc_line_lengths in enumerate( - all_pc_line_lengths): - if not pc_line_lengths: - continue - this_line = final_lines[final_lines_index + all_pc_line_lengths_index] - pc_line_length_index = 0 - for line_tok in this_line.tokens: - if line_tok.is_comment: - assert pc_line_length_index < len(pc_line_lengths) - assert pc_line_lengths[pc_line_length_index] < aligned_col +def _AlignTrailingComments(final_lines): + """Align trailing comments to the same column.""" - # Note that there may be newlines embedded in the comments, so - # we need to apply a whitespace prefix to each line. - whitespace = ' ' * ( - aligned_col - pc_line_lengths[pc_line_length_index] - 1) - pc_line_length_index += 1 + def _IsTokToAlignCurrentLine(tok): + # All trailing comments and comments that appear on a line by themselves + # in this block should be indented at the same level. The block is + # terminated by an empty line or EOF. Enumerate through each line in + # the block and calculate the max line length. Once complete, use the + # first col value greater than that value and create the necessary for + # each line accordingly. + return tok.is_comment and isinstance(tok.spaces_required_before, list) and tok.value.startswith('#') + + def _IsTokToAlignFollowingLines(tok): + return tok.is_comment + + def _CalculatePreTokenLineLengths(this_line, max_line_length): + line_content = '' + pt_line_lengths = [] + stop_align_block = False + + for line_tok in this_line.tokens: + whitespace_prefix = line_tok.formatted_whitespace_prefix + + newline_index = whitespace_prefix.rfind('\n') + if newline_index != -1: + max_line_length = max(max_line_length, len(line_content)) + line_content = '' + + whitespace_prefix = whitespace_prefix[newline_index + 1:] + + if line_tok.is_comment: + pt_line_lengths.append(len(line_content)) + else: + line_content += '{}{}'.format(whitespace_prefix, line_tok.value) + + return pt_line_lengths, max_line_length, stop_align_block + + def _CalculateColumnToAlignOn(tok, max_line_length): + aligned_col = None + for potential_col in tok.spaces_required_before: + if potential_col > max_line_length: + aligned_col = potential_col + break - line_content = [] + if aligned_col is None: + aligned_col = max_line_length - for comment_line_index, comment_line in enumerate( - line_tok.value.split('\n')): - line_content.append('{}{}'.format(whitespace, - comment_line.strip())) + return aligned_col - if comment_line_index == 0: - whitespace = ' ' * (aligned_col - 1) + def _GetValueAfterAlign(line_tok, aligned_col, pt_line_length): + # Note that there may be newlines embedded in the comments, so we need to + # apply a whitespace prefix to each line. + whitespace = ' ' * (aligned_col - pt_line_length - 1) - line_content = '\n'.join(line_content) + line_content = [] - # Account for initial whitespace already slated for the - # beginning of the line. - existing_whitespace_prefix = \ - line_tok.formatted_whitespace_prefix.lstrip('\n') + for comment_line_index, comment_line in enumerate(line_tok.value.split('\n')): + line_content.append('{}{}'.format(whitespace, comment_line.strip())) - if line_content.startswith(existing_whitespace_prefix): - line_content = line_content[len(existing_whitespace_prefix):] + if comment_line_index == 0: + whitespace = ' ' * (aligned_col - 1) - line_tok.value = line_content + line_content = '\n'.join(line_content) - assert pc_line_length_index == len(pc_line_lengths) + # Account for initial whitespace already slated for beginning of the line. + existing_whitespace_prefix = line_tok.formatted_whitespace_prefix.lstrip('\n') - final_lines_index += len(all_pc_line_lengths) + if line_content.startswith(existing_whitespace_prefix): + line_content = line_content[len(existing_whitespace_prefix):] - processed_content = True - break + return line_content - if not processed_content: - final_lines_index += 1 + return _AlignGeneric(final_lines, + _IsTokToAlignCurrentLine, + _CalculatePreTokenLineLengths, + _CalculateColumnToAlignOn, + _IsTokToAlignFollowingLines, + _GetValueAfterAlign) def _AlignAssignment(final_lines): From 4d903aaa6a5cb25e88a394f239e9f913d5b6df43 Mon Sep 17 00:00:00 2001 From: Andrea-Oliveri Date: Wed, 13 Aug 2025 09:56:58 +0200 Subject: [PATCH 714/719] Updated name of knob in style --- yapf/yapflib/style.py | 61 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py index f2912f1ee..c9d9a619a 100644 --- a/yapf/yapflib/style.py +++ b/yapf/yapflib/style.py @@ -52,15 +52,56 @@ def SetGlobalStyle(style): _STYLE_HELP = dict( - ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=textwrap.dedent("""\ - Align closing bracket with visual indentation."""), ALIGN_ASSIGNMENT=textwrap.dedent("""\ Align assignment or augmented assignment operators. If there is a blank line or newline comment or objects with newline entries in between, - it will start new block alignment."""), - NEW_ALIGNMENT_AFTER_COMMENTLINE=textwrap.dedent("""\ - Start new assignment or colon alignment when there is a newline comment in between.""" - ), + it will start new block alignment. For exemple: + + val_first = 1 + val_second += 2 + object = { + entry1:1, + entry2:2, + entry3:3, + } + val_third = 3 + + will be formatted as: + + val_first = 1 + val_second += 2 + object = { + entry1: 1, + entry2: 2, + entry3: 3, + } + val_third = 3 + """), + ALIGN_ASSIGNMENT_RESTART_AFTER_COMMENTS=textwrap.dedent("""\ + Start new assignment alignment block when there is a newline comment in + between. For example if this is off then: + + val_first = 1 + val_second += 2 + # comment + val_third = 3 + + will be formatted as: + + val_first = 1 + val_second += 2 + # comment + val_third = 3 + + and if it is on it will be formatted as: + + val_first = 1 + val_second += 2 + # comment + val_third = 3 + """), + ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=textwrap.dedent("""\ + Align closing bracket with visual indentation."""), ALLOW_MULTILINE_LAMBDAS=textwrap.dedent("""\ Allow lambdas to be formatted on more than one line."""), ALLOW_MULTILINE_DICTIONARY_KEYS=textwrap.dedent("""\ @@ -425,9 +466,9 @@ def method(): def CreatePEP8Style(): """Create the PEP8 formatting style.""" return dict( - ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=True, ALIGN_ASSIGNMENT=False, - NEW_ALIGNMENT_AFTER_COMMENTLINE=False, + ALIGN_ASSIGNMENT_RESTART_AFTER_COMMENTS=False, + ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=True, ALLOW_MULTILINE_LAMBDAS=False, ALLOW_MULTILINE_DICTIONARY_KEYS=False, ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=True, @@ -615,9 +656,9 @@ def _IntOrIntListConverter(s): # # Note: this dict has to map all the supported style options. _STYLE_OPTION_VALUE_CONVERTER = dict( - ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=_BoolConverter, ALIGN_ASSIGNMENT=_BoolConverter, - NEW_ALIGNMENT_AFTER_COMMENTLINE=_BoolConverter, + ALIGN_ASSIGNMENT_RESTART_AFTER_COMMENTS=_BoolConverter, + ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=_BoolConverter, ALLOW_MULTILINE_LAMBDAS=_BoolConverter, ALLOW_MULTILINE_DICTIONARY_KEYS=_BoolConverter, ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=_BoolConverter, From 0de5b5814d497e511c7a5ec626b9967b7f46e747 Mon Sep 17 00:00:00 2001 From: Andrea-Oliveri Date: Wed, 13 Aug 2025 09:59:11 +0200 Subject: [PATCH 715/719] Removed unused imports --- yapftests/format_token_test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py index e73f1ea8a..6ea24af63 100644 --- a/yapftests/format_token_test.py +++ b/yapftests/format_token_test.py @@ -15,11 +15,10 @@ import unittest -from lib2to3 import pytree, pygram +from lib2to3 import pytree from lib2to3.pgen2 import token from yapf.yapflib import format_token -from yapf.pytree import subtype_assigner class TabbedContinuationAlignPaddingTest(unittest.TestCase): From 51eeab6ba4648ece22c79b764b52f7d7c2aa2b42 Mon Sep 17 00:00:00 2001 From: Andrea-Oliveri Date: Wed, 13 Aug 2025 10:18:51 +0200 Subject: [PATCH 716/719] Refactored _AlignAssignment --- yapf/yapflib/reformatter.py | 255 ++++++++++++++---------------------- 1 file changed, 98 insertions(+), 157 deletions(-) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index dd2499ec1..5d2354749 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -269,6 +269,7 @@ def _CanPlaceOnSingleLine(line): def _AlignGeneric(final_lines, func_is_tok_to_align_current_line, + func_additional_checks_break_align_block, func_calculate_pre_token_line_lengths, func_calculate_column_to_align_on, func_is_tok_to_align_following_lines, @@ -288,12 +289,9 @@ def _AlignGeneric(final_lines, if func_is_tok_to_align_current_line(tok): all_pt_line_lengths = [] # All pre-tok line lengths max_line_length = 0 - stop_align_block = False + stop_next_it = False - while True: - if stop_align_block: - break - + while not stop_next_it: # EOF if final_lines_index + len(all_pt_line_lengths) == len(final_lines): break @@ -312,8 +310,14 @@ def _AlignGeneric(final_lines, all_pt_line_lengths.append([]) continue + # Check for additional specific conditions for breaking out of loop. + stop_now, stop_next_it = func_additional_checks_break_align_block(tok, final_lines, final_lines_index, all_pt_line_lengths) + if stop_now: + break + # Calculate the length of each line in this logical line. - pt_line_lengths, max_line_length, stop_align_block = func_calculate_pre_token_line_lengths(this_line, max_line_length) + pt_line_lengths, max_line_length, tmp = func_calculate_pre_token_line_lengths(this_line, max_line_length) + stop_next_it = stop_next_it or tmp if pt_line_lengths: max_line_length = max(max_line_length, max(pt_line_lengths)) @@ -368,6 +372,9 @@ def _IsTokToAlignCurrentLine(tok): def _IsTokToAlignFollowingLines(tok): return tok.is_comment + def _AdditionalChecksBreakAlignBlock(tok, final_lines, final_lines_index, all_pt_line_lengths): + return False, False + def _CalculatePreTokenLineLengths(this_line, max_line_length): line_content = '' pt_line_lengths = [] @@ -427,6 +434,7 @@ def _GetValueAfterAlign(line_tok, aligned_col, pt_line_length): return _AlignGeneric(final_lines, _IsTokToAlignCurrentLine, + _AdditionalChecksBreakAlignBlock, _CalculatePreTokenLineLengths, _CalculateColumnToAlignOn, _IsTokToAlignFollowingLines, @@ -436,167 +444,100 @@ def _GetValueAfterAlign(line_tok, aligned_col, pt_line_length): def _AlignAssignment(final_lines): """Align assignment operators and augmented assignment operators to the same column""" - final_lines_index = 0 - while final_lines_index < len(final_lines): - line = final_lines[final_lines_index] - - assert line.tokens - process_content = False - - for tok in line.tokens: - if tok.is_assign or tok.is_augassign: - # all pre assignment variable lengths in one block of lines - all_pa_variables_lengths = [] - max_variables_length = 0 - - while True: - # EOF - if final_lines_index + len(all_pa_variables_lengths) == len( - final_lines): - break - - this_line_index = final_lines_index + len(all_pa_variables_lengths) - this_line = final_lines[this_line_index] - - next_line = None - if this_line_index < len(final_lines) - 1: - next_line = final_lines[final_lines_index + - len(all_pa_variables_lengths) + 1] + def _IsTokToAlign(tok): + return tok.is_assign or tok.is_augassign - assert this_line.tokens, next_line.tokens - - # align them differently when there is a blank line in between - if (all_pa_variables_lengths and - this_line.tokens[0].formatted_whitespace_prefix.startswith('\n\n') - ): - break - - # if there is a standalone comment or keyword statement line - # or other lines without assignment in between, break - elif (all_pa_variables_lengths and True not in [ - tok.is_assign or tok.is_augassign for tok in this_line.tokens - ]): - if this_line.tokens[0].is_comment: - if style.Get('NEW_ALIGNMENT_AFTER_COMMENTLINE'): - break - else: - break + def _AdditionalChecksBreakAlignBlock(tok, final_lines, final_lines_index, all_pt_line_lengths): + stop_now = False + stop_next_it = False + + this_line_index = final_lines_index + len(all_pt_line_lengths) + this_line = final_lines[this_line_index] - if this_line.disable: - all_pa_variables_lengths.append([]) - continue + if this_line_index < len(final_lines) - 1: + next_line = final_lines[this_line_index + 1] + assert next_line.tokens + + if this_line.depth != next_line.depth: + stop_next_it = True + + # If there is a standalone comment or keyword statement line or other lines + # without assignment in between, break. + if (all_pt_line_lengths and not any(tok.is_assign or tok.is_augassign for tok in this_line.tokens)): + if this_line.tokens[0].is_comment: + if style.Get('ALIGN_ASSIGNMENT_RESTART_AFTER_COMMENTS'): + stop_now = True + else: + stop_now = True + return stop_now, stop_next_it - variables_content = '' - pa_variables_lengths = [] - contain_object = False - line_tokens = this_line.tokens - # only one assignment expression is on each line - for index in range(len(line_tokens)): - line_tok = line_tokens[index] - - prefix = line_tok.formatted_whitespace_prefix - newline_index = prefix.rfind('\n') - if newline_index != -1: - variables_content = '' - prefix = prefix[newline_index + 1:] - - if line_tok.is_assign or line_tok.is_augassign: - next_toks = [ - line_tokens[i] for i in range(index + 1, len(line_tokens)) - ] - # if there is object(list/tuple/dict) with newline entries, break, - # update the alignment so far and start to calulate new alignment - for tok in next_toks: - if tok.value in ['(', '[', '{'] and tok.next_token: - if (tok.next_token.formatted_whitespace_prefix.startswith( - '\n') or - (tok.next_token.is_comment and tok.next_token.next_token - .formatted_whitespace_prefix.startswith('\n'))): - pa_variables_lengths.append(len(variables_content)) - contain_object = True - break - if not contain_object: - if line_tok.is_assign: - pa_variables_lengths.append(len(variables_content)) - # if augassign, add the extra augmented part to the max length caculation - elif line_tok.is_augassign: - pa_variables_lengths.append( - len(variables_content) + len(line_tok.value) - 1) - # don't add the tokens - # after the assignment operator - break - else: - variables_content += '{}{}'.format(prefix, line_tok.value) - - if pa_variables_lengths: - max_variables_length = max(max_variables_length, - max(pa_variables_lengths)) - - all_pa_variables_lengths.append(pa_variables_lengths) - - # after saving this line's max variable length, - # we check if next line has the same depth as this line, - # if not, we don't want to calculate their max variable length together - # so we break the while loop, update alignment so far, and - # then go to next line that has '=' - if next_line: - if this_line.depth != next_line.depth: + def _CalculatePreTokenLineLengths(this_line, max_line_length): + pt_line_length = [] + variables_content = '' + contain_object = False + line_tokens = this_line.tokens + # Only one assignment expression in on each line + for index in range(len(line_tokens)): + line_tok = line_tokens[index] + + prefix = line_tok.formatted_whitespace_prefix + newline_index = prefix.rfind('\n') + if newline_index != -1: + variables_content = '' + prefix = prefix[newline_index + 1:] + + if line_tok.is_assign or line_tok.is_augassign: + next_toks = [ + line_tokens[i] for i in range(index + 1, len(line_tokens)) + ] + # if there is object(list/tuple/dict) with newline entries, break, + # update the alignment so far and start to calulate new alignment + for tok in next_toks: + if tok.value in ['(', '[', '{'] and tok.next_token: + if (tok.next_token.formatted_whitespace_prefix.startswith('\n') or + (tok.next_token.is_comment and tok.next_token.next_token + .formatted_whitespace_prefix.startswith('\n'))): + pt_line_length.append(len(variables_content)) + contain_object = True break - # if this line contains objects with newline entries, - # start new block alignment - if contain_object: - break - - # if no update of max_length, just go to the next block - if max_variables_length == 0: - continue - - max_variables_length += 2 - - # Update the assignment token values based on the max variable length - for all_pa_variables_lengths_index, pa_variables_lengths in enumerate( - all_pa_variables_lengths): - if not pa_variables_lengths: - continue - this_line = final_lines[final_lines_index + - all_pa_variables_lengths_index] - - # only the first assignment operator on each line - pa_variables_lengths_index = 0 - for line_tok in this_line.tokens: - if line_tok.is_assign or line_tok.is_augassign: - assert pa_variables_lengths[0] < max_variables_length - - if pa_variables_lengths_index < len(pa_variables_lengths): - whitespace = ' ' * ( - max_variables_length - pa_variables_lengths[0] - 1) - - assign_content = '{}{}'.format(whitespace, - line_tok.value.strip()) + if not contain_object: + if line_tok.is_assign: + pt_line_length.append(len(variables_content)) + # if augassign, add the extra augmented part to the max length caculation + elif line_tok.is_augassign: + pt_line_length.append( + len(variables_content) + len(line_tok.value) - 1) + # don't add the tokens after the assignment operator + break + else: + variables_content += '{}{}'.format(prefix, line_tok.value) + return pt_line_length, max_line_length, contain_object - existing_whitespace_prefix = \ - line_tok.formatted_whitespace_prefix.lstrip('\n') + def _CalculateColumnToAlignOn(tok, max_line_length): + return max_line_length - # in case the existing spaces are larger than padded spaces - if (len(whitespace) == 1 or len(whitespace) > 1 and - len(existing_whitespace_prefix) > len(whitespace)): - line_tok.whitespace_prefix = '' - elif assign_content.startswith(existing_whitespace_prefix): - assign_content = assign_content[len(existing_whitespace_prefix - ):] + def _GetValueAfterAlign(line_tok, aligned_col, pt_line_length): + whitespace = ' ' * (aligned_col - pt_line_length - 1) - # update the assignment operator value - line_tok.value = assign_content + assign_content = '{}{}'.format(whitespace, line_tok.value.strip()) - pa_variables_lengths_index += 1 + existing_whitespace_prefix = line_tok.formatted_whitespace_prefix.lstrip('\n') - final_lines_index += len(all_pa_variables_lengths) + # In case the existing spaces are larger than padded spaces + if (len(whitespace) == 1 or len(whitespace) > 1 and + len(existing_whitespace_prefix) > len(whitespace)): + line_tok.whitespace_prefix = '' + elif assign_content.startswith(existing_whitespace_prefix): + assign_content = assign_content[len(existing_whitespace_prefix):] + return assign_content - process_content = True - break - - if not process_content: - final_lines_index += 1 + return _AlignGeneric(final_lines, + _IsTokToAlign, + _AdditionalChecksBreakAlignBlock, + _CalculatePreTokenLineLengths, + _CalculateColumnToAlignOn, + _IsTokToAlign, + _GetValueAfterAlign) def _FormatFinalLines(final_lines, verify): From cd8a0c93c6bf01365e98ee2e0e8cdf1f51800076 Mon Sep 17 00:00:00 2001 From: Andrea-Oliveri Date: Wed, 13 Aug 2025 10:19:13 +0200 Subject: [PATCH 717/719] Added more tests for assignement alignment --- yapftests/reformatter_basic_test.py | 52 +++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 3e9d1597a..247811676 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -3236,6 +3236,58 @@ def testAlignAssignContinueWithCommentLineInbetween(self): finally: style.SetGlobalStyle(style.CreateYapfStyle()) + def testAlignIgnoreAssignInComment(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{align_assignment: true}')) + unformatted_code = textwrap.dedent("""\ + val_first = 1 + val_second += 2 + # comments should not be = aligned + val_third = 3 + """) + expected_formatted_code = textwrap.dedent("""\ + val_first = 1 + val_second += 2 + # comments should not be = aligned + val_third = 3 + """) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) + + def testAlignConfuseKwargs(self): + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig('{align_assignment: true}')) + unformatted_code = textwrap.dedent("""\ + val_first = 1 + val_second += 2 + def fun(a=1): + a = 'example' + abc = '' + val_third = 3 + """) + expected_formatted_code = textwrap.dedent("""\ + val_first = 1 + val_second += 2 + + + def fun(a=1): + a = 'example' + abc = '' + + + val_third = 3 + """) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) + def testAlignAssignDefLineInbetween(self): try: style.SetGlobalStyle( From 82ca12b50bc9fcdc3b0f90e361e9a557c4ca6071 Mon Sep 17 00:00:00 2001 From: Andrea-Oliveri Date: Wed, 13 Aug 2025 10:27:57 +0200 Subject: [PATCH 718/719] Ran yapf on codebase --- yapf/yapflib/format_token.py | 11 ++--- yapf/yapflib/reformatter.py | 71 +++++++++++++++-------------- yapftests/reformatter_basic_test.py | 60 ++++++++++++------------ 3 files changed, 71 insertions(+), 71 deletions(-) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index abb36f75b..9a86bde23 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -29,7 +29,6 @@ _CLOSING_BRACKETS = frozenset({')', ']', '}'}) - def _TabbedContinuationAlignPadding(spaces, align_style, tab_width): """Build padding string for continuation alignment in tabbed indentation. @@ -340,9 +339,9 @@ def is_augassign(self): '//=', '%=', '<<=', - '>>=', - '|=', - '&=', + '>>=', + '|=', + '&=', '^=', - '**=', - }) \ No newline at end of file + '**=', + }) diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py index 5d2354749..99cb81167 100644 --- a/yapf/yapflib/reformatter.py +++ b/yapf/yapflib/reformatter.py @@ -267,8 +267,8 @@ def _CanPlaceOnSingleLine(line): return (last.total_length + indent_amt <= style.Get('COLUMN_LIMIT') and not any(tok.is_comment for tok in line.tokens[:last_index])) -def _AlignGeneric(final_lines, - func_is_tok_to_align_current_line, + +def _AlignGeneric(final_lines, func_is_tok_to_align_current_line, func_additional_checks_break_align_block, func_calculate_pre_token_line_lengths, func_calculate_column_to_align_on, @@ -286,7 +286,7 @@ def _AlignGeneric(final_lines, for tok in line.tokens: - if func_is_tok_to_align_current_line(tok): + if func_is_tok_to_align_current_line(tok): all_pt_line_lengths = [] # All pre-tok line lengths max_line_length = 0 stop_next_it = False @@ -303,7 +303,7 @@ def _AlignGeneric(final_lines, assert this_line.tokens if (all_pt_line_lengths and this_line.tokens[0].formatted_whitespace_prefix.startswith('\n\n') - ): + ): break if this_line.disable: @@ -311,14 +311,16 @@ def _AlignGeneric(final_lines, continue # Check for additional specific conditions for breaking out of loop. - stop_now, stop_next_it = func_additional_checks_break_align_block(tok, final_lines, final_lines_index, all_pt_line_lengths) + stop_now, stop_next_it = func_additional_checks_break_align_block( + tok, final_lines, final_lines_index, all_pt_line_lengths) if stop_now: break # Calculate the length of each line in this logical line. - pt_line_lengths, max_line_length, tmp = func_calculate_pre_token_line_lengths(this_line, max_line_length) + pt_line_lengths, max_line_length, tmp = func_calculate_pre_token_line_lengths( + this_line, max_line_length) stop_next_it = stop_next_it or tmp - + if pt_line_lengths: max_line_length = max(max_line_length, max(pt_line_lengths)) @@ -342,7 +344,8 @@ def _AlignGeneric(final_lines, if func_is_tok_to_align_following_lines(line_tok): assert pt_line_length_index < len(pt_line_lengths) assert pt_line_lengths[pt_line_length_index] < aligned_col - line_tok.value = func_get_val_after_align(line_tok, aligned_col, pt_line_lengths[pt_line_length_index]) + line_tok.value = func_get_val_after_align( + line_tok, aligned_col, pt_line_lengths[pt_line_length_index]) pt_line_length_index += 1 assert pt_line_length_index == len(pt_line_lengths) @@ -356,7 +359,6 @@ def _AlignGeneric(final_lines, final_lines_index += 1 - def _AlignTrailingComments(final_lines): """Align trailing comments to the same column.""" @@ -367,12 +369,14 @@ def _IsTokToAlignCurrentLine(tok): # the block and calculate the max line length. Once complete, use the # first col value greater than that value and create the necessary for # each line accordingly. - return tok.is_comment and isinstance(tok.spaces_required_before, list) and tok.value.startswith('#') + return tok.is_comment and isinstance(tok.spaces_required_before, + list) and tok.value.startswith('#') def _IsTokToAlignFollowingLines(tok): return tok.is_comment - - def _AdditionalChecksBreakAlignBlock(tok, final_lines, final_lines_index, all_pt_line_lengths): + + def _AdditionalChecksBreakAlignBlock(tok, final_lines, final_lines_index, + all_pt_line_lengths): return False, False def _CalculatePreTokenLineLengths(this_line, max_line_length): @@ -416,7 +420,8 @@ def _GetValueAfterAlign(line_tok, aligned_col, pt_line_length): line_content = [] - for comment_line_index, comment_line in enumerate(line_tok.value.split('\n')): + for comment_line_index, comment_line in enumerate( + line_tok.value.split('\n')): line_content.append('{}{}'.format(whitespace, comment_line.strip())) if comment_line_index == 0: @@ -425,20 +430,18 @@ def _GetValueAfterAlign(line_tok, aligned_col, pt_line_length): line_content = '\n'.join(line_content) # Account for initial whitespace already slated for beginning of the line. - existing_whitespace_prefix = line_tok.formatted_whitespace_prefix.lstrip('\n') + existing_whitespace_prefix = line_tok.formatted_whitespace_prefix.lstrip( + '\n') if line_content.startswith(existing_whitespace_prefix): line_content = line_content[len(existing_whitespace_prefix):] return line_content - return _AlignGeneric(final_lines, - _IsTokToAlignCurrentLine, + return _AlignGeneric(final_lines, _IsTokToAlignCurrentLine, _AdditionalChecksBreakAlignBlock, - _CalculatePreTokenLineLengths, - _CalculateColumnToAlignOn, - _IsTokToAlignFollowingLines, - _GetValueAfterAlign) + _CalculatePreTokenLineLengths, _CalculateColumnToAlignOn, + _IsTokToAlignFollowingLines, _GetValueAfterAlign) def _AlignAssignment(final_lines): @@ -447,23 +450,25 @@ def _AlignAssignment(final_lines): def _IsTokToAlign(tok): return tok.is_assign or tok.is_augassign - def _AdditionalChecksBreakAlignBlock(tok, final_lines, final_lines_index, all_pt_line_lengths): + def _AdditionalChecksBreakAlignBlock(tok, final_lines, final_lines_index, + all_pt_line_lengths): stop_now = False stop_next_it = False - + this_line_index = final_lines_index + len(all_pt_line_lengths) this_line = final_lines[this_line_index] if this_line_index < len(final_lines) - 1: next_line = final_lines[this_line_index + 1] assert next_line.tokens - + if this_line.depth != next_line.depth: stop_next_it = True # If there is a standalone comment or keyword statement line or other lines # without assignment in between, break. - if (all_pt_line_lengths and not any(tok.is_assign or tok.is_augassign for tok in this_line.tokens)): + if (all_pt_line_lengths and + not any(tok.is_assign or tok.is_augassign for tok in this_line.tokens)): if this_line.tokens[0].is_comment: if style.Get('ALIGN_ASSIGNMENT_RESTART_AFTER_COMMENTS'): stop_now = True @@ -487,16 +492,14 @@ def _CalculatePreTokenLineLengths(this_line, max_line_length): prefix = prefix[newline_index + 1:] if line_tok.is_assign or line_tok.is_augassign: - next_toks = [ - line_tokens[i] for i in range(index + 1, len(line_tokens)) - ] + next_toks = [line_tokens[i] for i in range(index + 1, len(line_tokens))] # if there is object(list/tuple/dict) with newline entries, break, # update the alignment so far and start to calulate new alignment for tok in next_toks: if tok.value in ['(', '[', '{'] and tok.next_token: if (tok.next_token.formatted_whitespace_prefix.startswith('\n') or (tok.next_token.is_comment and tok.next_token.next_token - .formatted_whitespace_prefix.startswith('\n'))): + .formatted_whitespace_prefix.startswith('\n'))): pt_line_length.append(len(variables_content)) contain_object = True break @@ -521,7 +524,8 @@ def _GetValueAfterAlign(line_tok, aligned_col, pt_line_length): assign_content = '{}{}'.format(whitespace, line_tok.value.strip()) - existing_whitespace_prefix = line_tok.formatted_whitespace_prefix.lstrip('\n') + existing_whitespace_prefix = line_tok.formatted_whitespace_prefix.lstrip( + '\n') # In case the existing spaces are larger than padded spaces if (len(whitespace) == 1 or len(whitespace) > 1 and @@ -531,13 +535,10 @@ def _GetValueAfterAlign(line_tok, aligned_col, pt_line_length): assign_content = assign_content[len(existing_whitespace_prefix):] return assign_content - return _AlignGeneric(final_lines, - _IsTokToAlign, + return _AlignGeneric(final_lines, _IsTokToAlign, _AdditionalChecksBreakAlignBlock, - _CalculatePreTokenLineLengths, - _CalculateColumnToAlignOn, - _IsTokToAlign, - _GetValueAfterAlign) + _CalculatePreTokenLineLengths, _CalculateColumnToAlignOn, + _IsTokToAlign, _GetValueAfterAlign) def _FormatFinalLines(final_lines, verify): diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 247811676..ea3f38fe8 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -3213,56 +3213,56 @@ def testAlignAssignCommentLineInbetween(self): style.SetGlobalStyle(style.CreateYapfStyle()) def testAlignAssignContinueWithCommentLineInbetween(self): - try: - style.SetGlobalStyle( - style.CreateStyleFromConfig( - '{align_assignment: true,' - 'align_assignment_restart_after_comments: false}')) - unformatted_code = textwrap.dedent("""\ + try: + style.SetGlobalStyle( + style.CreateStyleFromConfig( + '{align_assignment: true,' + 'align_assignment_restart_after_comments: false}')) + unformatted_code = textwrap.dedent("""\ val_first = 1 val_second += 2 # comment val_third = 3 """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent("""\ val_first = 1 val_second += 2 # comment val_third = 3 """) - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) - finally: - style.SetGlobalStyle(style.CreateYapfStyle()) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) def testAlignIgnoreAssignInComment(self): - try: - style.SetGlobalStyle( + try: + style.SetGlobalStyle( style.CreateStyleFromConfig('{align_assignment: true}')) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ val_first = 1 val_second += 2 # comments should not be = aligned val_third = 3 """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent("""\ val_first = 1 val_second += 2 # comments should not be = aligned val_third = 3 """) - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) - finally: - style.SetGlobalStyle(style.CreateYapfStyle()) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) def testAlignConfuseKwargs(self): - try: - style.SetGlobalStyle( + try: + style.SetGlobalStyle( style.CreateStyleFromConfig('{align_assignment: true}')) - unformatted_code = textwrap.dedent("""\ + unformatted_code = textwrap.dedent("""\ val_first = 1 val_second += 2 def fun(a=1): @@ -3270,7 +3270,7 @@ def fun(a=1): abc = '' val_third = 3 """) - expected_formatted_code = textwrap.dedent("""\ + expected_formatted_code = textwrap.dedent("""\ val_first = 1 val_second += 2 @@ -3282,11 +3282,11 @@ def fun(a=1): val_third = 3 """) - llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) - self.assertCodeEqual(expected_formatted_code, - reformatter.Reformat(llines)) - finally: - style.SetGlobalStyle(style.CreateYapfStyle()) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_formatted_code, + reformatter.Reformat(llines)) + finally: + style.SetGlobalStyle(style.CreateYapfStyle()) def testAlignAssignDefLineInbetween(self): try: From 53f2f5f77a31f2c343298112a63c71418d9a2626 Mon Sep 17 00:00:00 2001 From: Andrea-Oliveri Date: Wed, 13 Aug 2025 17:10:07 +0200 Subject: [PATCH 719/719] Added lru_cache decorator to FormatToken.is_augassign for consistency with FormatToken.is_arithmetic_op --- yapf/yapflib/format_token.py | 1 + 1 file changed, 1 insertion(+) diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py index d1e53bdc7..5abcb8c3f 100644 --- a/yapf/yapflib/format_token.py +++ b/yapf/yapflib/format_token.py @@ -333,6 +333,7 @@ def is_assign(self): return subtypes.ASSIGN_OPERATOR in self.subtypes @property + @lru_cache() def is_augassign(self): return self.value in frozenset({ '+=',